/* * Copyright 2008 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 static com.google.common.truth.Truth.assertThat; import static com.google.javascript.jscomp.CheckAccessControls.VISIBILITY_MISMATCH; import static com.google.javascript.jscomp.CheckLevel.ERROR; import static com.google.javascript.jscomp.CheckLevel.OFF; import static com.google.javascript.jscomp.CheckLevel.WARNING; import static com.google.javascript.jscomp.NewTypeInference.MISTYPED_ASSIGN_RHS; import static com.google.javascript.jscomp.TypeCheck.DETERMINISTIC_TEST; import com.google.common.collect.ImmutableList; import com.google.javascript.jscomp.ShowByPathWarningsGuard.ShowType; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import java.util.HashMap; import java.util.List; import java.util.Map; import junit.framework.TestCase; /** * Testcase for WarningsGuard and its implementations. * * @author anatol@google.com (Anatol Pomazau) */ public final class WarningsGuardTest extends TestCase { private static final DiagnosticType BAR_WARNING = DiagnosticType.warning("BAR", "Bar description"); private static final WarningsGuard visibilityOff = new DiagnosticGroupWarningsGuard( DiagnosticGroups.ACCESS_CONTROLS, CheckLevel.OFF); private static final WarningsGuard visibilityWarning = new DiagnosticGroupWarningsGuard( DiagnosticGroups.ACCESS_CONTROLS, CheckLevel.WARNING); public void testShowByPathGuard_Restrict() { WarningsGuard includeGuard = new ShowByPathWarningsGuard("/foo/", ShowType.INCLUDE); assertNull(includeGuard.level(makeError("asasasd/foo/hello.js", WARNING))); assertNull(includeGuard.level(makeError("asasasd/foo/hello.js", ERROR))); assertEquals(OFF, includeGuard.level(makeError("asasasd/hello.js", WARNING))); assertEquals(OFF, includeGuard.level(makeError("asasasd/hello.js", OFF))); assertNull(includeGuard.level(makeError("asasasd/hello.js", ERROR))); assertNull(includeGuard.level(makeError(null))); assertNull(includeGuard.level(makeError(null, WARNING))); assertFalse(includeGuard.disables(DiagnosticGroups.DEPRECATED)); } public void testShowByPathGuard_Suppress() { WarningsGuard excludeGuard = new ShowByPathWarningsGuard( new String[] { "/foo/", "/bar/" }, ShowType.EXCLUDE); assertEquals(OFF, excludeGuard.level(makeError("asasasd/foo/hello.js", WARNING))); assertEquals(OFF, excludeGuard.level(makeError("asasasd/foo/bar/hello.js", WARNING))); assertEquals(OFF, excludeGuard.level(makeError("asasasd/bar/hello.js", WARNING))); assertEquals(OFF, excludeGuard.level(makeError("asasasd/foo/bar/hello.js", WARNING))); assertNull(excludeGuard.level(makeError("asasasd/foo/hello.js", ERROR))); assertNull(excludeGuard.level(makeError("asasasd/hello.js", WARNING))); assertNull(excludeGuard.level(makeError("asasasd/hello.js", OFF))); assertNull(excludeGuard.level(makeError("asasasd/hello.js", ERROR))); assertNull(excludeGuard.level(makeError(null))); assertNull(excludeGuard.level(makeError(null, WARNING))); assertFalse(excludeGuard.disables(DiagnosticGroups.DEPRECATED)); } public void testStrictGuard() { WarningsGuard guard = new StrictWarningsGuard(); assertEquals(ERROR, guard.level(makeError("foo/hello.js", WARNING))); assertNull(guard.level(makeError("foo/hello.js", OFF))); assertEquals(ERROR, guard.level(makeError("bar.js", ERROR))); assertFalse(guard.disables(DiagnosticGroups.DEPRECATED)); } public void testByPathGuard() { WarningsGuard strictGuard = ByPathWarningsGuard .forPath(ImmutableList.of("/foo/"), ERROR); assertEquals(ERROR, strictGuard.level(makeError("asasasd/foo/hello.js", WARNING))); assertNull(strictGuard.level(makeError("asasasd/foo/hello.js", ERROR))); assertNull(strictGuard.level(makeError("asasasd/hello.js", WARNING))); assertNull(strictGuard.level(makeError("asasasd/hello.js", OFF))); assertNull(strictGuard.level(makeError("asasasd/hello.js", ERROR))); assertNull(strictGuard.level(makeError(null))); assertNull(strictGuard.level(makeError(null, WARNING))); assertFalse(strictGuard.disables(DiagnosticGroups.DEPRECATED)); } public void testComposeGuard() { WarningsGuard g1 = new WarningsGuard() { private static final long serialVersionUID = 1L; @Override public CheckLevel level(JSError error) { return error.sourceName.equals("123456") ? ERROR : null; } @Override public boolean disables(DiagnosticGroup otherGroup) { return false; } }; WarningsGuard g2 = new WarningsGuard() { private static final long serialVersionUID = 1L; @Override public CheckLevel level(JSError error) { return error.lineNumber == 12 ? WARNING : null; } @Override public boolean disables(DiagnosticGroup otherGroup) { return true; } }; WarningsGuard guard = new ComposeWarningsGuard(g1, g2); assertNull(guard.level(makeError("aaa"))); assertNull(guard.level(makeError("12345"))); assertEquals(ERROR, guard.level(makeError("123456"))); assertEquals(WARNING, guard.level(makeError("12345", 12))); assertNull(guard.level(makeError("12345", 13))); assertTrue(guard.disables(DiagnosticGroups.DEPRECATED)); } public void testComposeGuard2() { WarningsGuard pathGuard = new ShowByPathWarningsGuard("/foo/"); WarningsGuard strictGuard = new StrictWarningsGuard(); WarningsGuard guard = new ComposeWarningsGuard(strictGuard, pathGuard); assertEquals( OFF, guard.level(makeError("asasasd/hello.js", WARNING))); assertEquals( ERROR, guard.level(makeError("asasasd/foo/hello.js", WARNING))); // Try again with the guards reversed. guard = new ComposeWarningsGuard(pathGuard, strictGuard); assertEquals( OFF, guard.level(makeError("asasasd/hello.js", WARNING))); assertEquals( ERROR, guard.level(makeError("asasasd/foo/hello.js", WARNING))); } public void testComposeGuard3() { // Confirm that explicit diagnostic groups override the promotion of // warnings to errors done by StrictWarningGuard. WarningsGuard typeGuard = new DiagnosticGroupWarningsGuard( DiagnosticGroups.DEPRECATED, WARNING); WarningsGuard strictGuard = new StrictWarningsGuard(); WarningsGuard guard = new ComposeWarningsGuard(strictGuard, typeGuard); assertEquals(WARNING, guard.level( JSError.make("example.js", 1, 0, CheckAccessControls.DEPRECATED_NAME))); // Ordering applied doesn't matter, do it again reversed. guard = new ComposeWarningsGuard(typeGuard, strictGuard); assertEquals(WARNING, guard.level( JSError.make("example.js", 1, 0, CheckAccessControls.DEPRECATED_NAME))); } public void testComposeGuardOrdering() { WarningsGuard pathGuard1 = new ShowByPathWarningsGuard("/foo/"); WarningsGuard pathGuard2 = new ShowByPathWarningsGuard("/bar/"); WarningsGuard strictGuard = new StrictWarningsGuard(); WarningsGuard diagnosticGuard1 = new DiagnosticGroupWarningsGuard( DiagnosticGroups.ACCESS_CONTROLS, CheckLevel.OFF); WarningsGuard diagnosticGuard2 = new DiagnosticGroupWarningsGuard( DiagnosticGroups.ACCESS_CONTROLS, CheckLevel.OFF); WarningsGuard diagnosticGuard3 = new DiagnosticGroupWarningsGuard( DiagnosticGroups.ACCESS_CONTROLS, CheckLevel.OFF); ComposeWarningsGuard guard = new ComposeWarningsGuard(pathGuard1, diagnosticGuard1, strictGuard, diagnosticGuard2, pathGuard2, diagnosticGuard3); List<WarningsGuard> guards = guard.getGuards(); assertThat(guards).hasSize(6); for (int i = 1; i < 6; i++) { assertThat(guards.get(i).getPriority()).isAtLeast(guards.get(i - 1).getPriority()); } } public void testComposeGuardOrdering2() { // Ensure that guards added later always override, when two guards // have the same priority. ComposeWarningsGuard guardA = new ComposeWarningsGuard(); guardA.addGuard(visibilityWarning); guardA.addGuard(visibilityOff); guardA.addGuard(visibilityWarning); ComposeWarningsGuard guardB = new ComposeWarningsGuard(); guardB.addGuard(visibilityOff); guardB.addGuard(visibilityWarning); guardB.addGuard(visibilityOff); assertFalse(guardA.disables(DiagnosticGroups.ACCESS_CONTROLS)); assertTrue(guardA.enables(DiagnosticGroups.ACCESS_CONTROLS)); assertTrue(guardB.disables(DiagnosticGroups.ACCESS_CONTROLS)); assertFalse(guardB.enables(DiagnosticGroups.ACCESS_CONTROLS)); } public void testComposeGuardOrdering3() { ComposeWarningsGuard guardA = new ComposeWarningsGuard(); guardA.addGuard( new DiagnosticGroupWarningsGuard( DiagnosticGroups.ACCESS_CONTROLS, CheckLevel.WARNING)); guardA.addGuard( new DiagnosticGroupWarningsGuard( DiagnosticGroups.ACCESS_CONTROLS, CheckLevel.WARNING)); guardA.addGuard( new DiagnosticGroupWarningsGuard( DiagnosticGroups.ACCESS_CONTROLS, CheckLevel.WARNING)); guardA.addGuard( new DiagnosticGroupWarningsGuard( DiagnosticGroups.ACCESS_CONTROLS, CheckLevel.WARNING)); guardA.addGuard(visibilityOff); assertTrue(guardA.disables(DiagnosticGroups.ACCESS_CONTROLS)); } public void testComposeGuardOrdering4() { ComposeWarningsGuard guardA = new ComposeWarningsGuard(); guardA.addGuard(visibilityWarning); guardA.addGuard(visibilityWarning); guardA.addGuard(visibilityWarning); guardA.addGuard(visibilityWarning); guardA.addGuard(visibilityWarning); guardA.addGuard(visibilityWarning); guardA.addGuard(visibilityOff); assertTrue(guardA.disables(DiagnosticGroups.ACCESS_CONTROLS)); } public void testEmergencyComposeGuard1() { ComposeWarningsGuard guard = new ComposeWarningsGuard(); guard.addGuard(new StrictWarningsGuard()); assertEquals(ERROR, guard.level(makeErrorWithLevel(WARNING))); assertEquals(WARNING, guard.makeEmergencyFailSafeGuard().level( makeErrorWithLevel(WARNING))); } public void testEmergencyComposeGuard2() { ComposeWarningsGuard guard = new ComposeWarningsGuard(); guard.addGuard( new DiagnosticGroupWarningsGuard( DiagnosticGroups.ACCESS_CONTROLS, ERROR)); assertEquals(ERROR, guard.level(makeErrorWithType(VISIBILITY_MISMATCH))); assertEquals(WARNING, guard.makeEmergencyFailSafeGuard().level( makeErrorWithType(VISIBILITY_MISMATCH))); } public void testEmergencyComposeGuard3() { ComposeWarningsGuard guard = new ComposeWarningsGuard(); guard.addGuard( new DiagnosticGroupWarningsGuard( DiagnosticGroups.ACCESS_CONTROLS, ERROR)); guard.addGuard( new DiagnosticGroupWarningsGuard( DiagnosticGroups.ACCESS_CONTROLS, OFF)); assertEquals(OFF, guard.level(makeErrorWithType(VISIBILITY_MISMATCH))); assertEquals(OFF, guard.makeEmergencyFailSafeGuard().level( makeErrorWithType(VISIBILITY_MISMATCH))); } public void testDiagnosticGuard1() { WarningsGuard guard = new DiagnosticGroupWarningsGuard( DiagnosticGroups.CHECK_TYPES, ERROR); assertEquals(ERROR, guard.level(makeError("foo", MISTYPED_ASSIGN_RHS))); assertEquals(ERROR, guard.level(makeError("foo", DETERMINISTIC_TEST))); assertFalse(guard.disables(DiagnosticGroups.OLD_CHECK_TYPES)); assertFalse(guard.disables(DiagnosticGroups.NEW_CHECK_TYPES)); assertFalse(guard.disables(DiagnosticGroups.CHECK_TYPES)); assertEnables(guard, DiagnosticGroups.OLD_CHECK_TYPES); assertEnables(guard, DiagnosticGroups.NEW_CHECK_TYPES); assertEnables(guard, DiagnosticGroups.CHECK_TYPES); assertNotEnables(guard, DiagnosticGroups.MESSAGE_DESCRIPTIONS); } public void testDiagnosticGuard2() { WarningsGuard guard = new DiagnosticGroupWarningsGuard( DiagnosticGroups.OLD_CHECK_TYPES, ERROR); assertNull(guard.level(makeError("foo", MISTYPED_ASSIGN_RHS))); assertEquals(ERROR, guard.level(makeError("foo", DETERMINISTIC_TEST))); assertFalse(guard.disables(DiagnosticGroups.OLD_CHECK_TYPES)); assertFalse(guard.disables(DiagnosticGroups.NEW_CHECK_TYPES)); assertFalse(guard.disables(DiagnosticGroups.CHECK_TYPES)); assertEnables(guard, DiagnosticGroups.OLD_CHECK_TYPES); assertNotEnables(guard, DiagnosticGroups.NEW_CHECK_TYPES); assertEnables(guard, DiagnosticGroups.CHECK_TYPES); assertNotEnables(guard, DiagnosticGroups.MESSAGE_DESCRIPTIONS); } public void testDiagnosticGuard3() { WarningsGuard guard = new DiagnosticGroupWarningsGuard( DiagnosticGroups.CHECK_TYPES, OFF); assertTrue(guard.disables(DiagnosticGroups.OLD_CHECK_TYPES)); assertTrue(guard.disables(DiagnosticGroups.NEW_CHECK_TYPES)); assertTrue(guard.disables(DiagnosticGroups.CHECK_TYPES)); assertNotEnables(guard, DiagnosticGroups.OLD_CHECK_TYPES); assertNotEnables(guard, DiagnosticGroups.NEW_CHECK_TYPES); assertNotEnables(guard, DiagnosticGroups.CHECK_TYPES); assertNotEnables(guard, DiagnosticGroups.MESSAGE_DESCRIPTIONS); } public void testDiagnosticGuard4() { WarningsGuard guard = new DiagnosticGroupWarningsGuard( DiagnosticGroups.DEPRECATED, OFF); assertTrue(guard.disables(DiagnosticGroups.DEPRECATED)); assertFalse(guard.disables(DiagnosticGroups.VISIBILITY)); assertFalse(guard.disables(DiagnosticGroups.ACCESS_CONTROLS)); assertNotEnables(guard, DiagnosticGroups.DEPRECATED); assertNotEnables(guard, DiagnosticGroups.VISIBILITY); assertNotEnables(guard, DiagnosticGroups.ACCESS_CONTROLS); assertNotEnables(guard, DiagnosticGroups.MESSAGE_DESCRIPTIONS); } public void testSuppressGuard1() { Map<String, DiagnosticGroup> map = new HashMap<>(); map.put("deprecated", new DiagnosticGroup(BAR_WARNING)); WarningsGuard guard = new SuppressDocWarningsGuard(map); Compiler compiler = new Compiler(); Node code = compiler.parseTestCode( "/** @suppress {deprecated} */ function f() { a; } " + "function g() { b; }"); assertNull( guard.level(JSError.make(code, BAR_WARNING))); assertEquals( OFF, guard.level(JSError.make( findNameNode(code, "a"), BAR_WARNING))); assertNull( guard.level(JSError.make( findNameNode(code, "b"), BAR_WARNING))); } public void testSuppressGuard2() { Map<String, DiagnosticGroup> map = new HashMap<>(); map.put("deprecated", new DiagnosticGroup(BAR_WARNING)); WarningsGuard guard = new SuppressDocWarningsGuard(map); Compiler compiler = new Compiler(); Node code = compiler.parseTestCode( "/** @fileoverview \n * @suppress {deprecated} */ function f() { a; } " + "function g() { b; }"); assertEquals( OFF, guard.level(JSError.make( findNameNode(code, "a"), BAR_WARNING))); assertEquals( OFF, guard.level(JSError.make( findNameNode(code, "b"), BAR_WARNING))); } public void testSuppressGuard3() { Map<String, DiagnosticGroup> map = new HashMap<>(); map.put("deprecated", new DiagnosticGroup(BAR_WARNING)); WarningsGuard guard = new SuppressDocWarningsGuard(map); Compiler compiler = new Compiler(); Node code = compiler.parseTestCode( "/** @suppress {deprecated} */ var f = function() { a; }"); assertEquals( OFF, guard.level(JSError.make( findNameNode(code, "a"), BAR_WARNING))); } public void testSuppressGuard4() { Map<String, DiagnosticGroup> map = new HashMap<>(); map.put("deprecated", new DiagnosticGroup(BAR_WARNING)); WarningsGuard guard = new SuppressDocWarningsGuard(map); Compiler compiler = new Compiler(); Node code = compiler.parseTestCode( "var goog = {}; " + "/** @suppress {deprecated} */ goog.f = function() { a; }"); assertEquals( OFF, guard.level(JSError.make( findNameNode(code, "a"), BAR_WARNING))); } public void testSuppressGuard5() { Map<String, DiagnosticGroup> map = new HashMap<>(); map.put("deprecated", new DiagnosticGroup(BAR_WARNING)); WarningsGuard guard = new SuppressDocWarningsGuard(map); Compiler compiler = new Compiler(); Node code = compiler.parseTestCode( "var goog = {}; " + "goog.f = function() { /** @suppress {deprecated} */ (a); }"); // We only care about @suppress annotations at the function and // script level. assertNull( guard.level(JSError.make( findNameNode(code, "a"), BAR_WARNING))); } public void testComposeGuardCycle() { ComposeWarningsGuard guard = new ComposeWarningsGuard( visibilityOff, visibilityWarning); guard.addGuard(guard); assertEquals( "DiagnosticGroup<visibility>(WARNING), DiagnosticGroup<visibility>(OFF)", guard.toString()); } private static Node findNameNode(Node root, String name) { if (root.isName() && root.getString().equals(name)) { return root; } for (Node n : root.children()) { Node result = findNameNode(n, name); if (result != null) { return result; } } return null; } private static void assertEnables(WarningsGuard guard, DiagnosticGroup type) { assertTrue((new ComposeWarningsGuard(guard)).enables(type)); } private static void assertNotEnables(WarningsGuard guard, DiagnosticGroup type) { assertFalse((new ComposeWarningsGuard(guard)).enables(type)); } private static JSError makeError(String sourcePath) { Node n = new Node(Token.EMPTY); n.setSourceFileForTesting(sourcePath); return JSError.make(n, BAR_WARNING); } private static JSError makeError(String sourcePath, DiagnosticType type) { Node n = new Node(Token.EMPTY); n.setSourceFileForTesting(sourcePath); return JSError.make(n, type); } private static JSError makeErrorWithType(DiagnosticType type) { Node n = new Node(Token.EMPTY); n.setSourceFileForTesting("input"); return JSError.make(n, type); } private static JSError makeError(String sourcePath, CheckLevel level) { Node n = new Node(Token.EMPTY); n.setSourceFileForTesting(sourcePath); return JSError.make(n, DiagnosticType.make("FOO", level, "Foo description")); } private static JSError makeErrorWithLevel(CheckLevel level) { Node n = new Node(Token.EMPTY); n.setSourceFileForTesting("input"); return JSError.make(n, DiagnosticType.make("FOO", level, "Foo description")); } private static JSError makeError(String sourcePath, int lineno) { return JSError.make(sourcePath, lineno, -1, BAR_WARNING); } }