blob: 6e8d0b7f6c9533287dd9c4a9d1accd289fe934c5 [file] [log] [blame]
/*
* Copyright 2010 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.core.ext.linker.impl;
import com.google.gwt.core.ext.LinkerContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.linker.Artifact;
import com.google.gwt.core.ext.linker.ArtifactSet;
import com.google.gwt.core.ext.linker.ConfigurationProperty;
import com.google.gwt.core.ext.linker.EmittedArtifact;
import com.google.gwt.core.ext.linker.SelectionProperty;
import com.google.gwt.core.ext.linker.Shardable;
import com.google.gwt.core.ext.linker.StatementRanges;
import com.google.gwt.thirdparty.guava.common.collect.Lists;
import junit.framework.TestCase;
import java.io.UnsupportedEncodingException;
import java.util.Collections;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
/**
* A regular JUnit test case for {@link SelectionScriptLinker}.
*/
public class SelectionScriptLinkerUnitTest extends TestCase {
private static class MockLinkerContext implements LinkerContext {
@Override
public SortedSet<ConfigurationProperty> getConfigurationProperties() {
return new TreeSet<ConfigurationProperty>();
}
@Override
public String getModuleFunctionName() {
return MOCK_MODULE_NAME;
}
@Override
public long getModuleLastModified() {
return MOCK_MODULE_LAST_MODIFIED;
}
@Override
public String getModuleName() {
return MOCK_MODULE_NAME;
}
@Override
public SortedSet<SelectionProperty> getProperties() {
return new TreeSet<SelectionProperty>();
}
@Override
public boolean isOutputCompact() {
return true;
}
@Override
public String optimizeJavaScript(TreeLogger logger, String jsProgram) {
return jsProgram;
}
}
private static class NonShardableSelectionScriptLinker extends
SelectionScriptLinker {
@Override
public String getDescription() {
return getClass().getName();
}
@Override
protected String getCompilationExtension(TreeLogger logger,
LinkerContext context) {
return ".js";
}
@Override
protected String getModulePrefix(TreeLogger logger, LinkerContext context,
String strongName) {
return "MODULE_PREFIX";
}
@Override
protected String getModuleSuffix(TreeLogger logger, LinkerContext context) {
return "MODULE_SUFFIX";
}
@Override
protected String getSelectionScriptTemplate(TreeLogger logger,
LinkerContext context) {
return SelectionScriptLinkerUnitTest.class.getPackage().getName().replace(
'.', '/')
+ "/MockTemplate.js";
}
}
@Shardable
private static class ShardableSelectionScriptLinker extends
NonShardableSelectionScriptLinker {
}
private static final long MOCK_MODULE_LAST_MODIFIED = 1234;
private static final String MOCK_MODULE_NAME = "test";
private static byte[] getBytes(String string) {
try {
return string.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
/**
* Test that running a non-shardable linker in simulated sharding mode does
* not lose the permutations.
*/
public void testNonShardableHasPermutations()
throws UnableToCompleteException {
ArtifactSet artifacts = new ArtifactSet();
StandardCompilationResult result = createCompilationResult();
artifacts.add(result);
ArtifactSet updated = new NonShardableSelectionScriptLinker().link(
TreeLogger.NULL, new MockLinkerContext(), artifacts);
SortedSet<SelectionInformation> selectionInfos = updated.find(SelectionInformation.class);
assertEquals(1, selectionInfos.size());
}
/**
* Test timestamps on the selection script. For both Development Mode and ProductionMode it should
* match the module's timestamp.
*/
public void testTimestampOnSelectionScript() throws UnableToCompleteException {
// Development Mode
{
ArtifactSet artifacts = new ArtifactSet();
ArtifactSet updated = new ShardableSelectionScriptLinker().link(
TreeLogger.NULL, new MockLinkerContext(), artifacts, false);
EmittedArtifact selectionScript = findSelectionScript(updated);
assertEquals(MOCK_MODULE_LAST_MODIFIED, selectionScript.getLastModified());
}
// Production Mode
{
ArtifactSet artifacts = new ArtifactSet();
artifacts.add(createCompilationResult());
ArtifactSet updated = new ShardableSelectionScriptLinker().link(
TreeLogger.NULL, new MockLinkerContext(), artifacts, true);
updated = transferThinning(updated);
updated = new ShardableSelectionScriptLinker().link(TreeLogger.NULL,
new MockLinkerContext(), updated, false);
EmittedArtifact selectionScript = findSelectionScript(updated);
assertEquals(MOCK_MODULE_LAST_MODIFIED, selectionScript.getLastModified());
}
}
private StandardCompilationResult createCompilationResult() {
byte[][] js = new byte[][] {getBytes("code for fragment 0"), getBytes("code for fragment 1")};
String jsStrongName = "fooStrongName";
StatementRanges[] statementRanges = new StatementRanges[] {
new StandardStatementRanges(Lists.newArrayList(0), Lists.newArrayList(10)),
new StandardStatementRanges(Lists.newArrayList(0), Lists.newArrayList(20))};
byte[] symbolMapBytes = getBytes("symbol map");
StandardCompilationResult result = new StandardCompilationResult(
new MockPermutationResult(js, jsStrongName, statementRanges, symbolMapBytes));
result.addSelectionPermutation(new TreeMap<SelectionProperty, String>());
result.addSoftPermutation(Collections.<SelectionProperty, String>emptyMap());
return result;
}
private EmittedArtifact findEmittedArtifact(ArtifactSet updated,
String partialPath) {
for (EmittedArtifact art : updated.find(EmittedArtifact.class)) {
if (art.getPartialPath().equals(partialPath)) {
return art;
}
}
return null;
}
private EmittedArtifact findSelectionScript(ArtifactSet updated) {
return findEmittedArtifact(updated, MOCK_MODULE_NAME + ".nocache.js");
}
/**
* Thin down the artifact set as if it were being transmitted back. The method
* in Link cannot be used because it wants a StandardLinkerContext, not an
* arbitrary LinkerContext.
*/
@SuppressWarnings("unchecked")
private ArtifactSet transferThinning(ArtifactSet artifacts) {
ArtifactSet updated = new ArtifactSet();
// The raw type Artifact is to work around a Java compiler bug:
// http://bugs.sun.com/view_bug.do?bug_id=6548436
for (Artifact art : artifacts) {
if (art.isTransferableFromShards() || (art instanceof EmittedArtifact)) {
updated.add(art);
}
}
return updated;
}
}