blob: 2ecf9e4cce768adb50531234a1a7dfc721dc6f86 [file] [log] [blame]
/*
* Copyright 2009 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.dev;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.dev.UnstableNestedAnonymousGenerator.OutputVersion;
import com.google.gwt.dev.cfg.EntryMethodHolderGenerator;
import com.google.gwt.dev.cfg.ModuleDef;
import com.google.gwt.dev.cfg.ModuleDefLoader;
import com.google.gwt.dev.cfg.ResourceLoader;
import com.google.gwt.dev.cfg.ResourceLoaders;
import com.google.gwt.dev.javac.UnitCacheSingleton;
import com.google.gwt.dev.javac.testing.impl.JavaResourceBase;
import com.google.gwt.dev.javac.testing.impl.MockJavaResource;
import com.google.gwt.dev.javac.testing.impl.MockResource;
import com.google.gwt.dev.jjs.JsOutputOption;
import com.google.gwt.dev.jjs.impl.JjsUtils;
import com.google.gwt.dev.util.UnitTestTreeLogger;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.arg.SourceLevel;
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
import com.google.gwt.thirdparty.guava.common.base.Charsets;
import com.google.gwt.thirdparty.guava.common.collect.ImmutableList;
import com.google.gwt.thirdparty.guava.common.collect.Lists;
import com.google.gwt.thirdparty.guava.common.collect.Sets;
import com.google.gwt.thirdparty.guava.common.io.Files;
import com.google.gwt.util.tools.Utility;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
/**
* Test for {@link Compiler}.
*/
public class CompilerTest extends ArgProcessorTestBase {
public static final String HELLO_MODULE = "com.google.gwt.sample.hello.Hello";
public static final String HELLO_MODULE_STACKMODE_STRIP =
"com.google.gwt.sample.hello.Hello_stackMode_strip";
private MockJavaResource packagePrivateParentResource =
JavaResourceBase.createMockJavaResource("com.foo.PackagePrivateParent",
"package com.foo;",
"public abstract class PackagePrivateParent {",
" abstract void someFunction();",
"}");
private MockJavaResource packagePrivateChildResource =
JavaResourceBase.createMockJavaResource("com.foo.PackagePrivateChild",
"package com.foo;",
"public class PackagePrivateChild extends PackagePrivateParent {",
" @Override",
" void someFunction() {}",
"}");
private MockJavaResource referencesParentResource =
JavaResourceBase.createMockJavaResource("com.foo.ReferencesParent",
"package com.foo;",
"public class ReferencesParent {",
" void run() {",
" PackagePrivateParent packagePrivateParent = null;",
" packagePrivateParent.someFunction();",
" }",
"}");
private MockJavaResource packagePrivateDispatchEntryPointResource =
JavaResourceBase.createMockJavaResource("com.foo.TestEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class TestEntryPoint implements EntryPoint {",
" @Override",
" public void onModuleLoad() {",
" ReferencesParent referencesParent = new ReferencesParent();",
" PackagePrivateChild packagePrivateChild = new PackagePrivateChild();",
" }",
"}");
private MockJavaResource jsoOne =
JavaResourceBase.createMockJavaResource("com.foo.JsoOne",
"package com.foo;",
"import com.google.gwt.core.client.JavaScriptObject;",
"public class JsoOne extends JavaScriptObject {",
" protected JsoOne() {",
" }",
"}");
private MockJavaResource jsoTwo_before =
JavaResourceBase.createMockJavaResource("com.foo.JsoTwo",
"package com.foo;",
"public class JsoTwo {",
" protected JsoTwo() {",
" }",
"}");
private MockJavaResource jsoTwo_after =
JavaResourceBase.createMockJavaResource("com.foo.JsoTwo",
"package com.foo;",
"import com.google.gwt.core.client.JavaScriptObject;",
"public class JsoTwo extends JavaScriptObject {",
" protected JsoTwo() {",
" }",
"}");
private MockJavaResource someClassReferringToJsoOneArrays =
JavaResourceBase.createMockJavaResource("com.foo.SomeClassReferringToJsoOneArrays",
"package com.foo;",
"public class SomeClassReferringToJsoOneArrays {",
" public static Object createJsoOneArray() { return new JsoOne[30]; }",
"}");
private MockJavaResource someClassReferringToJsoTwoArrays =
JavaResourceBase.createMockJavaResource("com.foo.SomeClassReferringToJsoTwoArrays",
"package com.foo;",
"public class SomeClassReferringToJsoTwoArrays {",
" public static Object createJsoTwoArray() { return new JsoTwo[30]; }",
"}");
private MockJavaResource jsoArrayTestEntryPointResource =
JavaResourceBase.createMockJavaResource("com.foo.TestEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class TestEntryPoint implements EntryPoint {",
" @Override",
" public void onModuleLoad() {",
" Object o1 = SomeClassReferringToJsoOneArrays.createJsoOneArray();",
" Object o2 = SomeClassReferringToJsoTwoArrays.createJsoTwoArray();",
" }",
"}");
private MockJavaResource simpleDialogResourceWithExport =
JavaResourceBase.createMockJavaResource("com.foo.SimpleDialog",
"package com.foo;",
"import jsinterop.annotations.JsProperty;",
"public class SimpleDialog {",
" @JsProperty(namespace = \"ns\")",
" public static int show;",
"}");
private MockJavaResource complexDialogResourceWithExport =
JavaResourceBase.createMockJavaResource("com.foo.ComplexDialog",
"package com.foo;",
"import jsinterop.annotations.JsProperty;",
"public class ComplexDialog {",
" @JsProperty(namespace = \"ns\")",
" public static int show;",
"}");
private MockJavaResource complexDialogResourceSansExport =
JavaResourceBase.createMockJavaResource("com.foo.ComplexDialog",
"package com.foo;",
"public class ComplexDialog {",
" public static void show() {}",
"}");
private MockJavaResource simpleModelEntryPointResource =
JavaResourceBase.createMockJavaResource("com.foo.TestEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class TestEntryPoint implements EntryPoint {",
" @Override",
" public void onModuleLoad() {",
" SimpleModel simpleModel1 = new SimpleModel();",
" SimpleModel simpleModel2 = new SimpleModel();",
" simpleModel2.copyFrom(simpleModel1);",
" }",
"}");
private MockJavaResource simpleModelResource =
JavaResourceBase.createMockJavaResource("com.foo.SimpleModel",
"package com.foo;",
"public class SimpleModel {",
" private int value = Constants.CONSTANT;",
" public void copyFrom(Object object) {}",
"}");
private MockJavaResource modifiedFunctionSignatureSimpleModelResource =
JavaResourceBase.createMockJavaResource("com.foo.SimpleModel",
"package com.foo;",
"public class SimpleModel {",
" private int value = Constants.CONSTANT;",
" public void copyFrom(SimpleModel that) {}",
"}");
private MockResource simpleModuleResource =
JavaResourceBase.createMockResource("com/foo/SimpleModule.gwt.xml",
"<module>",
"<source path=''/>",
"<entry-point class='com.foo.TestEntryPoint'/>",
"</module>");
private MockJavaResource constantsModelResource =
JavaResourceBase.createMockJavaResource("com.foo.Constants",
"package com.foo;",
"public class Constants {",
" public static final int CONSTANT = 0;",
"}");
private MockJavaResource modifiedConstantsModelResource =
JavaResourceBase.createMockJavaResource("com.foo.Constants",
"package com.foo;",
"public class Constants {",
" public static final int CONSTANT = 2;",
"}");
private MockResource unstableGeneratorModuleResource = JavaResourceBase.createMockResource(
"com/foo/SimpleModule.gwt.xml",
"<module>",
"<source path=''/>",
"<entry-point class='com.foo.TestEntryPoint'/>",
"<generate-with class='com.google.gwt.dev.UnstableNestedAnonymousGenerator'>",
" <when-type-is class='java.lang.Object' />",
"</generate-with>",
"</module>");
private MockResource resourceReadingGeneratorModuleResource =
JavaResourceBase.createMockResource("com/foo/SimpleModule.gwt.xml",
"<module>",
"<source path=''/>",
"<entry-point class='com.foo.TestEntryPoint'/>",
"<generate-with class='com.google.gwt.dev.FooResourceGenerator'>",
" <when-type-is class='java.lang.Object' />",
"</generate-with>",
"</module>");
private MockResource barReferencesFooGeneratorModuleResource =
JavaResourceBase.createMockResource("com/foo/SimpleModule.gwt.xml",
"<module>",
"<source path=''/>",
"<entry-point class='com.foo.TestEntryPoint'/>",
"<generate-with class='com.google.gwt.dev.BarReferencesFooGenerator'>",
" <when-type-is class='java.lang.Object' />",
"</generate-with>",
"</module>");
private MockResource cascadingGeneratorModuleResource =
JavaResourceBase.createMockResource("com/foo/SimpleModule.gwt.xml",
"<module>",
"<source path=''/>",
"<entry-point class='com.foo.TestEntryPoint'/>",
"<generate-with class='com.google.gwt.dev.CauseStringRebindGenerator'>",
" <when-type-is class='java.lang.Object' />",
"</generate-with>",
"<generate-with class='com.google.gwt.dev.CauseShortRebindGenerator'>",
" <when-type-is class='java.lang.String' />",
"</generate-with>",
"<generate-with class='com.google.gwt.dev.FooResourceGenerator'>",
" <when-type-is class='java.lang.Short' />",
"</generate-with>",
"</module>");
private MockResource multipleClassGeneratorModuleResource =
JavaResourceBase.createMockResource("com/foo/SimpleModule.gwt.xml",
"<module>",
"<source path=''/>",
"<entry-point class='com.foo.TestEntryPoint'/>",
"<generate-with class='com.google.gwt.dev.MultipleClassGenerator'>",
" <when-type-is class='java.lang.Object' />",
"</generate-with>",
"</module>");
private MockResource classNameToGenerateResource =
JavaResourceBase.createMockResource("com/foo/generatedClassName.txt",
"FooReplacementOne");
private MockResource modifiedClassNameToGenerateResource =
JavaResourceBase.createMockResource("com/foo/generatedClassName.txt",
"FooReplacementTwo");
private MockJavaResource generatorEntryPointResource =
JavaResourceBase.createMockJavaResource("com.foo.TestEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"import com.google.gwt.core.client.GWT;",
"public class TestEntryPoint implements EntryPoint {",
" @Override",
" public void onModuleLoad() {",
" GWT.create(Object.class);",
" }",
"}");
private MockJavaResource referencesBarAndGeneratorEntryPointResource =
JavaResourceBase.createMockJavaResource("com.foo.TestEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"import com.google.gwt.core.client.GWT;",
"public class TestEntryPoint implements EntryPoint {",
" Bar bar = new Bar();",
" @Override",
" public void onModuleLoad() {",
" GWT.create(Object.class);",
" }",
"}");
private MockJavaResource superClassOrderEntryPointResource =
JavaResourceBase.createMockJavaResource("com.foo.TestEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class TestEntryPoint implements EntryPoint {",
" @Override",
" public void onModuleLoad() {",
" SuperClass superClass = new SuperClass();",
" ASubClass aSubClass = new ASubClass();",
" }",
"}");
private MockJavaResource referencedBySuperClassResource =
JavaResourceBase.createMockJavaResource("com.foo.ReferencedBySuperClass",
"package com.foo;",
"public class ReferencedBySuperClass {}");
private MockJavaResource superClassResource =
JavaResourceBase.createMockJavaResource("com.foo.SuperClass",
"package com.foo;",
"public class SuperClass {",
" ReferencedBySuperClass referencedBySuperClass = new ReferencedBySuperClass();",
"}");
private MockJavaResource aSubClassResource =
JavaResourceBase.createMockJavaResource("com.foo.ASubClass",
"package com.foo;",
"public class ASubClass extends SuperClass {}");
private MockJavaResource modifiedSuperEntryPointResource =
JavaResourceBase.createMockJavaResource("com.foo.TestEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class TestEntryPoint implements EntryPoint {",
" @Override",
" public void onModuleLoad() {",
" Object d = new ModelD();",
" if (d instanceof ModelA) {",
" // ModelD extends ModelA;",
" } else {",
" // ModelD does not ModelA;",
" }",
" }",
"}");
private MockJavaResource modelAResource =
JavaResourceBase.createMockJavaResource("com.foo.ModelA",
"package com.foo;",
"public class ModelA {}");
private MockJavaResource modelBResource =
JavaResourceBase.createMockJavaResource("com.foo.ModelB",
"package com.foo;",
"public class ModelB extends ModelA {}");
private MockJavaResource modelCResource =
JavaResourceBase.createMockJavaResource("com.foo.ModelC",
"package com.foo;",
"public class ModelC {}");
private MockJavaResource modifiedSuperModelCResource =
JavaResourceBase.createMockJavaResource("com.foo.ModelC",
"package com.foo;",
"public class ModelC extends ModelA {}");
private MockJavaResource modelDResource =
JavaResourceBase.createMockJavaResource("com.foo.ModelD",
"package com.foo;",
"public class ModelD extends ModelC {}");
private MockJavaResource modifiedJsoIntfDispatchEntryPointResource =
JavaResourceBase.createMockJavaResource("com.foo.TestEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class TestEntryPoint implements EntryPoint {",
" @Override",
" public void onModuleLoad() {",
" Caller.call(this);",
" }",
"",
" public void runTest(FooInterface fooInterface) {",
" fooInterface.run();",
" }",
"}");
private MockJavaResource callerResource =
JavaResourceBase.createMockJavaResource("com.foo.Caller",
"package com.foo;",
"public class Caller {",
" public static void call(TestEntryPoint testEntryPoint) {",
" testEntryPoint.runTest(Foo.createFoo());",
" }",
"}");
private MockJavaResource sameContentDifferentTimeFooResource = JavaResourceBase
.createMockJavaResource("com.foo.Foo",
"package com.foo;",
"public class Foo {}");
private MockJavaResource fooInterfaceResource =
JavaResourceBase.createMockJavaResource("com.foo.FooInterface",
"package com.foo;",
"public interface FooInterface {",
" void run();",
"}");
private MockJavaResource jsoFooResource =
JavaResourceBase.createMockJavaResource("com.foo.Foo",
"package com.foo;",
"import com.google.gwt.core.client.JavaScriptObject;",
"public final class Foo extends JavaScriptObject implements FooInterface {",
" public static native Foo createFoo() /*-{",
" return {};",
" }-*/;",
"",
" protected Foo() {}",
"",
" @Override",
" public void run() {}",
"}");
private MockJavaResource nonJsoFooResource =
JavaResourceBase.createMockJavaResource("com.foo.Foo",
"package com.foo;",
"public class Foo implements FooInterface {",
" public static Foo createFoo() {",
" return new Foo();",
" }",
"",
" @Override",
" public void run() {}",
"}");
private MockJavaResource fooResource =
JavaResourceBase.createMockJavaResource("com.foo.Foo",
"package com.foo;",
"public class Foo {}");
private MockJavaResource barReferencesFooResource =
JavaResourceBase.createMockJavaResource("com.foo.Bar",
"package com.foo;",
"public class Bar {",
" Foo foo = new Foo();",
"}");
private MockJavaResource jsTypeBarResource =
JavaResourceBase.createMockJavaResource(
"com.foo.Bar",
"package com.foo;",
"import jsinterop.annotations.JsType;",
"@JsType public class Bar {",
" void doInstanceBar() {}",
" public static void doStaticBaz() {}",
"}");
private MockJavaResource nonCompilableFooResource =
JavaResourceBase.createMockJavaResource("com.foo.Foo",
"package com.foo;",
"public class Foo {",
" public void run() {",
" // Not available in GWT.",
" String.format(\"asdf\");",
" }",
"}");
private MockJavaResource emptyEntryPointResource =
JavaResourceBase.createMockJavaResource("com.foo.TestEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class TestEntryPoint implements EntryPoint {",
" @Override",
" public void onModuleLoad() {}",
"}");
MockJavaResource entryPointResourceForFoo =
JavaResourceBase.createMockJavaResource("com.foo.TestEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"import com.foo.Foo;",
"public class TestEntryPoint implements EntryPoint {",
" @Override",
" public void onModuleLoad() { new Foo(); }",
"}");
private MockJavaResource gwtCreateEntryPointResource =
JavaResourceBase.createMockJavaResource("com.foo.TestEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"import com.google.gwt.core.client.GWT;",
"import jsinterop.annotations.JsType;",
"public class TestEntryPoint implements EntryPoint {",
" @JsType public static class MyJsType {}",
" @JsType public interface MyJsTypeInterface {}",
" public static class MyTypeImplementsJsType implements MyJsTypeInterface {}",
" @Override",
" public void onModuleLoad() {",
" GWT.create(MyJsType.class);",
" GWT.create(MyTypeImplementsJsType.class);",
" }",
"}");
private MockJavaResource dialogEntryPointResource =
JavaResourceBase.createMockJavaResource("com.foo.TestEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class TestEntryPoint implements EntryPoint {",
" @Override",
" public void onModuleLoad() {",
" SimpleDialog simpleDialog = new SimpleDialog();",
" ComplexDialog complexDialog = new ComplexDialog();",
" }",
"}");
private MockJavaResource brokenGwtCreateEntryPointResource =
JavaResourceBase.createMockJavaResource("com.foo.TestEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"import com.google.gwt.core.client.GWT;",
"import com.google.gwt.core.client.JavaScriptObject;",
"public class TestEntryPoint implements EntryPoint {",
" public static class MyJso extends JavaScriptObject {",
" protected MyJso() {}",
" }",
" @Override",
" public void onModuleLoad() {",
" GWT.create(MyJso.class);",
" }",
"}");
private MockJavaResource topResource =
JavaResourceBase.createMockJavaResource("com.foo.top",
"package com.foo;",
"abstract class Top {",
" Object run() {",
" return \"\";",
" }",
"}");
private MockJavaResource middleResource =
JavaResourceBase.createMockJavaResource("com.foo.Middle",
"package com.foo;",
"public abstract class Middle extends Top {",
" abstract String run();",
"}");
private MockJavaResource bottomResource =
JavaResourceBase.createMockJavaResource("com.foo.Bottom",
"package com.foo;",
"public class Bottom extends Middle {",
" // ",
" private final class Value {}",
" String run() {",
" Value value = new Value();",
" return \"\";",
" }",
"}");
private MockJavaResource overriddenMethodChainEntryPointResource =
JavaResourceBase.createMockJavaResource("com.foo.TestEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class TestEntryPoint implements EntryPoint {",
" @Override",
" public void onModuleLoad() {",
" Bottom bottom = new Bottom();",
" ((Top)bottom).run();",
" }",
"}");
private MockJavaResource bazResource =
JavaResourceBase.createMockJavaResource("com.foo.Baz",
"package com.foo;",
"public class Baz {}");
private MockJavaResource regularFooImplemetorResource =
JavaResourceBase.createMockJavaResource("com.foo.FooImplementor",
"package com.foo;",
"public class FooImplementor implements FooInterface {",
" @Override",
" public void run() {}",
"}");
private MockJavaResource simpleFactory =
JavaResourceBase.createMockJavaResource("com.foo.SimpleFactory",
"package com.foo;",
"public class SimpleFactory {",
" public static SimpleIntf getJso() {",
" return getJsoImpl();",
" };",
" public static native SimpleJso getJsoImpl() /*-{",
" return null;",
" }-*/;",
"}");
private MockJavaResource simpleJso =
JavaResourceBase.createMockJavaResource("com.foo.SimpleJso",
"package com.foo;",
"import com.google.gwt.core.client.JavaScriptObject;",
"public class SimpleJso extends JavaScriptObject implements SimpleIntf {",
" protected SimpleJso() {",
" }",
" public final void method() {",
" }",
"}");
private MockJavaResource simpleIntf =
JavaResourceBase.createMockJavaResource("com.foo.SimpleIntf",
"package com.foo;",
"import com.google.gwt.core.client.JavaScriptObject;",
"public interface SimpleIntf {",
" public void method();",
"}");
private MockJavaResource jsoTestEntryPointResource =
JavaResourceBase.createMockJavaResource("com.foo.TestEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class TestEntryPoint implements EntryPoint {",
" @Override",
" public void onModuleLoad() {",
" SimpleFactory.getJso().method();",
" }",
"}");
private MockResource jsoTestModuleResource =
JavaResourceBase.createMockResource("com/foo/SimpleModule.gwt.xml",
"<module>",
"<source path=''/>",
"<entry-point class='com.foo.TestEntryPoint'/>",
"</module>");
private MockResource myWidgetUiXml =
JavaResourceBase.createMockResource("com/foo/MyWidget.ui.xml",
"<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'",
" xmlns:g='urn:import:com.google.gwt.user.client.ui'>",
"<g:HTMLPanel>",
" Hello, <g:ListBox ui:field='myListBox' visibleItemCount='1'/>.",
"</g:HTMLPanel>",
"</ui:UiBinder>");
private MockResource myWidgetWithWhiteStyleUiXml =
JavaResourceBase.createMockResource("com/foo/MyWidget.ui.xml",
"<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'",
" xmlns:g='urn:import:com.google.gwt.user.client.ui'>",
" <ui:style>",
" .title {",
" background-color: white;",
" }",
" </ui:style>",
" <g:HTMLPanel><g:ListBox ui:field='myListBox' visibleItemCount='1'/></g:HTMLPanel>",
"</ui:UiBinder>");
private MockResource myWidgetWithGreyStyleUiXml =
JavaResourceBase.createMockResource("com/foo/MyWidget.ui.xml",
"<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'",
" xmlns:g='urn:import:com.google.gwt.user.client.ui'>",
" <ui:style>",
" .title {",
" background-color: grey;",
" }",
" </ui:style>",
" <g:HTMLPanel><g:ListBox ui:field='myListBox' visibleItemCount='1'/></g:HTMLPanel>",
"</ui:UiBinder>");
private MockJavaResource myWidget =
JavaResourceBase.createMockJavaResource("com.foo.MyWidget",
"package com.foo;",
"import com.google.gwt.core.client.GWT;",
"import com.google.gwt.core.client.JavaScriptObject;",
"import com.google.gwt.uibinder.client.UiBinder;",
"import com.google.gwt.uibinder.client.UiField;",
"import com.google.gwt.user.client.ui.Composite;",
"import com.google.gwt.user.client.ui.ListBox;",
"import com.google.gwt.user.client.ui.Widget;",
"public class MyWidget extends Composite {",
" interface Binder extends UiBinder<Widget, MyWidget> {",
" }",
" private static final Binder binder = GWT.create(Binder.class);",
" @UiField ListBox myListBox;",
" public MyWidget() {",
" init();",
" }",
" protected void init() {",
" initWidget(binder.createAndBindUi(this));",
" myListBox.addItem(\"One\");",
" }",
"}");
private MockJavaResource uiBinderTestEntryPointResource =
JavaResourceBase.createMockJavaResource("com.foo.TestEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"import com.google.gwt.dom.client.Node;",
"import com.google.gwt.user.client.ui.RootPanel;",
"public class TestEntryPoint implements EntryPoint {",
" private Node node;",
" private MyWidget widget;",
" @Override",
" public void onModuleLoad() {",
" node = null; widget = new MyWidget();",
" RootPanel.get().add(widget);",
" }",
"}");
private MockResource uiBinderTestModuleResource =
JavaResourceBase.createMockResource("com/foo/UiBinderTestModule.gwt.xml",
"<module>",
" <inherits name='com.google.gwt.core.Core'/>",
" <inherits name='com.google.gwt.user.User' />",
" <source path=''/>",
" <set-property name='user.agent' value='safari'/>",
" <entry-point class='com.foo.TestEntryPoint'/>",
"</module>");
private MockResource devirtualizeStringModuleResource =
JavaResourceBase.createMockResource("com/foo/DevirtualizeStringModule.gwt.xml",
"<module>",
"<source path=''/>",
"<entry-point class='com.foo.DevirtualizeStringEntryPoint'/>",
"</module>");
private MockJavaResource devirtualizeStringEntryPointResource =
JavaResourceBase.createMockJavaResource("com.foo.DevirtualizeStringEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class DevirtualizeStringEntryPoint implements EntryPoint {",
" @Override",
" public void onModuleLoad() {",
" CharSequence seq = \"A\";",
" seq.subSequence(0,1);",
" }",
"}");
private MockResource transitivelyFoldableConstantModuleResource =
JavaResourceBase.createMockResource(
"com/foo/TransitivelyFoldableConstantModule.gwt.xml",
"<module>",
"<source path=''/>",
"<entry-point class='com.foo.TransitivelyFoldableConstantEntryPoint'/>",
"</module>");
private MockJavaResource transitivelyFoldableConstantEntryPointResource =
JavaResourceBase.createMockJavaResource(
"com.foo.TransitivelyFoldableConstantEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class TransitivelyFoldableConstantEntryPoint",
" implements EntryPoint {",
" static final int CONST = 1 + ClassOne.CONST;",
" @Override",
" public void onModuleLoad() {",
" int c = CONST;",
" }",
"}");
private MockJavaResource classOneResource =
JavaResourceBase.createMockJavaResource(
"com.foo.ClassOne",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class ClassOne {",
" static final int CONST = 1 + ClassTwo.CONST;",
"}");
private MockJavaResource classTwoResource =
JavaResourceBase.createMockJavaResource(
"com.foo.ClassTwo",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class ClassTwo {",
" static final int CONST = 1 + 3;",
"}");
private MockResource superFromStaleInnerModuleResource =
JavaResourceBase.createMockResource(
"com/foo/SuperFromStaleInnerModule.gwt.xml",
"<module>",
" <source path=''/>",
" <entry-point class='com.foo.SuperFromStaleInnerEntryPoint'/>",
"</module>");
private MockJavaResource superFromStaleInnerEntryPointResource =
JavaResourceBase.createMockJavaResource(
"com.foo.SuperFromStaleInnerEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class SuperFromStaleInnerEntryPoint",
" implements EntryPoint {",
" static class A { int f() { return 1; } }",
" static class B extends A {",
" int f() { return 2; }",
" void g() {",
" new InterfaceOne() {",
" public int m() { return 2 + B.super.f(); }",
" }.m();",
" }",
" }",
" @Override",
" public void onModuleLoad() {",
" new B().g();",
" }",
"}");
private MockJavaResource interfaceOneResource =
JavaResourceBase.createMockJavaResource(
"com.foo.InterfaceOne",
"package com.foo;",
"interface InterfaceOne {",
" int m();",
"}");
private MockResource helloModuleResource =
JavaResourceBase.createMockResource(
"com/foo/Hello.gwt.xml",
"<module>",
" <inherits name='com.google.gwt.user.User'/>",
" <source path=''/>",
" <set-property name='user.agent' value='safari'/>",
" <entry-point class='com.foo.HelloEntryPoint'/>",
"</module>");
private MockJavaResource helloEntryPointResource =
JavaResourceBase.createMockJavaResource(
"com.foo.HelloEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"import com.google.gwt.event.dom.client.ClickEvent;",
"import com.google.gwt.event.dom.client.ClickHandler;",
"import com.google.gwt.user.client.Window;",
"import com.google.gwt.user.client.ui.Button;",
"import com.google.gwt.user.client.ui.RootPanel;",
"public class HelloEntryPoint implements EntryPoint {",
" public void onModuleLoad() {",
" Button b = new Button(\"Click me\", new ClickHandler() {",
" public void onClick(ClickEvent event) {",
" Window.alert(\"Hello, AJAX\");",
" }",
" });",
" RootPanel.get().add(b);" ,
" }",
"}");
private Set<String> emptySet = stringSet();
@Override
protected void setUp() throws Exception {
super.setUp();
FooResourceGenerator.runCount = 0;
BarReferencesFooGenerator.runCount = 0;
CauseStringRebindGenerator.runCount = 0;
CauseShortRebindGenerator.runCount = 0;
}
public void testAllValidArgs() {
CompilerOptionsImpl options = new CompilerOptionsImpl();
Compiler.ArgProcessor argProcessor = new Compiler.ArgProcessor(options);
assertProcessSuccess(argProcessor, new String[] {"-logLevel", "DEBUG", "-style",
"PRETTY", "-ea", "-gen", "myGen",
"-war", "myWar", "-workDir", "myWork", "-extra", "myExtra", "-incremental",
"-localWorkers", "2", "-sourceLevel", "1.8", "c.g.g.h.H", "my.Module"});
assertEquals(new File("myGen").getAbsoluteFile(),
options.getGenDir().getAbsoluteFile());
assertEquals(new File("myWar"), options.getWarDir());
assertEquals(new File("myWork"), options.getWorkDir());
assertEquals(new File("myExtra"), options.getExtraDir());
assertEquals(2, options.getLocalWorkers());
assertEquals(TreeLogger.DEBUG, options.getLogLevel());
assertEquals(JsOutputOption.PRETTY, options.getOutput());
assertTrue(options.isEnableAssertions());
assertTrue(options.shouldClusterSimilarFunctions());
assertTrue(options.shouldInlineLiteralParameters());
assertTrue(options.shouldOptimizeDataflow());
assertTrue(options.shouldOrdinalizeEnums());
assertTrue(options.shouldRemoveDuplicateFunctions());
assertTrue(options.isIncrementalCompileEnabled());
assertEquals(SourceLevel.JAVA8, options.getSourceLevel());
assertEquals(2, options.getModuleNames().size());
assertEquals("c.g.g.h.H", options.getModuleNames().get(0));
assertEquals("my.Module", options.getModuleNames().get(1));
}
public void testDefaultArgs() {
CompilerOptionsImpl options = new CompilerOptionsImpl();
Compiler.ArgProcessor argProcessor = new Compiler.ArgProcessor(options);
assertProcessSuccess(argProcessor, new String[]{"c.g.g.h.H"});
assertEquals(null, options.getGenDir());
assertEquals(new File("war").getAbsoluteFile(),
options.getWarDir().getAbsoluteFile());
assertEquals(null, options.getWorkDir());
assertEquals(null, options.getExtraDir());
assertEquals(TreeLogger.INFO, options.getLogLevel());
assertEquals(JsOutputOption.OBFUSCATED, options.getOutput());
assertFalse(options.isEnableAssertions());
assertTrue(options.shouldClusterSimilarFunctions());
assertTrue(options.shouldInlineLiteralParameters());
assertTrue(options.shouldOptimizeDataflow());
assertTrue(options.shouldOrdinalizeEnums());
assertTrue(options.shouldRemoveDuplicateFunctions());
assertFalse(options.isIncrementalCompileEnabled());
assertEquals(1, options.getLocalWorkers());
assertEquals(1, options.getModuleNames().size());
assertEquals("c.g.g.h.H", options.getModuleNames().get(0));
}
public void testForbiddenArgs() {
CompilerOptionsImpl options = new CompilerOptionsImpl();
Compiler.ArgProcessor argProcessor = new Compiler.ArgProcessor(options);
assertProcessFailure(argProcessor, "Unknown argument", new String[]{"-out", "www"});
assertProcessFailure(argProcessor, "Source level must be one of",
new String[]{"-sourceLevel", "ssss"});
assertProcessFailure(argProcessor, "Source level must be one of",
new String[]{"-sourceLevel", "1.5"});
}
/**
* Tests ordering for emum {@link SourceLevel}.
*/
public void testSourceLevelOrdering() {
SourceLevel[] sourceLevels = SourceLevel.values();
SourceLevel previousSourceLevel = sourceLevels[0];
for (int i = 1; i < sourceLevels.length; i++) {
assertTrue(Utility.versionCompare(previousSourceLevel.getStringValue(),
sourceLevels[i].getStringValue()) < 0);
previousSourceLevel = sourceLevels[i];
}
}
public void testSourceLevelSelection() {
assertEquals(SourceLevel.JAVA8, SourceLevel.getBestMatchingVersion("1.4"));
assertEquals(SourceLevel.JAVA8, SourceLevel.getBestMatchingVersion("1.5"));
assertEquals(SourceLevel.JAVA8, SourceLevel.getBestMatchingVersion("1.6"));
assertEquals(SourceLevel.JAVA8, SourceLevel.getBestMatchingVersion("1.6_26"));
assertEquals(SourceLevel.JAVA8, SourceLevel.getBestMatchingVersion("1.7"));
assertEquals(SourceLevel.JAVA8, SourceLevel.getBestMatchingVersion("1.8"));
assertEquals(SourceLevel.JAVA8, SourceLevel.getBestMatchingVersion("1.9"));
// not proper version strings => default to JAVA8.
assertEquals(SourceLevel.JAVA8, SourceLevel.getBestMatchingVersion("1.6u3"));
assertEquals(SourceLevel.JAVA8, SourceLevel.getBestMatchingVersion("1.6b3"));
assertEquals(SourceLevel.JAVA8, SourceLevel.getBestMatchingVersion("1.7b3"));
}
/**
* Verify that a compile with a @JsType at least compiles successfully.
*/
public void testGwtCreateJsTypeRebindResult() throws Exception {
CompilerOptions compilerOptions = new CompilerOptionsImpl();
compileToJs(compilerOptions, Files.createTempDir(), "com.foo.SimpleModule",
Lists.newArrayList(simpleModuleResource, gwtCreateEntryPointResource),
new MinimalRebuildCache(), emptySet, JsOutputOption.OBFUSCATED);
}
/**
* Test that some lightly referenced interface through a @JsFunction is included in the output.
*/
public void testReferenceThroughJsFunction() throws Exception {
MockJavaResource someJsFunction =
JavaResourceBase.createMockJavaResource(
"com.foo.SomeJsFunction",
"package com.foo;",
"import jsinterop.annotations.JsFunction;",
"@JsFunction",
"public interface SomeJsFunction {",
" void m();",
"}");
MockJavaResource jsFunctionInterfaceImplementation =
JavaResourceBase.createMockJavaResource(
"com.foo.Impl",
"package com.foo;",
"public final class Impl implements SomeJsFunction {",
" public void m() { SomeInterface.class.getName(); } ",
"}");
MockJavaResource someInterface =
JavaResourceBase.createMockJavaResource(
"com.foo.SomeInterface",
"package com.foo;",
"public interface SomeInterface {",
"}");
MockJavaResource testEntryPoint =
JavaResourceBase.createMockJavaResource(
"com.foo.TestEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class TestEntryPoint implements EntryPoint {",
" private static native void f(SomeJsFunction f) /*-{}-*/;",
" public void onModuleLoad() {",
// Create Impl and pass it to JS but do not explicitly call m
" f(new Impl());",
" }",
"}");
MockResource moduleResource =
JavaResourceBase.createMockResource(
"com/foo/TestEntryPoint.gwt.xml",
"<module>",
" <source path=''/>",
" <entry-point class='com.foo.TestEntryPoint'/>",
"</module>");
CompilerOptions compilerOptions = new CompilerOptionsImpl();
String js = compileToJs(compilerOptions, Files.createTempDir(), testEntryPoint.getTypeName(),
Lists.newArrayList(moduleResource, testEntryPoint, someJsFunction,
jsFunctionInterfaceImplementation, someInterface),
new MinimalRebuildCache(), emptySet, JsOutputOption.DETAILED);
// Make sure the referenced class literals ends up being included in the resulting JS.
String classliteralHolderVarName =
JjsUtils.mangleMemberName("com.google.gwt.lang.ClassLiteralHolder",
JjsUtils.classLiteralFieldNameFromJavahTypeSignatureName(
JjsUtils.javahSignatureFromName(someInterface.getTypeName())));
assertTrue(js.contains("var " + classliteralHolderVarName + " = "));
}
/**
* Tests that changing Js namespace name on an exported method comes out accurately.
*
* <p>An unrelated and non-updated @JsType is also included in each compile to verify that updated
* exports do not forget non-edited items in a recompile.
*/
public void testChangeJsNamespaceOnMethod() throws Exception {
CompilerOptions compilerOptions = new CompilerOptionsImpl();
compilerOptions.setUseDetailedTypeIds(true);
compilerOptions.setGenerateJsInteropExports(true);
MockJavaResource jsNamespaceFooResource =
JavaResourceBase.createMockJavaResource(
"com.foo.Foo",
"package com.foo;",
"import jsinterop.annotations.JsMethod;",
"import jsinterop.annotations.JsType;",
"@JsType public class Foo {",
" @JsMethod(namespace=\"spazz\") public static void doStaticBar() {}",
"}");
MockJavaResource regularFooResource =
JavaResourceBase.createMockJavaResource(
"com.foo.Foo",
"package com.foo;",
"import jsinterop.annotations.JsType;",
"@JsType public class Foo {",
" public static void doStaticBar() {}",
"}");
checkRecompiledModifiedApp(
compilerOptions,
"com.foo.SimpleModule",
Lists.newArrayList(simpleModuleResource, emptyEntryPointResource, jsTypeBarResource),
regularFooResource,
jsNamespaceFooResource,
stringSet("com.foo.Bar", "com.foo.Foo"),
JsOutputOption.DETAILED);
}
/**
* Tests that changing Js namespace on a class comes out accurately.
*
* <p>An unrelated and non-updated @JsType is also included in each compile to verify that updated
* exports do not forget non-edited items in a recompile.
*/
public void testChangeJsNamespaceOnClass() throws Exception {
CompilerOptions compilerOptions = new CompilerOptionsImpl();
compilerOptions.setUseDetailedTypeIds(true);
compilerOptions.setGenerateJsInteropExports(true);
MockJavaResource jsNamespaceFooResource =
JavaResourceBase.createMockJavaResource(
"com.foo.Foo",
"package com.foo;",
"import jsinterop.annotations.JsType;",
"@JsType(namespace=\"spazz\") public class Foo {",
" public static void doStaticBar() {}",
"}");
MockJavaResource regularFooResource =
JavaResourceBase.createMockJavaResource(
"com.foo.Foo",
"package com.foo;",
"import jsinterop.annotations.JsType;",
"@JsType public class Foo {",
" public static void doStaticBar() {}",
"}");
checkRecompiledModifiedApp(
compilerOptions,
"com.foo.SimpleModule",
Lists.newArrayList(simpleModuleResource, emptyEntryPointResource, jsTypeBarResource),
regularFooResource,
jsNamespaceFooResource,
stringSet("com.foo.Bar", "com.foo.Foo"),
JsOutputOption.DETAILED);
}
/**
* Tests that changing @JsFunction name on an interface comes out accurately.
*
* <p>An unrelated and non-updated @JsType is also included in each compile to verify that updated
* exports do not forget non-edited items in a recompile.
*/
public void testChangeJsFunction() throws Exception {
CompilerOptions compilerOptions = new CompilerOptionsImpl();
compilerOptions.setUseDetailedTypeIds(true);
compilerOptions.setGenerateJsInteropExports(true);
MockJavaResource jsFunctionIFooResource =
JavaResourceBase.createMockJavaResource(
"com.foo.IFoo",
"package com.foo;",
"import jsinterop.annotations.JsFunction;",
"@JsFunction public interface IFoo {",
" int foo(int x);",
"}");
MockJavaResource regularIFooResource =
JavaResourceBase.createMockJavaResource(
"com.foo.IFoo",
"package com.foo;",
"public interface IFoo {",
" int foo(int x);",
"}");
MockJavaResource fooResource =
JavaResourceBase.createMockJavaResource(
"com.foo.Foo",
"package com.foo;",
"public final class Foo implements IFoo {",
" @Override public int foo(int x) { return 0; }",
"}");
checkRecompiledModifiedApp(
compilerOptions,
"com.foo.SimpleModule",
Lists.newArrayList(
simpleModuleResource, entryPointResourceForFoo, fooResource, jsTypeBarResource),
regularIFooResource,
jsFunctionIFooResource,
stringSet("com.foo.Bar", "com.foo.Foo", "com.foo.IFoo", "com.foo.TestEntryPoint"),
JsOutputOption.DETAILED);
}
/**
* Tests that toggling JsProperty methods in an interface comes out accurately.
*
* <p>An unrelated and non-updated @JsType is also included in each compile to verify that updated
* exports do not forget non-edited items in a recompile.
*/
public void testChangeJsProperty() throws Exception {
CompilerOptions compilerOptions = new CompilerOptionsImpl();
compilerOptions.setUseDetailedTypeIds(true);
compilerOptions.setGenerateJsInteropExports(true);
MockJavaResource jsPropertyIFooResource =
JavaResourceBase.createMockJavaResource(
"com.foo.IFoo",
"package com.foo;",
"import jsinterop.annotations.JsProperty;",
"import jsinterop.annotations.JsType;",
"@JsType public interface IFoo {",
" @JsProperty int getX();",
" @JsProperty int getY();",
"}");
MockJavaResource regularIFooResource =
JavaResourceBase.createMockJavaResource(
"com.foo.IFoo",
"package com.foo;",
"import jsinterop.annotations.JsType;",
"@JsType public interface IFoo {",
" int getX();",
" int getY();",
"}");
MockJavaResource fooResource =
JavaResourceBase.createMockJavaResource(
"com.foo.Foo",
"package com.foo;",
"public class Foo implements IFoo {",
" @Override public int getX() { return 0; }",
" @Override public int getY() { return 0; }",
"}");
checkRecompiledModifiedApp(
compilerOptions,
"com.foo.SimpleModule",
Lists.newArrayList(
simpleModuleResource, entryPointResourceForFoo, fooResource, jsTypeBarResource),
regularIFooResource,
jsPropertyIFooResource,
stringSet("com.foo.Bar", "com.foo.Foo", "com.foo.IFoo", "com.foo.TestEntryPoint"),
JsOutputOption.DETAILED);
}
/**
* Tests that adding a @JsType annotation on a class comes out accurately and that removing it
* comes out accurately as well.
*
* <p>An unrelated and non-updated @JsType is also included in each compile to verify that updated
* exports do not forget non-edited items in a recompile.
*/
public void testChangeJsType() throws Exception {
CompilerOptions compilerOptions = new CompilerOptionsImpl();
compilerOptions.setUseDetailedTypeIds(true);
compilerOptions.setGenerateJsInteropExports(true);
MockJavaResource jsTypeFooResource =
JavaResourceBase.createMockJavaResource(
"com.foo.Foo",
"package com.foo;",
"import jsinterop.annotations.JsType;",
"@JsType public class Foo {",
" void doInstanceBar() {}",
" public static void doStaticBar() {}",
"}");
MockJavaResource regularFooResource =
JavaResourceBase.createMockJavaResource(
"com.foo.Foo", "package com.foo;", "public class Foo {}");
checkRecompiledModifiedApp(
compilerOptions,
"com.foo.SimpleModule",
Lists.newArrayList(simpleModuleResource, emptyEntryPointResource, jsTypeBarResource),
regularFooResource,
jsTypeFooResource,
stringSet("com.foo.Bar", "com.foo.Foo"),
JsOutputOption.DETAILED);
}
/**
* Tests that changing a prototype on a @JsType annotated class comes out accurately.
*
* <p>An unrelated and non-updated @JsType is also included in each compile to verify that updated
* exports do not forget non-edited items in a recompile.
*/
public void testChangeJsTypeNative() throws Exception {
CompilerOptions compilerOptions = new CompilerOptionsImpl();
compilerOptions.setUseDetailedTypeIds(true);
compilerOptions.setGenerateJsInteropExports(true);
MockJavaResource nativeFooResource =
JavaResourceBase.createMockJavaResource(
"com.foo.Foo",
"package com.foo;",
"import jsinterop.annotations.JsType;",
"@JsType(isNative=true) public class Foo {",
" public static native void doStaticBar();",
"}");
MockJavaResource regularFooResource =
JavaResourceBase.createMockJavaResource(
"com.foo.Foo",
"package com.foo;",
"import jsinterop.annotations.JsType;",
"@JsType public class Foo {",
" public static void doStaticBar() {}",
"}");
checkRecompiledModifiedApp(
compilerOptions,
"com.foo.SimpleModule",
Lists.newArrayList(simpleModuleResource, emptyEntryPointResource, jsTypeBarResource),
regularFooResource,
nativeFooResource,
stringSet("com.foo.Bar", "com.foo.Foo"),
JsOutputOption.DETAILED);
}
/**
* Tests that adding a @JsIgnore annotation on a method comes out accurately and that removing
* it comes out accurately as well.
*
* <p>An unrelated and non-updated @JsType is also included in each compile to verify that updated
* exports do not forget non-edited items in a recompile.
*/
public void testChangeJsIgnore() throws Exception {
CompilerOptions compilerOptions = new CompilerOptionsImpl();
compilerOptions.setUseDetailedTypeIds(true);
compilerOptions.setGenerateJsInteropExports(true);
MockJavaResource jsIgnoreFooResource =
JavaResourceBase.createMockJavaResource(
"com.foo.Foo",
"package com.foo;",
"import jsinterop.annotations.JsIgnore;",
"import jsinterop.annotations.JsType;",
"@JsType public class Foo {",
" @JsIgnore public static void doStaticBar() {}",
"}");
MockJavaResource regularFooResource =
JavaResourceBase.createMockJavaResource(
"com.foo.Foo",
"package com.foo;",
"import jsinterop.annotations.JsType;",
"@JsType public class Foo {",
" public static void doStaticBar() {}",
"}");
checkRecompiledModifiedApp(
compilerOptions,
"com.foo.SimpleModule",
Lists.newArrayList(simpleModuleResource, emptyEntryPointResource, jsTypeBarResource),
regularFooResource,
jsIgnoreFooResource,
stringSet("com.foo.Bar", "com.foo.Foo"),
JsOutputOption.DETAILED);
}
public void testJsInteropNameCollision() throws Exception {
MinimalRebuildCache minimalRebuildCache = new MinimalRebuildCache();
File applicationDir = Files.createTempDir();
CompilerOptions compilerOptions = new CompilerOptionsImpl();
compilerOptions.setGenerateJsInteropExports(true);
// Simple compile with one dialog.alert() export succeeds.
compileToJs(compilerOptions, applicationDir, "com.foo.SimpleModule", Lists.newArrayList(
simpleModuleResource, dialogEntryPointResource, simpleDialogResourceWithExport,
complexDialogResourceSansExport), minimalRebuildCache, emptySet, JsOutputOption.OBFUSCATED);
try {
// Exporting a second dialog.alert() fails with an exported name collision.
compileToJs(compilerOptions, applicationDir, "com.foo.SimpleModule",
Lists.<MockResource> newArrayList(complexDialogResourceWithExport), minimalRebuildCache,
emptySet, JsOutputOption.OBFUSCATED);
fail("Compile should have failed");
} catch (UnableToCompleteException e) {
// success
}
// Reverting to just a single dialog.alert() starts succeeding again.
compileToJs(compilerOptions, applicationDir, "com.foo.SimpleModule",
Lists.<MockResource>newArrayList(complexDialogResourceSansExport), minimalRebuildCache,
stringSet("com.foo.SimpleDialog", "com.foo.ComplexDialog", "com.foo.TestEntryPoint"),
JsOutputOption.OBFUSCATED);
}
public void testGwtCreateJsoRebindResult() throws Exception {
try {
compileToJs(Files.createTempDir(), "com.foo.SimpleModule",
Lists.newArrayList(simpleModuleResource, brokenGwtCreateEntryPointResource),
new MinimalRebuildCache(), emptySet, JsOutputOption.OBFUSCATED);
fail("Compile should have failed");
} catch (UnableToCompleteException e) {
// success
}
}
public void testNonZeroArgConstructorEntryPoint() throws Exception {
MockResource moduleResource =
JavaResourceBase.createMockResource(
"com/foo/NonZeroArgConstructor.gwt.xml",
"<module>",
" <source path=''/>",
" <entry-point class='com.foo.NonZeroArgConstructorEntryPoint'/>",
"</module>");
MockJavaResource entryPointResource =
JavaResourceBase.createMockJavaResource(
"com.foo.NonZeroArgConstructorEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class NonZeroArgConstructorEntryPoint implements EntryPoint {",
" public NonZeroArgConstructorEntryPoint(String s) {",
" }",
" public void onModuleLoad() {",
" }",
"}");
MinimalRebuildCache minimalRebuildCache = new MinimalRebuildCache();
File applicationDir = Files.createTempDir();
CompilerOptions compilerOptions = new CompilerOptionsImpl();
UnitTestTreeLogger.Builder builder = new UnitTestTreeLogger.Builder();
builder.setLowestLogLevel(TreeLogger.ERROR);
builder.expectError(Pattern.compile("Errors in .*"), null);
builder.expectError("Line 3: Rebind result 'com.foo.NonZeroArgConstructorEntryPoint' "
+ "has no default (zero argument) constructors", null);
UnitTestTreeLogger errorLogger = builder.createLogger();
try {
// Simple compile with one dialog.alert() export succeeds.
compileToJs(errorLogger, compilerOptions, applicationDir, "com.foo.NonZeroArgConstructor",
Lists.newArrayList(moduleResource, entryPointResource), minimalRebuildCache,
emptySet, JsOutputOption.OBFUSCATED);
fail("Compile should have failed");
} catch (UnableToCompleteException expected) {
errorLogger.assertCorrectLogEntries();
}
}
public void testDeterministicBuild_Draft_StackModeStrip() throws
UnableToCompleteException, IOException {
assertDeterministicBuild(HELLO_MODULE_STACKMODE_STRIP, 0);
}
public void testDeterministicBuild_Optimized_StackModeStrip() throws
UnableToCompleteException, IOException {
assertDeterministicBuild(HELLO_MODULE_STACKMODE_STRIP, 9);
}
public void testDeterministicBuild_Draft() throws UnableToCompleteException, IOException {
assertDeterministicBuild(HELLO_MODULE, 0);
}
public void testDeterministicBuild_Optimized() throws UnableToCompleteException, IOException {
assertDeterministicBuild(HELLO_MODULE, 9);
}
public void testSuccessfulCompile_jsoClassLiteralOrder() throws Exception {
// Crafted resource to make sure the a native subclass is compiled before the JSO class,
// In the case of native sublcasses the class hierarchy does not match the class literal
// hierarchy.
MockJavaResource nativeClassAndSubclass =
JavaResourceBase.createMockJavaResource(
"com.foo.MyNativeSubclass",
"package com.foo;",
"import jsinterop.annotations.JsType;",
"@JsType(isNative=true)",
"class NativeClass {",
"}",
"public class MyNativeSubclass extends NativeClass {",
"}");
MockJavaResource testEntryPoint =
JavaResourceBase.createMockJavaResource(
"com.foo.MyEntryPoint",
"package com.foo;",
"import com.foo.MyNativeSubclass;",
"public class MyEntryPoint extends MyNativeSubclass {",
" public void onModuleLoad() {",
" Object o = new Object();",
" if (MyNativeSubclass.class.getName() == null) ",
" o = new MyNativeSubclass();",
// Make .clazz reachable so that class literals are emmitted with the respective
// classses.
" o.getClass();",
" }",
"}");
MockResource moduleResource =
JavaResourceBase.createMockResource(
"com/foo/MyEntryPoint.gwt.xml",
"<module>",
" <source path=''/>",
" <entry-point class='com.foo.MyEntryPoint'/>",
"</module>");
CompilerOptions compilerOptions = new CompilerOptionsImpl();
// Make sure it compiles successfully with no assertions
compilerOptions.setEnableAssertions(true);
compilerOptions.setGenerateJsInteropExports(true);
compilerOptions.setOutput(JsOutputOption.PRETTY);
compilerOptions.setOptimizationLevel(9);
assertCompileSucceeds(compilerOptions, testEntryPoint.getTypeName(),
Lists.newArrayList(moduleResource, nativeClassAndSubclass, testEntryPoint));
}
// TODO(stalcup): add recompile tests for file deletion.
public void testIncrementalRecompile_noop() throws UnableToCompleteException, IOException,
InterruptedException {
checkIncrementalRecompile_noop(JsOutputOption.OBFUSCATED);
checkIncrementalRecompile_noop(JsOutputOption.DETAILED);
}
public void testIncrementalRecompile_dateStampChange() throws UnableToCompleteException,
IOException, InterruptedException {
checkIncrementalRecompile_dateStampChange(JsOutputOption.OBFUSCATED);
checkIncrementalRecompile_dateStampChange(JsOutputOption.DETAILED);
}
// Repro for bug #9518
public void testIncrementalRecompile_jsPropertyConsistencyCheck()
throws UnableToCompleteException,
IOException, InterruptedException {
// Supertype defines the getter.
MockJavaResource superType =
JavaResourceBase.createMockJavaResource(
"com.foo.SuperType",
"package com.foo;",
"import jsinterop.annotations.JsProperty;",
"public class SuperType {",
" @JsProperty String getString() { return null; }",
"}");
// Subtype defines the setter.
MockJavaResource subType =
JavaResourceBase.createMockJavaResource(
"com.foo.SubType",
"package com.foo;",
"import jsinterop.annotations.JsProperty;",
"public class SubType extends SuperType {",
" @JsProperty void setString(String s) {}",
"}");
MockJavaResource testEntryPoint =
JavaResourceBase.createMockJavaResource(
"com.foo.TestEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class TestEntryPoint implements EntryPoint {",
" public void onModuleLoad() {",
// Create Impl and pass it to JS but do not explicitly call m
" new SubType();",
" }",
"}");
MockResource moduleResource =
JavaResourceBase.createMockResource(
"com/foo/TestModule.gwt.xml",
"<module>",
" <source path=''/>",
" <entry-point class='com.foo.TestEntryPoint'/>",
"</module>");
MinimalRebuildCache relinkMinimalRebuildCache = new MinimalRebuildCache();
File relinkApplicationDir = Files.createTempDir();
// Perform a first compile.
compileToJs(relinkApplicationDir, "com.foo.TestModule",
Lists.newArrayList(moduleResource, testEntryPoint, subType, superType),
relinkMinimalRebuildCache, null, JsOutputOption.OBFUSCATED);
// Invalidate ONLY the subtype. The types referred by the parameters of supertype methods are
// going to be reference only which means that the supertype property will have a reference
// to a JClassType for "java.lang.String" that isExternal() and is different from the
// (non external) reference in the supertype.
relinkMinimalRebuildCache.markSourceFileStale("com/foo/SubType.java");
compileToJs(relinkApplicationDir, "com.foo.TestModule", Lists.<MockResource> newArrayList(),
relinkMinimalRebuildCache, null, JsOutputOption.OBFUSCATED);
}
public void testIncrementalRecompile_invalidatePreamble() throws UnableToCompleteException,
IOException, InterruptedException {
MinimalRebuildCache relinkMinimalRebuildCache = new MinimalRebuildCache();
File relinkApplicationDir = Files.createTempDir();
// Perform a first compile.
compileToJs(relinkApplicationDir, "com.foo.SimpleModule",
Lists.newArrayList(simpleModuleResource, emptyEntryPointResource),
relinkMinimalRebuildCache, null, JsOutputOption.OBFUSCATED);
// On first compile nothing is explicitly stale, only implicitly stale.
assertEquals(0, relinkMinimalRebuildCache.getStaleTypeNames().size());
// Recompile with a deep change that invalidates the preamble.
relinkMinimalRebuildCache.markSourceFileStale("java/lang/Object.java");
compileToJs(relinkApplicationDir, "com.foo.SimpleModule", Lists.<MockResource> newArrayList(),
relinkMinimalRebuildCache, null, JsOutputOption.OBFUSCATED);
// Show that preamble invalidation marks everything stale.
assertTrue(relinkMinimalRebuildCache.getProcessedStaleTypeNames().size() > 100);
// Recompile again with a tiny change. Prove that it's not stuck repeatedly invalidating the
// whole world.
compileToJs(relinkApplicationDir, "com.foo.SimpleModule",
Lists.<MockResource> newArrayList(emptyEntryPointResource), relinkMinimalRebuildCache, null,
JsOutputOption.OBFUSCATED);
// Show that only this little change is stale, not the whole world.
assertEquals(2, getStaleTypeNames(relinkMinimalRebuildCache).size());
}
public void testIncrementalRecompile_bridgeMethodOverrideChain()
throws UnableToCompleteException, IOException, InterruptedException {
MinimalRebuildCache relinkMinimalRebuildCache = new MinimalRebuildCache();
File relinkApplicationDir = Files.createTempDir();
// Perform a first compile.
compileToJs(relinkApplicationDir, "com.foo.SimpleModule", Lists.newArrayList(
simpleModuleResource, overriddenMethodChainEntryPointResource, topResource, middleResource,
bottomResource), relinkMinimalRebuildCache, null, JsOutputOption.OBFUSCATED);
// On first compile nothing is explicitly stale, only implicitly stale.
assertEquals(0, relinkMinimalRebuildCache.getStaleTypeNames().size());
// Recompile with a change to Bottom.
relinkMinimalRebuildCache.markSourceFileStale("com/foo/Bottom.java");
compileToJs(relinkApplicationDir, "com.foo.SimpleModule", Lists.<MockResource> newArrayList(),
relinkMinimalRebuildCache, null, JsOutputOption.OBFUSCATED);
// Show that the third level bridge method override of Top.run() is seen to be live and thus
// makes type com.foo.Bottom$Value live.
assertTrue(
relinkMinimalRebuildCache.getProcessedStaleTypeNames().contains("com.foo.Bottom$Value"));
}
public void testIncrementalRecompile_classLiteralNewReference()
throws UnableToCompleteException, IOException, InterruptedException {
checkIncrementalRecompile_classLiteralNewReference(JsOutputOption.OBFUSCATED);
checkIncrementalRecompile_classLiteralNewReference(JsOutputOption.DETAILED);
}
public void testIncrementalRecompile_primitiveClassLiteralReference()
throws UnableToCompleteException, IOException, InterruptedException {
checkIncrementalRecompile_primitiveClassLiteralReference(JsOutputOption.OBFUSCATED);
checkIncrementalRecompile_primitiveClassLiteralReference(JsOutputOption.DETAILED);
}
public void testIncrementalRecompile_superClassOrder()
throws UnableToCompleteException, IOException, InterruptedException {
// Linked output is sorted alphabetically except that super-classes come before sub-classes. If
// on recompile a sub-class -> super-class relationship is lost then a sub-class with an
// alphabetically earlier name might start linking out before the super-class.
checkIncrementalRecompile_superClassOrder(JsOutputOption.OBFUSCATED);
checkIncrementalRecompile_superClassOrder(JsOutputOption.DETAILED);
}
public void testIncrementalRecompile_superFromStaleInner()
throws UnableToCompleteException, IOException, InterruptedException {
checkIncrementalRecompile_superFromStaleInner(JsOutputOption.OBFUSCATED);
checkIncrementalRecompile_superFromStaleInner(JsOutputOption.DETAILED);
}
public void testIncrementalRecompile_deterministicUiBinder() throws UnableToCompleteException,
IOException, InterruptedException {
checkIncrementalRecompile_deterministicUiBinder(JsOutputOption.OBFUSCATED);
checkIncrementalRecompile_deterministicUiBinder(JsOutputOption.DETAILED);
}
public void testIncrementalRecompile_uiBinderCssChange() throws UnableToCompleteException,
IOException, InterruptedException {
checkIncrementalRecompile_uiBinderCssChange(JsOutputOption.OBFUSCATED);
checkIncrementalRecompile_uiBinderCssChange(JsOutputOption.DETAILED);
}
public void testIncrementalRecompile_unstableGeneratorReferencesModifiedType()
throws UnableToCompleteException, IOException, InterruptedException {
checkIncrementalRecompile_unstableGeneratorReferencesModifiedType(JsOutputOption.OBFUSCATED);
checkIncrementalRecompile_unstableGeneratorReferencesModifiedType(JsOutputOption.DETAILED);
}
public void testIncrementalRecompile_withErrors()
throws UnableToCompleteException, IOException, InterruptedException {
MockResource moduleResource =
JavaResourceBase.createMockResource(
"com/foo/Errors.gwt.xml",
"<module>",
" <source path=''/>",
" <entry-point class='com.foo.ErrorsEntryPoint'/>",
"</module>");
MockJavaResource entryPointResource =
JavaResourceBase.createMockJavaResource(
"com.foo.ErrorsEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class ErrorsEntryPoint implements EntryPoint {",
" public void onModuleLoad() {",
" Foo.foo();",
" }",
"}");
MockJavaResource fooResource =
JavaResourceBase.createMockJavaResource(
"com.foo.Foo",
"package com.foo;",
"public class Foo {",
" public static void foo() {",
" }",
"}");
MockJavaResource fooResourceWithErrors =
JavaResourceBase.createMockJavaResource(
"com.foo.Foo",
"package com.foo;",
"public class Foo {",
" public static void foo() {",
" // x() method is not defined anywhere, should result in a compile error.",
" x();",
" }",
"}");
MinimalRebuildCache minimalRebuildCache = new MinimalRebuildCache();
File applicationDir = Files.createTempDir();
CompilerOptions compilerOptions = new CompilerOptionsImpl();
compilerOptions.setUseDetailedTypeIds(true);
compilerOptions.setSourceLevel(SourceLevel.JAVA8);
// Compile the application with no errors.
compileToJs(TreeLogger.NULL, compilerOptions, applicationDir, "com.foo.Errors",
Lists.newArrayList(moduleResource, entryPointResource, fooResource), minimalRebuildCache,
emptySet, JsOutputOption.OBFUSCATED);
// Recompile and expect error reporting.
UnitTestTreeLogger.Builder builder = new UnitTestTreeLogger.Builder();
builder.setLowestLogLevel(TreeLogger.ERROR);
builder.expectError("Line 5: The method x() is undefined for the type Foo", null);
UnitTestTreeLogger errorLogger = builder.createLogger();
try {
// Recompile but now the changed file has an error
compileToJs(errorLogger, compilerOptions, applicationDir, "com.foo.Errors",
Lists.newArrayList(moduleResource, entryPointResource, fooResourceWithErrors),
minimalRebuildCache,
emptySet, JsOutputOption.OBFUSCATED);
fail("Compile should have failed");
} catch (UnableToCompleteException expected) {
errorLogger.assertLogEntriesContainExpected();
}
}
public void testIncrementalRecompile_representedAsNative()
throws UnableToCompleteException, IOException, InterruptedException {
MockResource moduleResource =
JavaResourceBase.createMockResource(
"com/foo/RepresentedAsNative.gwt.xml",
"<module>",
" <source path=''/>",
" <entry-point class='com.foo.RepresentedAsNativeEntryPoint'/>",
"</module>");
MockResource entryPointResource =
JavaResourceBase.createMockJavaResource(
"com.foo.RepresentedAsNativeEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class RepresentedAsNativeEntryPoint implements EntryPoint {",
" public void onModuleLoad() {",
" Double d = new Double(1d);",
" }",
"}");
MockResource modifiedEntryPointResource =
JavaResourceBase.createMockJavaResource(
"com.foo.RepresentedAsNativeEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class RepresentedAsNativeEntryPoint implements EntryPoint {",
" public void onModuleLoad() {",
" Double d = new Double(\"1\");",
" }",
"}");
PrintWriterTreeLogger logger = new PrintWriterTreeLogger();
logger.setMaxDetail(TreeLogger.ERROR);
MinimalRebuildCache minimalRebuildCache = new MinimalRebuildCache();
File applicationDir = Files.createTempDir();
CompilerOptions compilerOptions = new CompilerOptionsImpl();
compilerOptions.setUseDetailedTypeIds(true);
compilerOptions.setSourceLevel(SourceLevel.JAVA8);
compilerOptions.setGenerateJsInteropExports(false);
// Compile the application with no errors.
compileToJs(logger, compilerOptions, applicationDir, "com.foo.RepresentedAsNative",
Lists.newArrayList(moduleResource, entryPointResource), minimalRebuildCache,
emptySet, JsOutputOption.OBFUSCATED);
// Recompile but now the changed file has an error
compileToJs(logger, compilerOptions, applicationDir, "com.foo.RepresentedAsNative",
Lists.newArrayList(modifiedEntryPointResource),
minimalRebuildCache,
stringSet(
"com.foo.RepresentedAsNativeEntryPoint",
getEntryMethodHolderTypeName("com.foo.RepresentedAsNative")),
JsOutputOption.OBFUSCATED);
}
public void testIncrementalRecompile_functionSignatureChange() throws UnableToCompleteException,
IOException, InterruptedException {
// Not testing recompile equality with Pretty/Obfuscated output since the JsIncrementalNamer's
// behavior is order dependent, and while still correct, will come out different in a recompile
// with this change versus a from scratch compile with this change.
checkIncrementalRecompile_functionSignatureChange(JsOutputOption.DETAILED);
}
public void testIncrementalRecompile_compileTimeConstantChange() throws UnableToCompleteException,
IOException, InterruptedException {
checkIncrementalRecompile_compileTimeConstantChange(JsOutputOption.DETAILED);
checkIncrementalRecompile_compileTimeConstantChange(JsOutputOption.OBFUSCATED);
}
public void testIncrementalRecompile_transitivelyFoldableConstant()
throws UnableToCompleteException,
IOException, InterruptedException {
checkIncrementalRecompile_transitivelyFoldableConstant(JsOutputOption.DETAILED);
checkIncrementalRecompile_transitivelyFoldableConstant(JsOutputOption.OBFUSCATED);
}
public void testIncrementalRecompile_packagePrivateDispatch() throws UnableToCompleteException,
IOException, InterruptedException {
checkIncrementalRecompile_packagePrivateOverride(JsOutputOption.OBFUSCATED);
checkIncrementalRecompile_packagePrivateOverride(JsOutputOption.DETAILED);
}
public void testIncrementalRecompile_prettyOutput()
throws UnableToCompleteException, IOException, InterruptedException {
// Nominal tests for pretty output. Pretty and Obfuscated output share most of the same code
// paths.
checkIncrementalRecompile_typeHierarchyChange(JsOutputOption.PRETTY);
checkIncrementalRecompile_unreachableIncompatibleChange(JsOutputOption.PRETTY);
}
public void testIncrementalRecompile_regularClassMadeIntoJsoClass()
throws UnableToCompleteException, IOException, InterruptedException {
// Not testing recompile equality with Pretty/Obfuscated output since the JsIncrementalNamer's
// behavior is order dependent, and while still correct, will come out different in a recompile
// with this change versus a from scratch compile with this change.
checkIncrementalRecompile_regularClassMadeIntoJsoClass(JsOutputOption.DETAILED);
}
public void testIncrementalRecompile_unreachableIncompatibleChange()
throws UnableToCompleteException, IOException, InterruptedException {
// Not testing recompile equality with Pretty/Obfuscated output since the JsIncrementalNamer's
// behavior is order dependent, and while still correct, will come out different in a recompile
// with this change versus a from scratch compile with this change.
checkIncrementalRecompile_unreachableIncompatibleChange(JsOutputOption.OBFUSCATED);
checkIncrementalRecompile_unreachableIncompatibleChange(JsOutputOption.DETAILED);
}
public void testIncrementalRecompile_typeHierarchyChange()
throws UnableToCompleteException, IOException, InterruptedException {
checkIncrementalRecompile_typeHierarchyChange(JsOutputOption.OBFUSCATED);
checkIncrementalRecompile_typeHierarchyChange(JsOutputOption.DETAILED);
}
public void testIncrementalRecompile_defaultMethod()
throws UnableToCompleteException, IOException, InterruptedException {
// Tests that default method on superclasses are correctly constructed
checkIncrementalRecompile_defaultMethod(JsOutputOption.OBFUSCATED);
checkIncrementalRecompile_defaultMethod(JsOutputOption.DETAILED);
}
public void testIncrementalRecompile_devirtualizeUnchangedJso()
throws UnableToCompleteException, IOException, InterruptedException {
// Tests that a JSO calls through interfaces are correctly devirtualized when compiling per file
// and the JSOs nor their single impl interfaces are not stale.
checkIncrementalRecompile_devirtualizeUnchangedJso(JsOutputOption.OBFUSCATED);
checkIncrementalRecompile_devirtualizeUnchangedJso(JsOutputOption.DETAILED);
}
public void testIncrementalRecompile_devirtualizeString()
throws UnableToCompleteException, IOException, InterruptedException {
// Tests that String calls through interfaces are correctly devirtualized when compiling per
// file and neither String nor CharSequence interface are stale.
checkIncrementalRecompile_devirtualizeString(JsOutputOption.OBFUSCATED);
checkIncrementalRecompile_devirtualizeString(JsOutputOption.DETAILED);
}
public void testIncrementalRecompile_devirtualizeComparable()
throws UnableToCompleteException, IOException, InterruptedException {
// Tests that Doublecalls through interfaces are correctly devirtualized when compiling per
// file and neither String nor CharSequence interface are stale.
checkIncrementalRecompile_devirtualizeComparable(JsOutputOption.OBFUSCATED);
checkIncrementalRecompile_devirtualizeComparable(JsOutputOption.DETAILED);
}
public void testIncrementalRecompile_multipleClassGenerator()
throws UnableToCompleteException, IOException, InterruptedException {
// Tests that a Generated type that is not directly referenced from the rebound GWT.create()
// call is still marked stale, regenerated, retraversed and output as JS.
checkIncrementalRecompile_multipleClassGenerator(JsOutputOption.OBFUSCATED);
checkIncrementalRecompile_multipleClassGenerator(JsOutputOption.DETAILED);
}
public void testIncrementalRecompile_singleJsoIntfDispatchChange()
throws UnableToCompleteException,
IOException, InterruptedException {
// Not testing recompile equality with Pretty/Obfuscated output since the JsIncrementalNamer's
// behavior is order dependent, and while still correct, will come out different in a recompile
// with this change versus a from scratch compile with this change.
checkIncrementalRecompile_singleJsoIntfDispatchChange(JsOutputOption.DETAILED);
}
public void testIncrementalRecompile_dualJsoIntfDispatchChange() throws UnableToCompleteException,
IOException, InterruptedException {
// Not testing recompile equality with Pretty/Obfuscated output since the JsIncrementalNamer's
// behavior is order dependent, and while still correct, will come out different in a recompile
// with this change versus a from scratch compile with this change.
checkIncrementalRecompile_dualJsoIntfDispatchChange(JsOutputOption.DETAILED);
}
public void testIncrementalRecompile_generatorInputResourceChange() throws IOException,
UnableToCompleteException, InterruptedException {
// Not testing recompile equality with Pretty/Obfuscated output since the JsIncrementalNamer's
// behavior is order dependent, and while still correct, will come out different in a recompile
// with this change versus a from scratch compile with this change.
checkIncrementalRecompile_generatorInputResourceChange(JsOutputOption.DETAILED);
}
public void testIncrementalRecompile_invalidatedGeneratorOutputRerunsGenerator()
throws UnableToCompleteException, IOException, InterruptedException {
// BarReferencesFoo Generator hasn't run yet.
assertEquals(0, BarReferencesFooGenerator.runCount);
CompilerOptions compilerOptions = new CompilerOptionsImpl();
List<MockResource> sharedResources =
Lists.newArrayList(barReferencesFooGeneratorModuleResource, generatorEntryPointResource);
JsOutputOption output = JsOutputOption.OBFUSCATED;
List<MockResource> originalResources = Lists.newArrayList(sharedResources);
originalResources.add(fooResource);
// Compile the app with original files, modify a file and do a per-file recompile.
MinimalRebuildCache relinkMinimalRebuildCache = new MinimalRebuildCache();
File relinkApplicationDir = Files.createTempDir();
compileToJs(compilerOptions, relinkApplicationDir, "com.foo.SimpleModule", originalResources,
relinkMinimalRebuildCache, emptySet, output);
// BarReferencesFoo Generator has now been run once.
assertEquals(1, BarReferencesFooGenerator.runCount);
// Recompile with no changes, which should not trigger any Generator runs.
compileToJs(compilerOptions, relinkApplicationDir, "com.foo.SimpleModule",
Lists.<MockResource>newArrayList(), relinkMinimalRebuildCache, emptySet, output);
// Since there were no changes BarReferencesFoo Generator was not run again.
assertEquals(1, BarReferencesFooGenerator.runCount);
// Recompile with a modified Foo class, which should invalidate Bar which was generated by a
// GWT.create() call in the entry point.
compileToJs(compilerOptions, relinkApplicationDir, "com.foo.SimpleModule",
Lists.<MockResource>newArrayList(fooResource), relinkMinimalRebuildCache,
stringSet("com.foo.TestEntryPoint", "com.foo.Foo", "com.foo.Bar"), output);
// BarReferencesFoo Generator was run again.
assertEquals(2, BarReferencesFooGenerator.runCount);
}
public void testIncrementalRecompile_invalidatedGeneratorOutputRerunsCascadedGenerators()
throws UnableToCompleteException, IOException, InterruptedException {
// Generators haven't run yet.
assertEquals(0, CauseStringRebindGenerator.runCount);
assertEquals(0, CauseShortRebindGenerator.runCount);
assertEquals(0, FooResourceGenerator.runCount);
CompilerOptions compilerOptions = new CompilerOptionsImpl();
List<MockResource> sharedResources = Lists.newArrayList(cascadingGeneratorModuleResource,
generatorEntryPointResource, classNameToGenerateResource);
JsOutputOption output = JsOutputOption.OBFUSCATED;
List<MockResource> originalResources = Lists.newArrayList(sharedResources);
// Compile the app with original files.
MinimalRebuildCache relinkMinimalRebuildCache = new MinimalRebuildCache();
File relinkApplicationDir = Files.createTempDir();
compileToJs(compilerOptions, relinkApplicationDir, "com.foo.SimpleModule", originalResources,
relinkMinimalRebuildCache, emptySet, output);
// Generators have now been run once.
assertEquals(1, CauseStringRebindGenerator.runCount);
assertEquals(1, CauseShortRebindGenerator.runCount);
assertEquals(1, FooResourceGenerator.runCount);
// Recompile with no changes, which should not trigger any Generator runs.
compileToJs(compilerOptions, relinkApplicationDir, "com.foo.SimpleModule",
Lists.<MockResource>newArrayList(), relinkMinimalRebuildCache, emptySet, output);
// Since there were no changes Generators were not run again.
assertEquals(1, CauseStringRebindGenerator.runCount);
assertEquals(1, CauseShortRebindGenerator.runCount);
assertEquals(1, FooResourceGenerator.runCount);
// Recompile with a modified resource, which should invalidate the output of the
// FooResourceGenerator and cascade the invalidate the Generators that triggered
// FooResourceGenerator.
compileToJs(compilerOptions, relinkApplicationDir, "com.foo.SimpleModule",
Lists.<MockResource>newArrayList(modifiedClassNameToGenerateResource),
relinkMinimalRebuildCache, stringSet("com.foo.TestEntryPoint", "com.foo.Baz$InnerBaz",
"com.foo.Bar", "com.foo.HasCustomContent", "com.foo.FooReplacementTwo"), output);
// Generators were run again.
assertEquals(2, CauseStringRebindGenerator.runCount);
assertEquals(2, CauseShortRebindGenerator.runCount);
assertEquals(2, FooResourceGenerator.runCount);
}
public void testIncrementalRecompile_carriesOverGeneratorArtifacts()
throws UnableToCompleteException,
IOException, InterruptedException {
// Foo Generator hasn't run yet.
assertEquals(0, FooResourceGenerator.runCount);
CompilerOptions compilerOptions = new CompilerOptionsImpl();
List<MockResource> sharedResources = Lists.newArrayList(resourceReadingGeneratorModuleResource,
referencesBarAndGeneratorEntryPointResource, classNameToGenerateResource,
barReferencesFooResource);
JsOutputOption output = JsOutputOption.OBFUSCATED;
List<MockResource> originalResources = Lists.newArrayList(sharedResources);
originalResources.add(fooResource);
// Compile the app with original files.
MinimalRebuildCache relinkMinimalRebuildCache = new MinimalRebuildCache();
File relinkApplicationDir = Files.createTempDir();
compileToJs(compilerOptions, relinkApplicationDir, "com.foo.SimpleModule", originalResources,
relinkMinimalRebuildCache, emptySet, output);
// Foo Generator has now been run once.
assertEquals(1, FooResourceGenerator.runCount);
// The bar.txt artifact was output.
File barFile = new File(relinkApplicationDir.getPath() + File.separator + "com.foo.SimpleModule"
+ File.separator + "bar.txt");
assertTrue(barFile.exists());
// Recompile with just 1 file change, which should not trigger any Generator runs.
compileToJs(compilerOptions, relinkApplicationDir, "com.foo.SimpleModule",
Lists.<MockResource> newArrayList(fooResource), relinkMinimalRebuildCache,
stringSet("com.foo.Foo", "com.foo.Bar"), output);
// Foo Generator was not run again.
assertEquals(1, FooResourceGenerator.runCount);
// But the bar.txt artifact was still output.
barFile = new File(relinkApplicationDir.getPath() + File.separator + "com.foo.SimpleModule"
+ File.separator + "bar.txt");
assertTrue(barFile.exists());
}
/**
* Regression test for UnifyAST assertion failure problem in incremental SDM.
*/
public void testIncrementalRecompile_unifyASTAssertionRegression()
throws UnableToCompleteException, IOException, InterruptedException {
CompilerOptions compilerOptions = new CompilerOptionsImpl();
List<MockResource> originalResources = Lists.newArrayList(helloEntryPointResource,
helloModuleResource);
JsOutputOption output = JsOutputOption.OBFUSCATED;
// Compile the app with original files.
MinimalRebuildCache relinkMinimalRebuildCache = new MinimalRebuildCache();
File relinkApplicationDir = Files.createTempDir();
compileToJs(compilerOptions, relinkApplicationDir, "com.foo.Hello",
originalResources, relinkMinimalRebuildCache, emptySet, output);
}
private void checkIncrementalRecompile_noop(JsOutputOption output) throws UnableToCompleteException,
IOException, InterruptedException {
MinimalRebuildCache relinkMinimalRebuildCache = new MinimalRebuildCache();
File relinkApplicationDir = Files.createTempDir();
String originalJs = compileToJs(relinkApplicationDir, "com.foo.SimpleModule", Lists
.newArrayList(simpleModuleResource, simpleModelEntryPointResource, simpleModelResource,
constantsModelResource),
relinkMinimalRebuildCache, emptySet, output);
// Compile again with absolutely no file changes and reusing the minimalRebuildCache.
String relinkedJs = compileToJs(relinkApplicationDir, "com.foo.SimpleModule",
Lists.<MockResource>newArrayList(), relinkMinimalRebuildCache, emptySet, output);
assertTrue(originalJs.equals(relinkedJs));
}
private void checkIncrementalRecompile_defaultMethod(JsOutputOption output)
throws UnableToCompleteException, IOException, InterruptedException {
// Tests that when a superclass has a "inherits" a default method,
MockJavaResource interfaceWithDefaultMethod =
JavaResourceBase.createMockJavaResource(
"com.foo.InterfaceWithDefaultMethod",
"package com.foo;",
"interface InterfaceWithDefaultMethod {",
" default String m() {return null; }",
"}");
MockJavaResource classImplementingInterfaceWithDefaultMethod =
JavaResourceBase.createMockJavaResource(
"com.foo.classImplementingInterfaceWithDefaultMethod",
"package com.foo;",
"public class classImplementingInterfaceWithDefaultMethod",
" implements InterfaceWithDefaultMethod {",
"}");
MockJavaResource aSubclass =
JavaResourceBase.createMockJavaResource(
"com.foo.ASubclass",
"package com.foo;",
"public class ASubclass extends classImplementingInterfaceWithDefaultMethod {",
" public String someMethod() {return super.m(); }",
"}");
MockResource moduleResource =
JavaResourceBase.createMockResource(
"com/foo/DefaultMethod.gwt.xml",
"<module>",
" <source path=''/>",
" <entry-point class='com.foo.DefaultMethodEntryPoint'/>",
"</module>");
MockJavaResource entryPointResource =
JavaResourceBase.createMockJavaResource(
"com.foo.DefaultMethodEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class DefaultMethodEntryPoint implements EntryPoint {",
" public void onModuleLoad() {",
" new ASubclass().someMethod();",
" }",
"}");
CompilerOptions compilerOptions = new CompilerOptionsImpl();
compilerOptions.setUseDetailedTypeIds(true);
compilerOptions.setSourceLevel(SourceLevel.JAVA8);
checkRecompiledModifiedApp(compilerOptions, "com.foo.DefaultMethod",
Lists.newArrayList(moduleResource, entryPointResource, aSubclass,
classImplementingInterfaceWithDefaultMethod, interfaceWithDefaultMethod),
aSubclass, aSubclass, stringSet("com.foo.ASubclass", "com.foo.DefaultMethodEntryPoint"),
output);
}
public void checkIncrementalRecompile_classLiteralNewReference(JsOutputOption output)
throws UnableToCompleteException, IOException, InterruptedException {
MockJavaResource interfaceA =
JavaResourceBase.createMockJavaResource(
"com.foo.A",
"package com.foo;",
"interface A {",
" static String b = \"\";",
"}");
MockJavaResource classBSansLiteralReference =
JavaResourceBase.createMockJavaResource(
"com.foo.B",
"package com.foo;",
"public class B {",
"}");
MockJavaResource classBWithLiteralReference =
JavaResourceBase.createMockJavaResource(
"com.foo.B",
"package com.foo;",
"public class B {",
" public B() { Class c = A.class; }",
"}");
MockJavaResource classC =
JavaResourceBase.createMockJavaResource(
"com.foo.C",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class C implements EntryPoint {",
" public void onModuleLoad() {",
" if (A.b == null) ",
" new B();",
" }",
"}");
MockResource moduleResource =
JavaResourceBase.createMockResource(
"com/foo/ClassLiteralReference.gwt.xml",
"<module>",
" <source path=''/>",
" <entry-point class='com.foo.C'/>",
"</module>");
checkRecompiledModifiedApp("com.foo.ClassLiteralReference", Lists.newArrayList(
moduleResource, interfaceA, classC),
classBSansLiteralReference, classBWithLiteralReference,
stringSet("com.foo.B", "com.foo.C"), output);
}
public void checkIncrementalRecompile_primitiveClassLiteralReference(JsOutputOption output)
throws UnableToCompleteException, IOException, InterruptedException {
MockJavaResource classA =
JavaResourceBase.createMockJavaResource(
"com.foo.A",
"package com.foo;",
"public class A {",
" public A() { ",
" Class c = void.class; ",
" c = int.class; ",
" c = boolean.class;",
" c = short.class;",
" c = byte.class;",
" c = long.class;",
" c = float.class;",
" c = double.class;",
" }",
"}");
MockJavaResource classB =
JavaResourceBase.createMockJavaResource(
"com.foo.B",
"package com.foo;",
"public class B {",
" public B() { }",
" public void m () { new A(); }",
"}");
MockJavaResource classC =
JavaResourceBase.createMockJavaResource(
"com.foo.C",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class C implements EntryPoint {",
" public void onModuleLoad() {",
" new B().m();",
" }",
"}");
MockResource moduleResource =
JavaResourceBase.createMockResource(
"com/foo/PrimitiveClassLiteralReference.gwt.xml",
"<module>",
" <source path=''/>",
" <entry-point class='com.foo.C'/>",
"</module>");
checkRecompiledModifiedApp("com.foo.PrimitiveClassLiteralReference", Lists.newArrayList(
moduleResource, classA, classB),
classC, classC,
stringSet(getEntryMethodHolderTypeName("com.foo.PrimitiveClassLiteralReference"),
"com.foo.C"), output);
}
private void checkIncrementalRecompile_dateStampChange(JsOutputOption output)
throws UnableToCompleteException, IOException, InterruptedException {
MinimalRebuildCache relinkMinimalRebuildCache = new MinimalRebuildCache();
File relinkApplicationDir = Files.createTempDir();
String originalJs = compileToJs(relinkApplicationDir, "com.foo.SimpleModule",
Lists.newArrayList(simpleModuleResource, simpleModelEntryPointResource, simpleModelResource,
constantsModelResource),
relinkMinimalRebuildCache, emptySet, output);
// Compile again with the same source but a new date stamp on SimpleModel and reusing the
// minimalRebuildCache.
String relinkedJs = compileToJs(relinkApplicationDir, "com.foo.SimpleModule",
Lists.<MockResource>newArrayList(simpleModelResource), relinkMinimalRebuildCache,
stringSet("com.foo.TestEntryPoint", "com.foo.SimpleModel"), output);
assertTrue(originalJs.equals(relinkedJs));
}
private void checkIncrementalRecompile_superClassOrder(JsOutputOption output)
throws UnableToCompleteException, IOException, InterruptedException {
// Mark ReferencedBySuperClassResource modified, so that SuperClass becomes stale. This will
// result in SuperClass's indexing being rebuilt but NOT ASubClasses's. If there is a bug in the
// index updates then the link output ordering will change.
checkRecompiledModifiedApp("com.foo.SimpleModule", Lists.newArrayList(simpleModuleResource,
superClassOrderEntryPointResource, referencedBySuperClassResource, superClassResource,
aSubClassResource), referencedBySuperClassResource, referencedBySuperClassResource,
stringSet("com.foo.SuperClass", "com.foo.ReferencedBySuperClass"), output);
}
private void checkIncrementalRecompile_superFromStaleInner(JsOutputOption output)
throws UnableToCompleteException, IOException, InterruptedException {
// Makes sure that type ids for (effectively static) super dispatches, i.e. of the form
// super.m() or X.this.m(), are computed also for classes only referenced by stale classes.
checkRecompiledModifiedApp("com.foo.SuperFromStaleInnerModule",
Lists.newArrayList(superFromStaleInnerModuleResource,
superFromStaleInnerEntryPointResource), interfaceOneResource, interfaceOneResource,
stringSet(interfaceOneResource.getTypeName(), "com.foo.SuperFromStaleInnerEntryPoint$B",
"com.foo.SuperFromStaleInnerEntryPoint$B$1"),
output);
}
private void checkIncrementalRecompile_deterministicUiBinder(JsOutputOption output)
throws UnableToCompleteException, IOException, InterruptedException {
CompilerOptions compilerOptions = new CompilerOptionsImpl();
checkRecompiledModifiedApp(compilerOptions, "com.foo.UiBinderTestModule", Lists.newArrayList(
uiBinderTestModuleResource, uiBinderTestEntryPointResource, myWidgetUiXml), myWidget,
myWidget, stringSet("com.foo.MyWidget", "com.foo.MyWidget$Binder", "com.foo.TestEntryPoint",
"com.foo.MyWidget_BinderImpl", "com.foo.MyWidget_BinderImpl$Widgets"), output);
}
private void checkIncrementalRecompile_uiBinderCssChange(JsOutputOption output)
throws UnableToCompleteException, IOException, InterruptedException {
// Switches from a white styled widget to a grey styled widget in the CSS in the style tag
// nested in the .ui.xml template file.
String binderImpl = "com.foo.MyWidget_BinderImpl";
checkRecompiledModifiedApp("com.foo.UiBinderTestModule",
Lists.newArrayList(uiBinderTestModuleResource, uiBinderTestEntryPointResource, myWidget),
myWidgetWithWhiteStyleUiXml, myWidgetWithGreyStyleUiXml,
stringSet("com.foo.MyWidget",
binderImpl, binderImpl + "_GenBundle_default_InlineClientBundleGenerator",
binderImpl + "_GenBundle_default_InlineClientBundleGenerator$1",
binderImpl + "_GenBundle_default_InlineClientBundleGenerator$styleInitializer",
binderImpl + "_TemplateImpl",
binderImpl + "$Widgets", binderImpl + "$Template"), output);
}
private void checkIncrementalRecompile_packagePrivateOverride(JsOutputOption output)
throws UnableToCompleteException, IOException, InterruptedException {
CompilerOptions compilerOptions = new CompilerOptionsImpl();
compilerOptions.setUseDetailedTypeIds(true);
checkRecompiledModifiedApp(compilerOptions, "com.foo.SimpleModule", Lists.newArrayList(
simpleModuleResource, packagePrivateDispatchEntryPointResource,
packagePrivateParentResource, referencesParentResource),
packagePrivateChildResource, packagePrivateChildResource,
stringSet("com.foo.PackagePrivateChild", "com.foo.TestEntryPoint"), output);
}
private void checkIncrementalRecompile_regularClassMadeIntoJsoClass(JsOutputOption output)
throws UnableToCompleteException, IOException, InterruptedException {
CompilerOptions compilerOptions = new CompilerOptionsImpl();
compilerOptions.setUseDetailedTypeIds(true);
checkRecompiledModifiedApp(compilerOptions, "com.foo.SimpleModule", Lists.newArrayList(
simpleModuleResource, jsoArrayTestEntryPointResource, someClassReferringToJsoOneArrays,
someClassReferringToJsoTwoArrays, jsoOne), jsoTwo_before, jsoTwo_after,
stringSet("com.foo.JsoTwo", "com.foo.SomeClassReferringToJsoTwoArrays"), output);
}
private void checkIncrementalRecompile_unstableGeneratorReferencesModifiedType(
JsOutputOption output)
throws UnableToCompleteException, IOException, InterruptedException {
// Make sure that the recompile with changes and the full compile with changes have the same
// output from the unstable generator, so that it is safe to make byte for byte output
// comparisons.
UnstableNestedAnonymousGenerator.outputVersionOrder.addAll(Lists.newArrayList(
// first compile
OutputVersion.A,
// recompile with changes
OutputVersion.B,
// full compile with changes
OutputVersion.B));
checkRecompiledModifiedApp("com.foo.SimpleModule",
Lists.newArrayList(generatorEntryPointResource, unstableGeneratorModuleResource),
fooResource, sameContentDifferentTimeFooResource, stringSet(
"com.foo.NestedAnonymousClasses$1", "com.foo.NestedAnonymousClasses",
"com.foo.NestedAnonymousClasses$ClassTwo", "com.foo.NestedAnonymousClasses$ClassOne",
"com.foo.TestEntryPoint", "com.foo.NestedAnonymousClasses$1$1", "com.foo.Foo"), output);
}
private void checkIncrementalRecompile_functionSignatureChange(JsOutputOption output)
throws UnableToCompleteException, IOException, InterruptedException {
checkRecompiledModifiedApp("com.foo.SimpleModule", Lists.newArrayList(
simpleModuleResource, simpleModelEntryPointResource, constantsModelResource),
simpleModelResource, modifiedFunctionSignatureSimpleModelResource,
stringSet("com.foo.TestEntryPoint", "com.foo.SimpleModel"), output);
}
private void checkIncrementalRecompile_compileTimeConstantChange(JsOutputOption output)
throws UnableToCompleteException, IOException, InterruptedException {
checkRecompiledModifiedApp("com.foo.SimpleModule", Lists.newArrayList(
simpleModuleResource, simpleModelEntryPointResource, simpleModelResource),
constantsModelResource, modifiedConstantsModelResource,
stringSet("com.foo.SimpleModel", "com.foo.Constants"), output);
}
private void checkIncrementalRecompile_transitivelyFoldableConstant(JsOutputOption output)
throws UnableToCompleteException, IOException, InterruptedException {
// Tests that constants that are provided by types are only referenced by reference only types
// (hence not traversed) are still available for constant propagation.
checkRecompiledModifiedApp("com.foo.TransitivelyFoldableConstantModule", Lists.newArrayList(
transitivelyFoldableConstantModuleResource, classOneResource, classTwoResource),
transitivelyFoldableConstantEntryPointResource,
transitivelyFoldableConstantEntryPointResource,
stringSet("com.foo.TransitivelyFoldableConstantEntryPoint",
getEntryMethodHolderTypeName("com.foo.TransitivelyFoldableConstantModule")),
output);
}
private void checkIncrementalRecompile_unreachableIncompatibleChange(JsOutputOption output)
throws UnableToCompleteException, IOException, InterruptedException {
checkRecompiledModifiedApp("com.foo.SimpleModule",
Lists.newArrayList(simpleModuleResource, emptyEntryPointResource), nonCompilableFooResource,
nonCompilableFooResource, stringSet(), output);
}
private void checkIncrementalRecompile_typeHierarchyChange(JsOutputOption output)
throws UnableToCompleteException, IOException, InterruptedException {
checkRecompiledModifiedApp("com.foo.SimpleModule", Lists.newArrayList(simpleModuleResource,
modifiedSuperEntryPointResource, modelAResource, modelBResource, modelDResource),
modelCResource, modifiedSuperModelCResource,
stringSet("com.foo.TestEntryPoint", "com.foo.ModelC", "com.foo.ModelD"), output);
}
private void checkIncrementalRecompile_singleJsoIntfDispatchChange(JsOutputOption output)
throws UnableToCompleteException, IOException, InterruptedException {
CompilerOptions compilerOptions = new CompilerOptionsImpl();
compilerOptions.setUseDetailedTypeIds(true);
checkRecompiledModifiedApp(compilerOptions, "com.foo.SimpleModule", Lists.newArrayList(
simpleModuleResource, modifiedJsoIntfDispatchEntryPointResource, callerResource,
fooInterfaceResource), nonJsoFooResource, jsoFooResource,
stringSet("com.foo.TestEntryPoint", "com.foo.Foo", "com.foo.Caller"), output);
}
private void checkIncrementalRecompile_devirtualizeUnchangedJso(JsOutputOption output)
throws UnableToCompleteException, IOException, InterruptedException {
CompilerOptions compilerOptions = new CompilerOptionsImpl();
compilerOptions.setUseDetailedTypeIds(true);
checkRecompiledModifiedApp(compilerOptions, "com.foo.SimpleModule",
Lists.newArrayList(jsoTestModuleResource, simpleFactory, simpleIntf, simpleJso),
jsoTestEntryPointResource, jsoTestEntryPointResource, stringSet("com.foo.TestEntryPoint",
getEntryMethodHolderTypeName("com.foo.SimpleModule")), output);
}
private void checkIncrementalRecompile_devirtualizeString(JsOutputOption output)
throws UnableToCompleteException, IOException, InterruptedException {
CompilerOptions compilerOptions = new CompilerOptionsImpl();
compilerOptions.setUseDetailedTypeIds(true);
checkRecompiledModifiedApp(compilerOptions, "com.foo.DevirtualizeStringModule",
Lists.newArrayList(devirtualizeStringModuleResource),
devirtualizeStringEntryPointResource, devirtualizeStringEntryPointResource,
stringSet("com.foo.DevirtualizeStringEntryPoint",
getEntryMethodHolderTypeName("com.foo.DevirtualizeStringModule")),
output);
}
private void checkIncrementalRecompile_devirtualizeComparable(JsOutputOption output)
throws UnableToCompleteException, IOException, InterruptedException {
final MockResource devirtualizeComparableModuleResource =
JavaResourceBase.createMockResource("com/foo/DevirtualizeComparableModule.gwt.xml",
"<module>",
"<source path=''/>",
"<entry-point class='com.foo.DevirtualizeComparableEntryPoint'/>",
"</module>");
final MockJavaResource devirtualizeComparableEntryPointResource =
JavaResourceBase.createMockJavaResource("com.foo.DevirtualizeComparableEntryPoint",
"package com.foo;",
"import com.google.gwt.core.client.EntryPoint;",
"public class DevirtualizeComparableEntryPoint implements EntryPoint {",
" @Override",
" public void onModuleLoad() {",
" Comparable c = (Double) 0.1;",
" c.compareTo(c);",
" }",
"}");
CompilerOptions compilerOptions = new CompilerOptionsImpl();
compilerOptions.setUseDetailedTypeIds(true);
checkRecompiledModifiedApp(compilerOptions, "com.foo.DevirtualizeComparableModule",
Lists.newArrayList(devirtualizeComparableModuleResource),
devirtualizeComparableEntryPointResource, devirtualizeComparableEntryPointResource,
stringSet("com.foo.DevirtualizeComparableEntryPoint",
getEntryMethodHolderTypeName("com.foo.DevirtualizeComparableModule")),
output);
}
private void checkIncrementalRecompile_multipleClassGenerator(JsOutputOption output)
throws UnableToCompleteException, IOException, InterruptedException {
CompilerOptions compilerOptions = new CompilerOptionsImpl();
compilerOptions.setUseDetailedTypeIds(true);
checkRecompiledModifiedApp(compilerOptions, "com.foo.SimpleModule",
Lists.newArrayList(multipleClassGeneratorModuleResource, generatorEntryPointResource),
bazResource, bazResource,
stringSet("com.foo.Baz", "com.foo.TestEntryPoint", "com.foo.Bar"), output);
}
private void checkIncrementalRecompile_dualJsoIntfDispatchChange(JsOutputOption output)
throws UnableToCompleteException, IOException, InterruptedException {
CompilerOptions compilerOptions = new CompilerOptionsImpl();
compilerOptions.setUseDetailedTypeIds(true);
checkRecompiledModifiedApp(compilerOptions, "com.foo.SimpleModule", Lists.newArrayList(
simpleModuleResource, modifiedJsoIntfDispatchEntryPointResource, callerResource,
fooInterfaceResource, regularFooImplemetorResource), nonJsoFooResource, jsoFooResource,
stringSet("com.foo.TestEntryPoint", "com.foo.Foo", "com.foo.Caller"), output);
}
private void checkIncrementalRecompile_generatorInputResourceChange(JsOutputOption outputOption)
throws IOException, UnableToCompleteException, InterruptedException {
CompilerOptions compilerOptions = new CompilerOptionsImpl();
compilerOptions.setUseDetailedTypeIds(true);
checkRecompiledModifiedApp(compilerOptions, "com.foo.SimpleModule", Lists.newArrayList(
resourceReadingGeneratorModuleResource, generatorEntryPointResource, fooInterfaceResource,
nonJsoFooResource), classNameToGenerateResource, modifiedClassNameToGenerateResource,
stringSet("com.foo.TestEntryPoint", "com.foo.HasCustomContent",
"com.foo.FooReplacementTwo"), outputOption);
}
private void assertCompileSucceeds(CompilerOptions options, String moduleName,
List<MockResource> applicationResources) throws Exception {
File compileWorkDir = Utility.makeTemporaryDirectory(null, moduleName);
final CompilerOptionsImpl compilerOptions = new CompilerOptionsImpl(options);
PrintWriterTreeLogger logger = new PrintWriterTreeLogger();
logger.setMaxDetail(TreeLogger.ERROR);
String oldPersistentUnitCacheValue =
System.setProperty(UnitCacheSingleton.GWT_PERSISTENTUNITCACHE, "false");
try {
File applicationDir = Files.createTempDir();
Thread.sleep(1001);
// We might be reusing the same application dir but we want to make sure that the output dir
// is clean to avoid confusion when returning the output JS.
File outputDir = new File(applicationDir.getPath() + File.separator + moduleName);
if (outputDir.exists()) {
Util.recursiveDelete(outputDir, true);
}
// Fake out the resource loader to read resources both from the normal classpath as well as
// this new application directory.
ResourceLoader resourceLoader = ResourceLoaders.fromContextClassLoader();
resourceLoader =
ResourceLoaders.forPathAndFallback(ImmutableList.of(applicationDir), resourceLoader);
// Setup options to perform a per-file compile, output to this new application directory and
// compile the given module.
compilerOptions.setGenerateJsInteropExports(true);
compilerOptions.setWarDir(applicationDir);
compilerOptions.setModuleNames(ImmutableList.of(moduleName));
// Write the Java/XML/etc resources that make up the test application.
for (MockResource applicationResource : applicationResources) {
writeResourceTo(applicationResource, applicationDir);
}
// Cause the module to be cached with a reference to the prefixed resource loader so that the
// compile process will see those resources.
ModuleDefLoader.clearModuleCache();
ModuleDefLoader.loadFromResources(logger, moduleName, resourceLoader, true);
options.addModuleName(moduleName);
options.setWarDir(new File(compileWorkDir, "war"));
options.setExtraDir(new File(compileWorkDir, "extra"));
// Run the compiler once here.
Compiler.compile(logger, options);
} finally {
Util.recursiveDelete(compileWorkDir, false);
if (oldPersistentUnitCacheValue == null) {
System.clearProperty(UnitCacheSingleton.GWT_PERSISTENTUNITCACHE);
} else {
System.setProperty(UnitCacheSingleton.GWT_PERSISTENTUNITCACHE, oldPersistentUnitCacheValue);
}
}
}
private void assertDeterministicBuild(String topLevelModule, int optimizationLevel)
throws UnableToCompleteException, IOException {
final CompilerOptionsImpl options = new CompilerOptionsImpl();
options.setOptimizationLevel(optimizationLevel);
File firstCompileWorkDir = Utility.makeTemporaryDirectory(null, "hellowork");
File secondCompileWorkDir = Utility.makeTemporaryDirectory(null, "hellowork");
String oldPersistentUnitCacheValue =
System.setProperty(UnitCacheSingleton.GWT_PERSISTENTUNITCACHE, "false");
try {
options.addModuleName(topLevelModule);
options.setWarDir(new File(firstCompileWorkDir, "war"));
options.setExtraDir(new File(firstCompileWorkDir, "extra"));
TreeLogger logger = TreeLogger.NULL;
// Run the compiler once here.
Compiler.compile(logger, options);
Set<String> firstTimeOutput =
Sets.newHashSet(new File(options.getWarDir() + "/hello").list());
options.setWarDir(new File(secondCompileWorkDir, "war"));
options.setExtraDir(new File(secondCompileWorkDir, "extra"));
// Run the compiler for a second time here.
Compiler.compile(logger, options);
Set<String> secondTimeOutput =
Sets.newHashSet(new File(options.getWarDir() + "/hello").list());
// It is only necessary to check that the filenames in the output directory are the same
// because the names of the files for the JavaScript outputs are the hash of its contents.
assertEquals("First and second compile produced different outputs", firstTimeOutput,
secondTimeOutput);
} finally {
if (oldPersistentUnitCacheValue == null) {
System.clearProperty(UnitCacheSingleton.GWT_PERSISTENTUNITCACHE);
} else {
System.setProperty(UnitCacheSingleton.GWT_PERSISTENTUNITCACHE, oldPersistentUnitCacheValue);
}
Util.recursiveDelete(firstCompileWorkDir, false);
Util.recursiveDelete(secondCompileWorkDir, false);
}
}
/**
* Compiles an initial application with version 1 of file Foo, then recompiles using version 2 of
* file Foo. Lastly it performs a final from scratch compile using version 2 of file Foo and
* verifies that the recompile and the full compile (both of which used version 2 of file Foo)
* come out the same.
*/
private void checkRecompiledModifiedApp(
String moduleName,
List<MockResource> sharedResources,
MockResource originalResource,
MockResource modifiedResource,
Set<String> expectedStaleTypeNamesOnModify,
JsOutputOption output)
throws IOException, UnableToCompleteException, InterruptedException {
checkRecompiledModifiedApp(new CompilerOptionsImpl(), moduleName, sharedResources,
originalResource, modifiedResource, expectedStaleTypeNamesOnModify, output);
}
/**
* Compiles an initial application with version 1 of file Foo, then recompiles using version 2 of
* file Foo. Lastly it performs a final from scratch compile using version 2 of file Foo and
* verifies that the recompile and the full compile (both of which used version 2 of file Foo)
* come out the same.
*/
private void checkRecompiledModifiedApp(
CompilerOptions compilerOptions,
String moduleName,
List<MockResource> sharedResources,
MockResource originalResource,
MockResource modifiedResource,
Set<String> expectedStaleTypeNamesOnModify,
JsOutputOption output)
throws IOException, UnableToCompleteException, InterruptedException {
List<MockResource> originalResources = Lists.newArrayList(sharedResources);
originalResources.add(originalResource);
List<MockResource> modifiedResources = Lists.newArrayList(sharedResources);
modifiedResources.add(modifiedResource);
// Compile the app with original files, modify a file and do a per-file recompile.
MinimalRebuildCache relinkMinimalRebuildCache = new MinimalRebuildCache();
File relinkApplicationDir = Files.createTempDir();
String originalAppFromScratchJs = compileToJs(compilerOptions, relinkApplicationDir, moduleName,
originalResources, relinkMinimalRebuildCache, emptySet, output);
String modifiedAppRelinkedJs = compileToJs(compilerOptions, relinkApplicationDir, moduleName,
Lists.<MockResource> newArrayList(modifiedResource), relinkMinimalRebuildCache,
expectedStaleTypeNamesOnModify, output);
// Compile the app from scratch with the modified file.
MinimalRebuildCache fromScratchMinimalRebuildCache = new MinimalRebuildCache();
File fromScratchApplicationDir = Files.createTempDir();
String modifiedAppFromScratchJs = compileToJs(compilerOptions, fromScratchApplicationDir,
moduleName, modifiedResources, fromScratchMinimalRebuildCache, emptySet, output);
// If a resource contents were changed between the original compile and the relink compile
// check that the output JS has also changed. If all resources have the same content (their
// timestamps might have changed) then outputs should be the same.
boolean wasNotModified = modifiedResource == originalResource;
assertTrue("Resource " + modifiedResource.getPath() + " was " +
(wasNotModified ? "NOT " : "") + "modified but the output was " +
(wasNotModified ? "" : "NOT ") + "different.",
wasNotModified == originalAppFromScratchJs.equals(modifiedAppRelinkedJs));
// If per-file compiles properly avoids global-knowledge dependencies and correctly invalidates
// referencing types when a type changes, then the relinked and from scratch JS will be
// identical.
assertTrue(modifiedAppRelinkedJs.equals(modifiedAppFromScratchJs));
}
private String compileToJs(File applicationDir, String moduleName,
List<MockResource> applicationResources, MinimalRebuildCache minimalRebuildCache,
Set<String> expectedStaleTypeNames, JsOutputOption output) throws IOException,
UnableToCompleteException, InterruptedException {
return compileToJs(new CompilerOptionsImpl(), applicationDir, moduleName, applicationResources,
minimalRebuildCache, expectedStaleTypeNames, output);
}
private String compileToJs(CompilerOptions compilerOptions, File applicationDir,
String moduleName, List<MockResource> applicationResources,
MinimalRebuildCache minimalRebuildCache, Set<String> expectedProcessedStaleTypeNames,
JsOutputOption output) throws IOException, UnableToCompleteException, InterruptedException {
PrintWriterTreeLogger logger = new PrintWriterTreeLogger();
logger.setMaxDetail(TreeLogger.ERROR);
return compileToJs(logger, compilerOptions, applicationDir, moduleName, applicationResources,
minimalRebuildCache, expectedProcessedStaleTypeNames, output);
}
private String compileToJs(TreeLogger logger, CompilerOptions compilerOptions, File applicationDir,
String moduleName, List<MockResource> applicationResources,
MinimalRebuildCache minimalRebuildCache, Set<String> expectedProcessedStaleTypeNames,
JsOutputOption output) throws IOException, UnableToCompleteException, InterruptedException {
// Make sure we're using a MemoryUnitCache.
System.setProperty(UnitCacheSingleton.GWT_PERSISTENTUNITCACHE, "false");
// Wait 1 second so that any new file modification times are actually different.
Thread.sleep(1001);
// We might be reusing the same application dir but we want to make sure that the output dir is
// clean to avoid confusion when returning the output JS.
File outputDir = new File(applicationDir.getPath() + File.separator + moduleName);
if (outputDir.exists()) {
Util.recursiveDelete(outputDir, true);
}
// Fake out the resource loader to read resources both from the normal classpath as well as this
// new application directory.
ResourceLoader resourceLoader = ResourceLoaders.fromContextClassLoader();
resourceLoader =
ResourceLoaders.forPathAndFallback(ImmutableList.of(applicationDir), resourceLoader);
// Setup options to perform a per-file compile, output to this new application directory and
// compile the given module.
compilerOptions.setIncrementalCompileEnabled(true);
compilerOptions.setWarDir(applicationDir);
compilerOptions.setModuleNames(ImmutableList.of(moduleName));
compilerOptions.setOutput(output);
// Write the Java/XML/etc resources that make up the test application.
for (MockResource applicationResource : applicationResources) {
writeResourceTo(applicationResource, applicationDir);
}
// Cause the module to be cached with a reference to the prefixed resource loader so that the
// compile process will see those resources.
ModuleDefLoader.clearModuleCache();
ModuleDef moduleDef = ModuleDefLoader.loadFromResources(logger, moduleName, resourceLoader, true);
// Run the compile.
Compiler.compile(logger, compilerOptions, minimalRebuildCache, moduleDef);
// Find, read and return the created JS.
File outputJsFile = null;
outputDir = new File(applicationDir.getPath() + File.separator + moduleName);
if (outputDir.exists()) {
for (File outputFile : outputDir.listFiles()) {
if (outputFile.getPath().endsWith(".cache.js")) {
outputJsFile = outputFile;
break;
}
}
}
if (outputJsFile == null) {
throw new UnableToCompleteException();
}
if (expectedProcessedStaleTypeNames != null) {
assertEquals(expectedProcessedStaleTypeNames, getStaleTypeNames(minimalRebuildCache));
}
return Files.toString(outputJsFile, Charsets.UTF_8);
}
private Set<String> getStaleTypeNames(MinimalRebuildCache relinkMinimalRebuildCache) {
Set<String> staleTypeNames =
new HashSet<>(relinkMinimalRebuildCache.getProcessedStaleTypeNames());
// List of JRE types that provide JsInterop entry points and jre native JsTypes. These are
// always traversed fully and polute the tests, so they will be removed from stale type
// comparisons.
staleTypeNames.removeAll(Arrays.asList(
"java.lang.Boolean",
"java.lang.CharSequence",
"java.lang.Comparable",
"java.lang.Double",
"java.lang.HasCharSequenceTypeMarker",
"java.lang.HasComparableTypeMarker",
"java.lang.Integer$NativeNumber",
"java.lang.Number",
"java.lang.Number$JavaLangNumber",
"java.lang.String",
"java.lang.String$NativeFunction",
"java.lang.String$NativeString",
"java.lang.Throwable",
"java.lang.Throwable$NativeError",
"java.lang.Throwable$NativeTypeError",
"javaemul.internal.NativeRegExp",
"javaemul.internal.NativeRegExp$Match"));
return staleTypeNames;
}
private String getEntryMethodHolderTypeName(String typeName) {
return "com.google.gwt.lang." +
EntryMethodHolderGenerator.getEntryMethodHolderTypeName(typeName);
}
private Set<String> stringSet(String... strings) {
return Sets.newHashSet(strings);
}
private void writeResourceTo(MockResource mockResource, File applicationDir) throws IOException {
File resourceFile =
new File(applicationDir.getAbsolutePath() + File.separator + mockResource.getPath());
resourceFile.getParentFile().mkdirs();
Files.write(mockResource.getContent(), resourceFile, Charsets.UTF_8);
}
}