/* * Copyright 2013 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.javascript.jscomp.MinimizedCondition.MinimizationStyle; import com.google.javascript.rhino.Node; import junit.framework.TestCase; import java.util.ArrayList; import java.util.List; /** * Tests for {@link MinimizedCondition} in isolation. * Tests for the containing PeepholeMinimizeConditions pass are in * {@link PeepholeMinimizeConditionsTest}. * * @author blickly@google.com (Ben Lickly) */ public final class MinimizedConditionTest extends TestCase { private static Node parseExpr(String code) { Compiler compiler = new Compiler(); List<SourceFile> input = ImmutableList.of(SourceFile.fromCode("code", code)); List<SourceFile> externs = new ArrayList<>(); compiler.init(externs, input, new CompilerOptions()); Node root = compiler.parseInputs(); assertNotNull("Unexpected parse error(s): " + Joiner.on("\n").join(compiler.getErrors()), root); Node externsRoot = root.getFirstChild(); Node mainRoot = externsRoot.getNext(); Node script = mainRoot.getFirstChild(); Node exprResult = script.getFirstChild(); return exprResult.getFirstChild(); } private static void minCond(String input, String positive, String negative) { Node inputNode = parseExpr(input); MinimizedCondition result = MinimizedCondition.fromConditionNode(inputNode); Node positiveNode = parseExpr(positive); Node negativeNode = parseExpr(negative); // With counting the leading NOT node: Node positiveResult = result.getMinimized(MinimizationStyle.PREFER_UNNEGATED).getNode(); // Without counting the leading NOT node: Node negativeResult = result.getMinimized(MinimizationStyle.ALLOW_LEADING_NOT).getNode(); if (!positiveResult.isEquivalentTo(positiveNode)) { fail("Not equal:" + "\nExpected: " + positive + "\nBut was : " + (new Compiler()).toSource(positiveResult) + "\nExpected tree:\n" + positiveNode.toStringTree() + "\nActual tree:\n" + positiveResult.toStringTree()); } if (!negativeResult.isEquivalentTo(negativeNode)) { fail("Not equal:" + "\nExpected: " + negative + "\nBut was : " + (new Compiler()).toSource(negativeResult) + "\nExpected tree:\n" + negativeNode.toStringTree() + "\nActual tree:\n" + negativeResult.toStringTree()); } } public void testTryMinimizeCondSimple() { minCond("x", "x", "x"); minCond("!x", "!x", "!x"); minCond("!!x", "x", "x"); minCond("!(x && y)", "!x || !y", "!(x && y)"); } public void testMinimizeDemorganSimple() { minCond("!(x&&y)", "!x||!y", "!(x&&y)"); minCond("!(x||y)", "!x&&!y", "!(x||y)"); minCond("!x||!y", "!x||!y", "!(x&&y)"); minCond("!x&&!y", "!x&&!y", "!(x||y)"); minCond("!(x && y && z)", "!(x && y && z)", "!(x && y && z)"); minCond("(!a||!b)&&c", "(!a||!b)&&c", "!(a&&b||!c)"); minCond("(!a||!b)&&(c||d)", "!(a&&b||!c&&!d)", "!(a&&b||!c&&!d)"); } public void testMinimizeBug8494751() { minCond( "x && (y===2 || !f()) && (y===3 || !h())", // TODO(tbreisacher): The 'positive' option could be better: // "x && !((y!==2 && f()) || (y!==3 && h()))", "!(!x || (y!==2 && f()) || (y!==3 && h()))", "!(!x || (y!==2 && f()) || (y!==3 && h()))"); } public void testMinimizeComplementableOperator() { minCond( "0===c && (2===a || 1===a)", "0===c && (2===a || 1===a)", "!(0!==c || 2!==a && 1!==a)"); } public void testMinimizeHook() { minCond("!(x ? y : z)", "(x ? !y : !z)", "!(x ? y : z)"); } public void testMinimizeComma() { minCond("!(inc(), test())", "inc(), !test()", "!(inc(), test())"); minCond("!((x,y)&&z)", "(x,!y)||!z", "!((x,y)&&z)"); } }