/* * Copyright 2014 Google Inc. * * 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.gwt.resources.gss; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import com.google.gwt.thirdparty.common.css.compiler.ast.CssClassSelectorNode; import com.google.gwt.thirdparty.common.css.compiler.ast.CssCompositeValueNode; import com.google.gwt.thirdparty.common.css.compiler.ast.CssLiteralNode; import com.google.gwt.thirdparty.common.css.compiler.ast.CssStringNode; import com.google.gwt.thirdparty.common.css.compiler.ast.CssUnknownAtRuleNode; import com.google.gwt.thirdparty.common.css.compiler.ast.CssValueNode; import com.google.gwt.thirdparty.common.css.compiler.ast.ErrorManager; import com.google.gwt.thirdparty.common.css.compiler.ast.MutatingVisitController; import com.google.gwt.thirdparty.guava.common.collect.Lists; import com.google.gwt.thirdparty.guava.common.collect.Sets; import junit.framework.TestCase; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Test for {@link com.google.gwt.resources.gss.ExternalClassesCollector}. */ public class ExternalClassesCollectorTest extends TestCase { private CssUnknownAtRuleNode cssUnknownAtRuleNode; private CssLiteralNode atRuleNameNode; private MutatingVisitController mutatingVisitController; private CssCompositeValueNode atRuleParameters; private ErrorManager errorManager; @Override protected void setUp() { cssUnknownAtRuleNode = mock(CssUnknownAtRuleNode.class); atRuleNameNode = mock(CssLiteralNode.class); mutatingVisitController = mock(MutatingVisitController.class); atRuleParameters = mock(CssCompositeValueNode.class); errorManager = mock(ErrorManager.class); when(cssUnknownAtRuleNode.getName()).thenReturn(atRuleNameNode); when(cssUnknownAtRuleNode.getParameters()).thenReturn( Lists.<CssValueNode>newArrayList(atRuleParameters)); } public void testLeaveUnknownAtRule_notAnExternalAtRule_doNothing() { // Given ExternalClassesCollector externalClassesCollector = createAndInitExternalClassesCollector(); when(atRuleNameNode.getValue()).thenReturn("dummy"); // When externalClassesCollector.leaveUnknownAtRule(cssUnknownAtRuleNode); // Then verify(cssUnknownAtRuleNode, never()).getParameters(); verify(mutatingVisitController, never()).removeCurrentNode(); } public void testLeaveUnknownAtRule_simpleExternalAtRule_classesReturnByGetExternalClass() { // Given HashSet<String> styleClassSet = Sets.newHashSet(); HashSet<String> orphanClassName = Sets.newHashSet(); ExternalClassesCollector externalClassesCollector = createAndInitExternalClassesCollector(); when(atRuleNameNode.getValue()).thenReturn("external"); List<CssValueNode> parameters = Lists.newArrayList(literalNode("externalClass"), literalNode("externalClass2")); when(atRuleParameters.getValues()).thenReturn(parameters); // When externalClassesCollector.leaveUnknownAtRule(cssUnknownAtRuleNode); // Then verify(cssUnknownAtRuleNode).getParameters(); verify(atRuleParameters).getValues(); verify(mutatingVisitController).removeCurrentNode(); Set<String> externalClasses = externalClassesCollector.getExternalClassNames(styleClassSet, orphanClassName); assertEquals(2, externalClasses.size()); assertTrue(externalClasses.contains("externalClass")); assertTrue(externalClasses.contains("externalClass2")); } public void testLeaveUnknownAtRule_externalAtRuleWithMatchAllPrefix_allClassesAreExternals() { // Given HashSet<String> styleClassSet = Sets.newHashSet("class1", "class2", "class3"); HashSet<String> orphanClassName = Sets.newHashSet(); ExternalClassesCollector externalClassesCollector = createAndInitExternalClassesCollector(); when(atRuleNameNode.getValue()).thenReturn("external"); List<CssValueNode> parameters = Lists.newArrayList(stringNode("*")); when(atRuleParameters.getValues()).thenReturn(parameters); // When externalClassesCollector.leaveUnknownAtRule(cssUnknownAtRuleNode); // Then verify(cssUnknownAtRuleNode).getParameters(); verify(atRuleParameters).getValues(); verify(mutatingVisitController).removeCurrentNode(); Set<String> externalClasses = externalClassesCollector.getExternalClassNames(styleClassSet, orphanClassName); assertEquals(3, externalClasses.size()); assertTrue(externalClasses.contains("class1")); assertTrue(externalClasses.contains("class2")); assertTrue(externalClasses.contains("class3")); } public void testLeaveUnknownAtRule_styleClassWithoutMethodAndRemovedFromAST_consideredAsExternal() { // Given HashSet<String> styleClassSet = Sets.newHashSet("foo", "bar"); ExternalClassesCollector externalClassesCollector = createAndInitExternalClassesCollector(); // AST contains only one style class named foo, bar is not in the AST anymore CssClassSelectorNode classSelectorNode = mock(CssClassSelectorNode.class); when(classSelectorNode.getRefinerName()).thenReturn("foo"); externalClassesCollector.enterClassSelector(classSelectorNode); // The style class bar is not associated to a java method HashSet<String> orphanClassName = Sets.newHashSet("bar"); // When Set<String> externalClasses = externalClassesCollector.getExternalClassNames(styleClassSet, orphanClassName); // Then assertEquals(1, externalClasses.size()); assertTrue(externalClasses.contains("bar")); } public void testLeaveUnknownAtRule_externalAtRuleWithMatchAllPrefixThenAnotherExternalAtRule_anotherAtRuleNotProcessed() { // Given ExternalClassesCollector externalClassesCollector = createAndInitExternalClassesCollector(); when(atRuleNameNode.getValue()).thenReturn("external"); List<CssValueNode> parameters = Lists.newArrayList(stringNode("*")); when(atRuleParameters.getValues()).thenReturn(parameters); externalClassesCollector.leaveUnknownAtRule(cssUnknownAtRuleNode); reset(mutatingVisitController); CssUnknownAtRuleNode secondAtRuleNode = mock(CssUnknownAtRuleNode.class); CssLiteralNode secondAtRuleNameNode = mock(CssLiteralNode.class); when(secondAtRuleNameNode.getValue()).thenReturn("external"); when(secondAtRuleNode.getName()).thenReturn(secondAtRuleNameNode); // When externalClassesCollector.leaveUnknownAtRule(secondAtRuleNode); // Then verify(secondAtRuleNode, never()).getParameters(); verify(mutatingVisitController).removeCurrentNode(); } public void testLeaveUnknownAtRule_externalAtRuleWithPrefix_classesMatchingThePrefixAreExternals() { // Given HashSet<String> styleClassSet = Sets.newHashSet("prefix", "prefix-class1", "prefi-notexternal","external"); HashSet<String> orphanClassName = Sets.newHashSet(); ExternalClassesCollector externalClassesCollector = createAndInitExternalClassesCollector(); when(atRuleNameNode.getValue()).thenReturn("external"); List<CssValueNode> parameters = Lists.newArrayList(literalNode("external"), stringNode("prefix*")); when(atRuleParameters.getValues()).thenReturn(parameters); // When externalClassesCollector.leaveUnknownAtRule(cssUnknownAtRuleNode); // Then verify(cssUnknownAtRuleNode).getParameters(); verify(atRuleParameters).getValues(); verify(mutatingVisitController).removeCurrentNode(); Set<String> externalClasses = externalClassesCollector.getExternalClassNames(styleClassSet, orphanClassName); assertEquals(3, externalClasses.size()); assertTrue(externalClasses.contains("prefix")); assertTrue(externalClasses.contains("prefix-class1")); assertTrue(externalClasses.contains("external")); } private CssValueNode literalNode(String externalClass) { CssValueNode node = mock(CssLiteralNode.class); when(node.getValue()).thenReturn(externalClass); return node; } private CssValueNode stringNode(String selector) { CssStringNode node = mock(CssStringNode.class); when(node.getConcreteValue()).thenReturn(selector); return node; } private ExternalClassesCollector createAndInitExternalClassesCollector() { ExternalClassesCollector externalClassesCollector = new ExternalClassesCollector(mutatingVisitController, errorManager); // initialise the object but do nothing externalClassesCollector.runPass(); return externalClassesCollector; } }