gt:     foldSame("null == ([f()])");
context: /*
   * Copyright 2004 The Closure Compiler Authors.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.google.javascript.jscomp;
  
  import com.google.common.base.Joiner;
  import com.google.common.collect.ImmutableList;
  import com.google.common.collect.ImmutableMap;
  import com.google.common.collect.ImmutableSet;
  import com.google.javascript.rhino.Node;
  
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  /**
   * Tests for {@link PeepholeFoldConstants} in isolation. Tests for
   * the interaction of multiple peephole passes are in
   * {@link PeepholeIntegrationTest}.
   */
  public class PeepholeFoldConstantsTest extends CompilerTestCase {
  
    private boolean late;
  
    // TODO(user): Remove this when we no longer need to do string comparison.
    private PeepholeFoldConstantsTest(boolean compareAsTree) {
      super("", compareAsTree);
    }
  
    public PeepholeFoldConstantsTest() {
      super("");
    }
  
    @Override
    public void setUp() {
      late = false;
      enableLineNumberCheck(true);
    }
  
    @Override
    public CompilerPass getProcessor(final Compiler compiler) {
      CompilerPass peepholePass = new PeepholeOptimizationsPass(compiler,
            new PeepholeFoldConstants(late));
      return peepholePass;
    }
  
    @Override
    protected int getNumRepetitions() {
      // Reduce this to 1 if we get better expression evaluators.
      return 2;
    }
  
    private void foldSame(String js) {
      testSame(js);
    }
  
    private void fold(String js, String expected) {
      test(js, expected);
    }
  
    private void fold(String js, String expected, DiagnosticType warning) {
      test(js, expected, null, warning);
    }
  
    // TODO(user): This is same as fold() except it uses string comparison. Any
    // test that needs tell us where a folding is constructing an invalid AST.
    private void assertResultString(String js, String expected) {
      PeepholeFoldConstantsTest scTest = new PeepholeFoldConstantsTest(false);
  
      scTest.test(js, expected);
    }
  
    public void testUndefinedComparison1() {
      fold("undefined == undefined", "true");
      fold("undefined == null", "true");
      fold("undefined == void 0", "true");
  
      fold("undefined == 0", "false");
      fold("undefined == 1", "false");
      fold("undefined == 'hi'", "false");
      fold("undefined == true", "false");
      fold("undefined == false", "false");
  
      fold("undefined === undefined", "true");
      fold("undefined === null", "false");
      fold("undefined === void 0", "true");
  
      foldSame("undefined == this");
      foldSame("undefined == x");
  
      fold("undefined != undefined", "false");
      fold("undefined != null", "false");
      fold("undefined != void 0", "false");
  
      fold("undefined != 0", "true");
      fold("undefined != 1", "true");
      fold("undefined != 'hi'", "true");
      fold("undefined != true", "true");
      fold("undefined != false", "true");
  
      fold("undefined !== undefined", "false");
      fold("undefined !== void 0", "false");
      fold("undefined !== null", "true");
  
      foldSame("undefined != this");
      foldSame("undefined != x");
  
      fold("undefined < undefined", "false");
      fold("undefined > undefined", "false");
      fold("undefined >= undefined", "false");
      fold("undefined <= undefined", "false");
  
      fold("0 < undefined", "false");
      fold("true > undefined", "false");
      fold("'hi' >= undefined", "false");
      fold("null <= undefined", "false");
  
      fold("undefined < 0", "false");
      fold("undefined > true", "false");
      fold("undefined >= 'hi'", "false");
      fold("undefined <= null", "false");
  
      fold("null == undefined", "true");
      fold("0 == undefined", "false");
      fold("1 == undefined", "false");
      fold("'hi' == undefined", "false");
      fold("true == undefined", "false");
      fold("false == undefined", "false");
      fold("null === undefined", "false");
      fold("void 0 === undefined", "true");
  
      fold("undefined == NaN", "false");
      fold("NaN == undefined", "false");
      fold("undefined == Infinity", "false");
      fold("Infinity == undefined", "false");
      fold("undefined == -Infinity", "false");
      fold("-Infinity == undefined", "false");
      fold("({}) == undefined", "false");
      fold("undefined == ({})", "false");
      fold("([]) == undefined", "false");
      fold("undefined == ([])", "false");
      fold("(/a/g) == undefined", "false");
      fold("undefined == (/a/g)", "false");
      fold("(function(){}) == undefined", "false");
      fold("undefined == (function(){})", "false");
  
      fold("undefined != NaN", "true");
      fold("NaN != undefined", "true");
      fold("undefined != Infinity", "true");
      fold("Infinity != undefined", "true");
      fold("undefined != -Infinity", "true");
      fold("-Infinity != undefined", "true");
      fold("({}) != undefined", "true");
      fold("undefined != ({})", "true");
      fold("([]) != undefined", "true");
      fold("undefined != ([])", "true");
      fold("(/a/g) != undefined", "true");
      fold("undefined != (/a/g)", "true");
      fold("(function(){}) != undefined", "true");
      fold("undefined != (function(){})", "true");
  
      foldSame("this == undefined");
      foldSame("x == undefined");
    }
  
    public void testUndefinedComparison2() {
      fold("\"123\" !== void 0", "true");
      fold("\"123\" === void 0", "false");
  
      fold("void 0 !== \"123\"", "true");
      fold("void 0 === \"123\"", "false");
    }
  
    public void testUndefinedComparison3() {
      fold("\"123\" !== undefined", "true");
      fold("\"123\" === undefined", "false");
  
      fold("undefined !== \"123\"", "true");
      fold("undefined === \"123\"", "false");
    }
  
    public void testUndefinedComparison4() {
      fold("1 !== void 0", "true");
      fold("1 === void 0", "false");
  
      fold("null !== void 0", "true");
      fold("null === void 0", "false");
  
      fold("undefined !== void 0", "false");
      fold("undefined === void 0", "true");
    }
  
    public void testNullComparison1() {
      fold("null == undefined", "true");
      fold("null == null", "true");
      fold("null == void 0", "true");
  
      fold("null == 0", "false");
      fold("null == 1", "false");
      fold("null == 'hi'", "false");
      fold("null == true", "false");
      fold("null == false", "false");
  
      fold("null === undefined", "false");
      fold("null === null", "true");
      fold("null === void 0", "false");
  
      foldSame("null == this");
      foldSame("null == x");
  
      fold("null != undefined", "false");
      fold("null != null", "false");
      fold("null != void 0", "false");
  
      fold("null != 0", "true");
      fold("null != 1", "true");
      fold("null != 'hi'", "true");
      fold("null != true", "true");
      fold("null != false", "true");
  
      fold("null !== undefined", "true");
      fold("null !== void 0", "true");
      fold("null !== null", "false");
  
      foldSame("null != this");
      foldSame("null != x");
  
      fold("null < null", "false");
      fold("null > null", "false");
      fold("null >= null", "true");
      fold("null <= null", "true");
  
      foldSame("0 < null"); // foldable
      fold("true > null", "true");
      foldSame("'hi' >= null"); // foldable
      fold("null <= null", "true");
  
      foldSame("null < 0");  // foldable
      fold("null > true", "false");
      foldSame("null >= 'hi'"); // foldable
      fold("null <= null", "true");
  
      fold("null == null", "true");
      fold("0 == null", "false");
      fold("1 == null", "false");
      fold("'hi' == null", "false");
      fold("true == null", "false");
      fold("false == null", "false");
      fold("null === null", "true");
      fold("void 0 === null", "false");
  
      fold("null == NaN", "false");
      fold("NaN == null", "false");
      fold("null == Infinity", "false");
      fold("Infinity == null", "false");
      fold("null == -Infinity", "false");
      fold("-Infinity == null", "false");
      fold("({}) == null", "false");
      fold("null == ({})", "false");
      fold("([]) == null", "false");
      fold("null == ([])", "false");
      fold("(/a/g) == null", "false");
      fold("null == (/a/g)", "false");
      fold("(function(){}) == null", "false");
      fold("null == (function(){})", "false");
  
      fold("null != NaN", "true");
      fold("NaN != null", "true");
      fold("null != Infinity", "true");
      fold("Infinity != null", "true");
      fold("null != -Infinity", "true");
      fold("-Infinity != null", "true");
      fold("({}) != null", "true");
      fold("null != ({})", "true");
      fold("([]) != null", "true");
      fold("null != ([])", "true");
      fold("(/a/g) != null", "true");
      fold("null != (/a/g)", "true");
      fold("(function(){}) != null", "true");
      fold("null != (function(){})", "true");
  
      foldSame("({a:f()}) == null");
      foldSame("null == ({a:f()})");
      foldSame("([f()]) == null");
  