Exporting a map of obfuscated CSS names to full class names into a build
artifact CSV file. This will allow CSS names to be found in the DOM for
frontend testing.
Review by: unnurg@google.com
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10675 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java b/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
index 6baee52..eaf02ed 100644
--- a/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
+++ b/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
@@ -21,6 +21,7 @@
import com.google.gwt.core.ext.PropertyOracle;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.linker.EmittedArtifact.Visibility;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
@@ -74,6 +75,10 @@
import com.google.gwt.user.rebind.SourceWriter;
import com.google.gwt.user.rebind.StringSourceWriter;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.net.URL;
import java.util.ArrayList;
@@ -437,10 +442,13 @@
JClassType cssResourceSubtype = method.getReturnType().isInterface();
assert cssResourceSubtype != null;
CssStylesheet stylesheet = stylesheetMap.get(method);
-
+
// Optimize the stylesheet, recording the class selector obfuscations
Map<JMethod, String> actualReplacements = optimize(logger, context, method);
+ outputCssMapArtifact(logger, context, actualReplacements,
+ cssResourceSubtype.getQualifiedSourceName());
+
outputAdditionalArtifacts(logger, context, method, actualReplacements,
cssResourceSubtype, stylesheet);
@@ -577,12 +585,56 @@
* Output additional artifacts. Does nothing in this baseclass, but is a hook
* for subclasses to do so.
*/
- protected void outputAdditionalArtifacts(TreeLogger logger,
- ResourceContext context, JMethod method,
+ protected void outputAdditionalArtifacts(TreeLogger logger,
+ ResourceContext context, JMethod method,
Map<JMethod, String> actualReplacements, JClassType cssResourceSubtype,
CssStylesheet stylesheet) throws UnableToCompleteException {
}
+ /**
+ * Builds a CSV file mapping obfuscated CSS class names to their qualified source name and
+ * outputs it as a private build artifact.
+ */
+ protected void outputCssMapArtifact(TreeLogger logger, ResourceContext context,
+ Map<JMethod, String> actualReplacements, String outputFileName) {
+ String mappingFileName = "cssResource/" + outputFileName + ".cssmap";
+
+ OutputStream os = null;
+ try {
+ os = context.getGeneratorContext().tryCreateResource(logger, mappingFileName);
+ } catch (UnableToCompleteException e) {
+ logger.log(TreeLogger.ERROR, "Could not create resource: " + mappingFileName);
+ return;
+ }
+
+ if (os == null) {
+ logger.log(TreeLogger.ERROR, "Created resource is null: " + mappingFileName);
+ return;
+ }
+
+ BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os));
+ try {
+ for (Map.Entry<JMethod, String> replacement : actualReplacements.entrySet()) {
+ String qualifiedName = replacement.getKey().getEnclosingType().getQualifiedSourceName();
+ String baseName = replacement.getKey().getName();
+ writer.write(qualifiedName.replaceAll("[.$]", "-") + "-" + baseName);
+ writer.write(",");
+ writer.write(replacement.getValue());
+ writer.newLine();
+ }
+ writer.flush();
+ writer.close();
+ } catch (IOException e) {
+ logger.log(TreeLogger.ERROR, "Error writing artifact: " + mappingFileName);
+ }
+
+ try {
+ context.getGeneratorContext().commitResource(logger, os).setVisibility(Visibility.Private);
+ } catch (UnableToCompleteException e) {
+ logger.log(TreeLogger.ERROR, "Error trying to commit artifact: " + mappingFileName);
+ }
+ }
+
protected void writeGetName(JMethod method, SourceWriter sw) {
sw.println("public String getName() {");
sw.indent();
diff --git a/user/test/com/google/gwt/resources/ResourcesSuite.java b/user/test/com/google/gwt/resources/ResourcesSuite.java
index b101b12..5310191 100644
--- a/user/test/com/google/gwt/resources/ResourcesSuite.java
+++ b/user/test/com/google/gwt/resources/ResourcesSuite.java
@@ -33,6 +33,7 @@
import com.google.gwt.resources.css.UnknownAtRuleTest;
import com.google.gwt.resources.ext.ResourceGeneratorUtilTest;
import com.google.gwt.resources.rg.CssClassNamesTestCase;
+import com.google.gwt.resources.rg.CssOutputTestCase;
import junit.framework.Test;
@@ -46,6 +47,7 @@
suite.addTestSuite(CssClassNamesTestCase.class);
suite.addTestSuite(CssExternalTest.class);
suite.addTestSuite(CssNodeClonerTest.class);
+ suite.addTestSuite(CssOutputTestCase.class);
suite.addTestSuite(CssReorderTest.class);
suite.addTestSuite(CSSResourceTest.class);
suite.addTestSuite(CssRtlTest.class);
diff --git a/user/test/com/google/gwt/resources/rg/CssOutputTestCase.java b/user/test/com/google/gwt/resources/rg/CssOutputTestCase.java
new file mode 100644
index 0000000..aa55f0d
--- /dev/null
+++ b/user/test/com/google/gwt/resources/rg/CssOutputTestCase.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2011 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.rg;
+
+import com.google.gwt.core.ext.GeneratorContext;
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.linker.GeneratedResource;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JMethod;
+import com.google.gwt.dev.util.UnitTestTreeLogger;
+import com.google.gwt.resources.ext.ResourceContext;
+
+import junit.framework.TestCase;
+
+import org.easymock.EasyMock;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Tests output functions.
+ */
+public class CssOutputTestCase extends TestCase {
+
+ public void testOutputCssMapArtifact() throws UnableToCompleteException {
+ UnitTestTreeLogger testLogger = new UnitTestTreeLogger.Builder().createLogger();
+ ResourceContext mockResourceContext = EasyMock.createMock(ResourceContext.class);
+ Map<JMethod, String> testMap = new HashMap<JMethod, String>();
+ OutputStream mockOutputStream = EasyMock.createMock(OutputStream.class);
+ GeneratorContext mockGeneratorContext = EasyMock.createMock(GeneratorContext.class);
+ GeneratedResource mockGeneratedResource = EasyMock.createMock(GeneratedResource.class);
+
+ EasyMock.expect(mockResourceContext.getGeneratorContext()).andReturn(mockGeneratorContext);
+ EasyMock.expectLastCall().times(2);
+ EasyMock.expect(mockGeneratorContext.tryCreateResource(
+ testLogger, "cssResource/test-file-name.cssmap")).andReturn(mockOutputStream);
+ EasyMock.expect(mockGeneratorContext.commitResource(testLogger, mockOutputStream)).andReturn(
+ mockGeneratedResource);
+ EasyMock.replay(mockResourceContext);
+ EasyMock.replay(mockGeneratorContext);
+
+ CssResourceGenerator crg = new CssResourceGenerator();
+ crg.outputCssMapArtifact(testLogger, mockResourceContext, testMap, "test-file-name");
+
+ testLogger.assertCorrectLogEntries();
+ EasyMock.verify(mockResourceContext);
+ EasyMock.verify(mockGeneratorContext);
+ }
+
+ public void testOutputCssMapArtifactThrowOnTryCreateResource() throws UnableToCompleteException {
+ UnitTestTreeLogger.Builder builder = new UnitTestTreeLogger.Builder();
+ builder.expectError("Could not create resource: cssResource/test-file2.cssmap", null);
+ UnitTestTreeLogger testLogger = builder.createLogger();
+ ResourceContext mockResourceContext = EasyMock.createMock(ResourceContext.class);
+ Map<JMethod, String> testMap = new HashMap<JMethod, String>();
+ OutputStream mockOutputStream = EasyMock.createMock(OutputStream.class);
+ GeneratorContext mockGeneratorContext = EasyMock.createMock(GeneratorContext.class);
+ GeneratedResource mockGeneratedResource = EasyMock.createMock(GeneratedResource.class);
+
+ EasyMock.expect(mockResourceContext.getGeneratorContext()).andReturn(mockGeneratorContext);
+ EasyMock.expect(mockGeneratorContext.tryCreateResource(
+ testLogger, "cssResource/test-file2.cssmap")).andThrow(new UnableToCompleteException());
+ EasyMock.replay(mockResourceContext);
+ EasyMock.replay(mockGeneratorContext);
+
+ CssResourceGenerator crg = new CssResourceGenerator();
+ crg.outputCssMapArtifact(testLogger, mockResourceContext, testMap, "test-file2");
+
+ testLogger.assertCorrectLogEntries();
+ EasyMock.verify(mockResourceContext);
+ EasyMock.verify(mockGeneratorContext);
+ }
+
+ public void testOutputCssMapArtifactReturnNullOutputString() throws UnableToCompleteException {
+ UnitTestTreeLogger.Builder builder = new UnitTestTreeLogger.Builder();
+ builder.expectError("Created resource is null: cssResource/test-file3.cssmap", null);
+ UnitTestTreeLogger testLogger = builder.createLogger();
+ ResourceContext mockResourceContext = EasyMock.createMock(ResourceContext.class);
+ Map<JMethod, String> testMap = new HashMap<JMethod, String>();
+ OutputStream mockOutputStream = EasyMock.createMock(OutputStream.class);
+ GeneratorContext mockGeneratorContext = EasyMock.createMock(GeneratorContext.class);
+ GeneratedResource mockGeneratedResource = EasyMock.createMock(GeneratedResource.class);
+
+ EasyMock.expect(mockResourceContext.getGeneratorContext()).andReturn(mockGeneratorContext);
+ EasyMock.expect(mockGeneratorContext.tryCreateResource(
+ testLogger, "cssResource/test-file3.cssmap")).andReturn(null);
+ EasyMock.replay(mockResourceContext);
+ EasyMock.replay(mockGeneratorContext);
+
+ CssResourceGenerator crg = new CssResourceGenerator();
+ crg.outputCssMapArtifact(testLogger, mockResourceContext, testMap, "test-file3");
+
+ testLogger.assertCorrectLogEntries();
+ EasyMock.verify(mockResourceContext);
+ EasyMock.verify(mockGeneratorContext);
+ }
+
+ public void testOutputCssMapArtifactThrowOnCommitResource() throws UnableToCompleteException {
+ UnitTestTreeLogger.Builder builder = new UnitTestTreeLogger.Builder();
+ builder.expectError("Error trying to commit artifact: cssResource/test-file4.cssmap", null);
+ UnitTestTreeLogger testLogger = builder.createLogger();
+ ResourceContext mockResourceContext = EasyMock.createMock(ResourceContext.class);
+ Map<JMethod, String> testMap = new HashMap<JMethod, String>();
+ OutputStream mockOutputStream = EasyMock.createMock(OutputStream.class);
+ GeneratorContext mockGeneratorContext = EasyMock.createMock(GeneratorContext.class);
+ GeneratedResource mockGeneratedResource = EasyMock.createMock(GeneratedResource.class);
+
+ EasyMock.expect(mockResourceContext.getGeneratorContext()).andReturn(mockGeneratorContext);
+ EasyMock.expectLastCall().times(2);
+ EasyMock.expect(mockGeneratorContext.tryCreateResource(
+ testLogger, "cssResource/test-file4.cssmap")).andReturn(mockOutputStream);
+ EasyMock.expect(mockGeneratorContext.commitResource(testLogger, mockOutputStream)).andThrow(
+ new UnableToCompleteException());
+ EasyMock.replay(mockResourceContext);
+ EasyMock.replay(mockGeneratorContext);
+
+ CssResourceGenerator crg = new CssResourceGenerator();
+ crg.outputCssMapArtifact(testLogger, mockResourceContext, testMap, "test-file4");
+
+ testLogger.assertCorrectLogEntries();
+ EasyMock.verify(mockResourceContext);
+ EasyMock.verify(mockGeneratorContext);
+ }
+
+ public void testOutputCssMapArtifactWithTestData() throws UnableToCompleteException {
+ UnitTestTreeLogger testLogger = new UnitTestTreeLogger.Builder().createLogger();
+ ResourceContext mockResourceContext = EasyMock.createMock(ResourceContext.class);
+ JMethod mockJMethod1 = EasyMock.createMock(JMethod.class);
+ JMethod mockJMethod2 = EasyMock.createMock(JMethod.class);
+ JMethod mockJMethod3 = EasyMock.createMock(JMethod.class);
+ JClassType mockJClassType1 = EasyMock.createMock(JClassType.class);
+ JClassType mockJClassType2 = EasyMock.createMock(JClassType.class);
+ JClassType mockJClassType3 = EasyMock.createMock(JClassType.class);
+ Map<JMethod, String> testMap = new LinkedHashMap<JMethod, String>();
+ testMap.put(mockJMethod1, "TESTCSSNAME1");
+ testMap.put(mockJMethod2, "TESTCSSNAME2");
+ testMap.put(mockJMethod3, "TESTCSSNAME3");
+ ByteArrayOutputStream testOutputStream = new ByteArrayOutputStream();
+ GeneratorContext mockGeneratorContext = EasyMock.createMock(GeneratorContext.class);
+ GeneratedResource mockGeneratedResource = EasyMock.createMock(GeneratedResource.class);
+
+ EasyMock.expect(mockResourceContext.getGeneratorContext()).andReturn(mockGeneratorContext);
+ EasyMock.expectLastCall().times(2);
+ EasyMock.expect(mockGeneratorContext.tryCreateResource(
+ testLogger, "cssResource/test-file5.cssmap")).andReturn(testOutputStream);
+ EasyMock.expect(mockJMethod1.getEnclosingType()).andReturn(mockJClassType1);
+ EasyMock.expect(mockJClassType1.getQualifiedSourceName()).andReturn("test.class.type.1");
+ EasyMock.expect(mockJMethod1.getName()).andReturn("basename1");
+ EasyMock.expect(mockJMethod2.getEnclosingType()).andReturn(mockJClassType2);
+ EasyMock.expect(mockJClassType2.getQualifiedSourceName()).andReturn("test.class.type.2");
+ EasyMock.expect(mockJMethod2.getName()).andReturn("basename2");
+ EasyMock.expect(mockJMethod3.getEnclosingType()).andReturn(mockJClassType3);
+ EasyMock.expect(mockJClassType3.getQualifiedSourceName()).andReturn("test.class.type.3");
+ EasyMock.expect(mockJMethod3.getName()).andReturn("basename3");
+ EasyMock.expect(mockGeneratorContext.commitResource(testLogger, testOutputStream)).andReturn(
+ mockGeneratedResource);
+ EasyMock.replay(mockResourceContext);
+ EasyMock.replay(mockGeneratorContext);
+ EasyMock.replay(mockJMethod1);
+ EasyMock.replay(mockJMethod2);
+ EasyMock.replay(mockJMethod3);
+ EasyMock.replay(mockJClassType1);
+ EasyMock.replay(mockJClassType2);
+ EasyMock.replay(mockJClassType3);
+
+ CssResourceGenerator crg = new CssResourceGenerator();
+ crg.outputCssMapArtifact(testLogger, mockResourceContext, testMap, "test-file5");
+ String expectedOutput = "test-class-type-1-basename1,TESTCSSNAME1\n" +
+ "test-class-type-2-basename2,TESTCSSNAME2\n" +
+ "test-class-type-3-basename3,TESTCSSNAME3\n";
+ assertEquals(expectedOutput, testOutputStream.toString());
+
+ testLogger.assertCorrectLogEntries();
+ EasyMock.verify(mockResourceContext);
+ EasyMock.verify(mockGeneratorContext);
+ EasyMock.verify(mockJMethod1);
+ EasyMock.verify(mockJMethod2);
+ EasyMock.verify(mockJMethod3);
+ EasyMock.verify(mockJClassType1);
+ EasyMock.verify(mockJClassType2);
+ EasyMock.verify(mockJClassType3);
+ }
+
+}