Package com.google.gwt.dev.jjs

Source Code of com.google.gwt.dev.jjs.LibraryJavaToJavaScriptCompilerTest$BrowserShimGenerator

/*
* Copyright 2014 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.dev.jjs;

import com.google.gwt.core.ext.BadPropertyValueException;
import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.Generator.RunsLocal;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.linker.ArtifactSet;
import com.google.gwt.dev.CompilerContext;
import com.google.gwt.dev.CompilerOptionsImpl;
import com.google.gwt.dev.MinimalRebuildCache;
import com.google.gwt.dev.PrecompileTaskOptions;
import com.google.gwt.dev.cfg.BindingProperty;
import com.google.gwt.dev.cfg.Condition;
import com.google.gwt.dev.cfg.ConditionWhenPropertyIs;
import com.google.gwt.dev.cfg.ConditionWhenTypeIs;
import com.google.gwt.dev.cfg.ConfigurationProperty;
import com.google.gwt.dev.cfg.DeferredBindingQuery;
import com.google.gwt.dev.cfg.LibraryGroup;
import com.google.gwt.dev.cfg.LibraryGroupTest;
import com.google.gwt.dev.cfg.MockLibraryWriter;
import com.google.gwt.dev.cfg.MockModuleDef;
import com.google.gwt.dev.cfg.Properties;
import com.google.gwt.dev.cfg.PropertyProvider;
import com.google.gwt.dev.cfg.RuleFail;
import com.google.gwt.dev.cfg.RuleGenerateWith;
import com.google.gwt.dev.cfg.RuleReplaceWith;
import com.google.gwt.dev.cfg.RuleReplaceWithFallback;
import com.google.gwt.dev.cfg.Rules;
import com.google.gwt.dev.cfg.RuntimeRebindRuleGenerator;
import com.google.gwt.dev.javac.CompilationState;
import com.google.gwt.dev.javac.CompilationStateBuilder;
import com.google.gwt.dev.javac.StandardGeneratorContext;
import com.google.gwt.dev.jdt.RebindPermutationOracle;
import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JConstructor;
import com.google.gwt.dev.jjs.ast.JDeclaredType;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JType;
import com.google.gwt.dev.resource.Resource;
import com.google.gwt.thirdparty.guava.common.collect.Lists;
import com.google.gwt.thirdparty.guava.common.collect.Maps;
import com.google.gwt.thirdparty.guava.common.collect.Sets;
import com.google.gwt.thirdparty.guava.common.util.concurrent.AtomicLongMap;

import junit.framework.TestCase;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Map;
import java.util.Set;

/**
* Tests for LibraryJavaToJavaScriptCompiler.
*/
public class LibraryJavaToJavaScriptCompilerTest extends TestCase {

  /**
   * Test Generator that wants to create a FooShim%user.agent% type for every processed FooShim
   * type.
   */
  @RunsLocal(requiresProperties = {"user.agent"})
  public static class BrowserShimGenerator extends Generator {

    @Override
    public String generate(TreeLogger logger, GeneratorContext generatorContext,
        String typeShortName) throws UnableToCompleteException {
      try {
        String userAgentValue = generatorContext.getPropertyOracle()
            .getSelectionProperty(logger, "user.agent").getCurrentValue();
        PrintWriter pw =
            generatorContext.tryCreate(logger, "com.google.gwt", userAgentValue + typeShortName);
        if (pw != null) {
          generatorContext.commit(logger, pw);
        }
        return typeShortName + userAgentValue;
      } catch (BadPropertyValueException e) {
        throw new UnableToCompleteException();
      }
    }
  }

  /**
   * Test Generator that wants to create a FooShim%locale% type for every processed FooShim
   * type.
   */
  @RunsLocal(requiresProperties = {"locale"})
  public static class LocaleMessageGenerator extends Generator {

    @Override
    public String generate(TreeLogger logger, GeneratorContext generatorContext,
        String typeShortName) throws UnableToCompleteException {
      try {
        String localeValue = generatorContext.getPropertyOracle()
            .getSelectionProperty(logger, "locale").getCurrentValue();
        PrintWriter pw =
            generatorContext.tryCreate(logger, "com.google.gwt", localeValue + typeShortName);
        if (pw != null) {
          generatorContext.commit(logger, pw);
        }
        return typeShortName + localeValue;
      } catch (BadPropertyValueException e) {
        throw new UnableToCompleteException();
      }
    }
  }

  private static class ConditionWhenTypeEndsWith extends Condition {

    private final String suffix;

    public ConditionWhenTypeEndsWith(String suffix) {
      this.suffix = suffix;
    }

    @Override
    public String toSource() {
      return String.format("requestTypeName.endsWith(\"%s\")", suffix);
    }

    @Override
    public String toString() {
      return "<when-type-ends-with class='" + suffix + "'/>";
    }

    @Override
    protected boolean doEval(TreeLogger logger, DeferredBindingQuery query) {
      return query.getTestType().endsWith(suffix);
    }

    @Override
    protected String getEvalAfterMessage(String testType, boolean result) {
      if (result) {
        return "Yes, the requested type ended in " + suffix;
      } else {
        return "Suffix didn't match";
      }
    }

    @Override
    protected String getEvalBeforeMessage(String testType) {
      return toString();
    }
  }

  private static class MockGeneratorContext extends StandardGeneratorContext {

    private boolean dirty = false;
    private boolean globalCompile;
    private Map<String, StringWriter> stringWriterByTypeSourceName = Maps.newHashMap();

    public MockGeneratorContext(CompilerContext compilerContext, CompilationState compilationState,
        ArtifactSet allGeneratedArtifacts, boolean isProdMode, boolean globalCompile) {
      super(compilerContext, compilationState, allGeneratedArtifacts, isProdMode);
      this.globalCompile = globalCompile;
    }

    @Override
    public ArtifactSet finish(TreeLogger logger) throws UnableToCompleteException {
      dirty = false;
      // Don't actually compile generated source code;
      return new ArtifactSet();
    }

    @Override
    public boolean isDirty() {
      return dirty;
    }

    @Override
    public boolean isGlobalCompile() {
      return globalCompile;
    }

    @Override
    public boolean isProdMode() {
      return true;
    }

    @Override
    public void reset() {
      dirty = false;
    }

    @Override
    public PrintWriter tryCreate(TreeLogger logger, String packageName, String typeShortName) {
      if (!stringWriterByTypeSourceName.containsKey(packageName + "." + typeShortName)) {
        StringWriter stringWriter = new StringWriter();
        stringWriterByTypeSourceName.put(packageName + "." + typeShortName, stringWriter);
        dirty = true;
        return new PrintWriter(stringWriter);
      }
      return null;
    }
  }

  private class MockLibraryJavaToJavaScriptCompiler extends LibraryJavaToJavaScriptCompiler {

    private class MockLibraryPrecompiler extends LibraryPrecompiler {

      private Set<String> processedReboundTypeSourceNames = Sets.newHashSet();
      private Set<JDeclaredType> reboundTypes = Sets.<JDeclaredType>newHashSet(
          createInstantiableClassType("com.google.ErrorMessages"),
          createInstantiableClassType("com.google.EventShim"));
      private AtomicLongMap<String> runCountByGeneratorName = AtomicLongMap.create();

      public MockLibraryPrecompiler(RebindPermutationOracle rpo, String[] entryPointTypeNames) {
        super(rpo, entryPointTypeNames);
      }

      /**
       * Overridden to avoid the complexity of mocking out a LibraryGroupUnitCache.
       */
      @Override
      protected JDeclaredType ensureFullTypeLoaded(JDeclaredType type) {
        return type;
      }

      /**
       * Overridden to avoid the need to mock out DistillerRebindPermutationOracle as well as to
       * dynamically expand the reboundTypes list to cause repeated generator runs.
       */
      @Override
      protected Set<JDeclaredType> gatherReboundTypes(RebindPermutationOracle rpo) {
        return reboundTypes;
      }

      @Override
      protected StandardGeneratorContext getGeneratorContext() {
        return mockGeneratorContext;
      }

      @Override
      protected void runGenerator(RuleGenerateWith generatorRule,
          Set<String> reboundTypeSourceNames) throws UnableToCompleteException {
        processedReboundTypeSourceNames.addAll(reboundTypeSourceNames);
        runCountByGeneratorName.incrementAndGet(generatorRule.getName());
        super.runGenerator(generatorRule, reboundTypeSourceNames);
      }
    }

    private StandardGeneratorContext mockGeneratorContext;

    public MockLibraryJavaToJavaScriptCompiler(TreeLogger logger, CompilerContext compilerContext,
        StandardGeneratorContext generatorContext) {
      super(logger, compilerContext);
      this.mockGeneratorContext = generatorContext;
    }

    private MockLibraryPrecompiler createPrecompiler() {
      return new MockLibraryPrecompiler(null, null);
    }
  }

  private static JClassType createInstantiableClassType(String typeBinaryName) {
    JClassType instantiableType = new JClassType(SourceOrigin.UNKNOWN, typeBinaryName, false, true);
    JConstructor defaultConstructor = new JConstructor(SourceOrigin.UNKNOWN, instantiableType);
    defaultConstructor.setOriginalTypes(instantiableType, Lists.<JType>newArrayList());
    instantiableType.addMethod(defaultConstructor);
    return instantiableType;
  }

  private MockLibraryJavaToJavaScriptCompiler compiler;
  private CompilerContext compilerContext;
  private MockGeneratorContext generatorContext;
  private MockLibraryJavaToJavaScriptCompiler.MockLibraryPrecompiler precompiler;

  public void testBuildFallbackRuntimeRebindRules() throws UnableToCompleteException {
    // Sets up environment.
    Map<String, String> runtimeRebindRuleSourcesByShortName =
        RuntimeRebindRuleGenerator.RUNTIME_REBIND_RULE_SOURCES_BY_SHORT_NAME;
    Set<JDeclaredType> reboundTypes =
        Sets.<JDeclaredType>newHashSet(createInstantiableClassType("CanvasElement"));

    // Runs fallback rebind rule creation for rebound types.
    precompiler.buildFallbackRuntimeRebindRules(reboundTypes);

    // Expects a worst case rebind rule was created that will at least attempt to create a
    // CanvasElement when a CanvasElement is requested.
    String runtimeRebindRule0 = runtimeRebindRuleSourcesByShortName.get("RuntimeRebindRule0");
    assertTrue(runtimeRebindRule0.contains("@CanvasElement::new()()"));
    assertTrue(runtimeRebindRule0.contains("requestTypeClass == @CanvasElement::class"));
  }

  public void testBuildLocalRuntimeRebindRules() throws UnableToCompleteException {
    // Sets up environment.
    Set<String> allRootTypes = Sets.newHashSet();
    compiler.jprogram = new JProgram(new MinimalRebuildCache());
    Map<String, String> runtimeRebindRuleSourcesByShortName =
        RuntimeRebindRuleGenerator.RUNTIME_REBIND_RULE_SOURCES_BY_SHORT_NAME;
    Rules rules = new Rules();
    RuleFail ruleFail = new RuleFail();
    ruleFail.getRootCondition().getConditions().add(new ConditionWhenPropertyIs("foo", "bar"));
    rules.prepend(ruleFail);
    rules.prepend(new RuleGenerateWith(Generator.class));
    RuleReplaceWith ruleReplaceCanvas = new RuleReplaceWith("WebkitCanvasElement");
    ruleReplaceCanvas.getRootCondition()
        .getConditions().add(new ConditionWhenTypeIs("CanvasElement"));
    rules.prepend(ruleReplaceCanvas);
    rules.prepend(new RuleReplaceWithFallback("CanvasElement"));

    // Creates rebind rule classes for the non-generator rules in the provided list.
    precompiler.buildSimpleRuntimeRebindRules(rules);

    // Only 3 rebind rules were created because the generator rule was skipped.
    assertEquals(3, runtimeRebindRuleSourcesByShortName.size());

    // Expects to see the created fallback rule first.
    String runtimeRebindRule0 = runtimeRebindRuleSourcesByShortName.get("RuntimeRebindRule0");
    assertTrue(runtimeRebindRule0.contains("@CanvasElement::new()()"));
    assertTrue(runtimeRebindRule0.contains("requestTypeClass == @CanvasElement::class"));

    // Expects to see the created replace with rule second.
    String runtimeRebindRule1 = runtimeRebindRuleSourcesByShortName.get("RuntimeRebindRule1");
    assertTrue(runtimeRebindRule1.contains("@WebkitCanvasElement::new()()"));
    assertTrue(runtimeRebindRule1.contains("requestTypeClass == @CanvasElement::class"));

    // Expects to see the created fail rule third.
    String runtimeRebindRule2 = runtimeRebindRuleSourcesByShortName.get("RuntimeRebindRule2");
    assertTrue(runtimeRebindRule2.contains("Deferred binding request failed for type"));
    assertTrue(runtimeRebindRule2.contains(
        "RuntimePropertyRegistry::getPropertyValue(*)(\"foo\") == \"bar\""));

    // Now that runtime rebind rules have been generated, create a registrator for them.
    precompiler.buildRuntimeRebindRegistrator(allRootTypes);

    // JProgram was informed of the newly created PropertyProviderRegistrator type and its name
    // reflects the name of the module currently being processed.
    assertEquals("com.google.gwt.lang.mock_RuntimeRebindRegistrator",
        compiler.jprogram.getRuntimeRebindRegistratorTypeSourceName());
    // The allRootTypes list was augmented to know about this newly created type.
    assertTrue(
        allRootTypes.contains(compiler.jprogram.getRuntimeRebindRegistratorTypeSourceName()));

    String registratorSource = generatorContext.stringWriterByTypeSourceName.get(
        compiler.jprogram.getRuntimeRebindRegistratorTypeSourceName()).toString();
    // The generated registrator contains all of the RuntimeRebindRule class instantiation,
    // and registrations.
    assertTrue(registratorSource.contains(
        "RuntimeRebinder.registerRuntimeRebindRule(new RuntimeRebindRule0());"));
    assertTrue(registratorSource.contains(
        "RuntimeRebinder.registerRuntimeRebindRule(new RuntimeRebindRule1());"));
    assertTrue(registratorSource.contains(
        "RuntimeRebinder.registerRuntimeRebindRule(new RuntimeRebindRule2());"));
  }

  public void testBuildPropertyProviderRegistrator() throws UnableToCompleteException {
    // Sets up environment.
    Set<String> allRootTypes = Sets.newHashSet();
    Properties properties = new Properties();
    BindingProperty userAgentProperty = properties.createBinding("user.agent");
    userAgentProperty.setProvider(new PropertyProvider("return navigator.userAgent;"));
    userAgentProperty.addTargetLibraryDefinedValue(userAgentProperty.getRootCondition(), "mozilla");
    userAgentProperty.addTargetLibraryDefinedValue(userAgentProperty.getRootCondition(), "webkit");
    BindingProperty flavorProperty = properties.createBinding("flavor");
    flavorProperty.setProvider(new PropertyProvider("return window.properties.flavor;"));
    flavorProperty.addTargetLibraryDefinedValue(flavorProperty.getRootCondition(), "Vanilla");
    flavorProperty.addTargetLibraryDefinedValue(flavorProperty.getRootCondition(), "Chocolate");
    ConfigurationProperty emulateStackProperty =
        properties.createConfiguration("emulateStack", false);
    emulateStackProperty.setValue("TRUE");
    compiler.jprogram = new JProgram(new MinimalRebuildCache());

    // Builds property provider classes and a property provider registrator to register them.
    precompiler.buildPropertyProviderRegistrator(allRootTypes,
        Sets.newTreeSet(Lists.newArrayList(userAgentProperty, flavorProperty)),
        Sets.newTreeSet(Lists.newArrayList(emulateStackProperty)));

    // JProgram was informed of the newly created PropertyProviderRegistrator type and its source
    // name reflects the name of the module currently being processed.
    assertEquals("com.google.gwt.lang.mock_PropertyProviderRegistrator",
        compiler.jprogram.getPropertyProviderRegistratorTypeSourceName());
    // The allRootTypes list was augmented to know about this newly created type.
    assertTrue(
        allRootTypes.contains(compiler.jprogram.getPropertyProviderRegistratorTypeSourceName()));

    String registratorSource = generatorContext.stringWriterByTypeSourceName.get(
        compiler.jprogram.getPropertyProviderRegistratorTypeSourceName()).toString();
    // The generated registrator contains PropertyValueProvider class definitions, instantiation,
    // and registration for each binding property.
    assertTrue(registratorSource.contains("class PropertyValueProvider0"));
    assertTrue(registratorSource.contains("\"flavor\""));
    assertTrue(registratorSource.contains("/*-return window.properties.flavor;-*/"));
    assertTrue(registratorSource.contains(
        "registerPropertyValueProvider(" + "new PropertyValueProvider0())"));
    assertTrue(registratorSource.contains("class PropertyValueProvider1"));
    assertTrue(registratorSource.contains("\"user.agent\""));
    assertTrue(registratorSource.contains("/*-return navigator.userAgent;-*/;"));
    assertTrue(registratorSource.contains(
        "registerPropertyValueProvider(" + "new PropertyValueProvider1())"));
  }

  public void testRunGeneratorsToFixedPoint() throws UnableToCompleteException {
    // Sets up environment.
    Map<String, String> runtimeRebindRuleSourcesByShortName =
        RuntimeRebindRuleGenerator.RUNTIME_REBIND_RULE_SOURCES_BY_SHORT_NAME;
    MockLibraryWriter libraryWriter = new MockLibraryWriter();
    // A library group with a varied
    // user.agent/locale/BrowserShimGenerator/LocaleMessageGenerator configuration of properties
    // and generators.
    MockModuleDef module = new MockModuleDef();
    BindingProperty userAgentProperty = module.getProperties().createBinding("user.agent");
    userAgentProperty.addDefinedValue(userAgentProperty.getRootCondition(), "mozilla");
    userAgentProperty.addDefinedValue(userAgentProperty.getRootCondition(), "webkit");
    userAgentProperty.addDefinedValue(userAgentProperty.getRootCondition(), "ie");
    userAgentProperty.addDefinedValue(userAgentProperty.getRootCondition(), "webkit_phone");
    userAgentProperty.addDefinedValue(userAgentProperty.getRootCondition(), "webkit_tablet");
    BindingProperty flavorProperty = module.getProperties().createBinding("locale");
    flavorProperty.addDefinedValue(flavorProperty.getRootCondition(), "en");
    flavorProperty.addDefinedValue(flavorProperty.getRootCondition(), "fr");
    flavorProperty.addDefinedValue(flavorProperty.getRootCondition(), "ru");
    RuleGenerateWith browserShimGenerateRule = new RuleGenerateWith(BrowserShimGenerator.class);
    browserShimGenerateRule.getRootCondition()
        .getConditions().add(new ConditionWhenTypeEndsWith("Shim"));
    module.addRule(browserShimGenerateRule);
    RuleGenerateWith localeMessageGenerateRule = new RuleGenerateWith(LocaleMessageGenerator.class);
    localeMessageGenerateRule.getRootCondition()
        .getConditions().add(new ConditionWhenTypeEndsWith("Messages"));
    module.addRule(localeMessageGenerateRule);
    LibraryGroup libraryGroup = LibraryGroupTest.buildVariedPropertyGeneratorLibraryGroup(
        Sets.newHashSet("com.google.ChromeMessages"),
        Sets.newHashSet("com.google.WindowShim"));
    PrecompileTaskOptions options = new CompilerOptionsImpl();
    options.setFinalProperties(module.getProperties());
    compilerContext = new CompilerContext.Builder().libraryGroup(libraryGroup)
        .libraryWriter(libraryWriter).module(module).options(options).build();
    finishSetUpWithCompilerContext();

    // Analyzes properties and generators in the library group and watches output in the generator
    // context to figure out which generators to run and how many times.
    precompiler.runGeneratorsToFixedPoint(null);

    // Shows that rebinds processed by generators were not just the ones explicitly rebound in this
    // module but also ones previously processed in dependency libraries but reprocessed now because
    // of new property value changes.
    assertEquals(Sets.newHashSet("com.google.EventShim", // Explicitly rebound at top level
        "com.google.WindowShim", // Old lib rebind, reprocessed because of new property values.
        "com.google.ChromeMessages", // Old lib rebind, reprocessed because of new property values.
        "com.google.ErrorMessages" // Explicitly rebound at top level
    ), precompiler.processedReboundTypeSourceNames);
    // Rebinds for 3 locales * 2 locale rebound files + 5 user agents * 2 user agent rebound files.
    assertEquals(16, runtimeRebindRuleSourcesByShortName.size());
  }

  protected void finishSetUpWithCompilerContext() throws UnableToCompleteException {
    generatorContext = new MockGeneratorContext(compilerContext, CompilationStateBuilder.buildFrom(
        TreeLogger.NULL, compilerContext, Sets.<Resource>newHashSet()), null, true, false);
    compiler =
        new MockLibraryJavaToJavaScriptCompiler(TreeLogger.NULL, compilerContext, generatorContext);
    precompiler = compiler.createPrecompiler();
  }

  @Override
  protected void setUp() throws Exception {
    super.setUp();

    RuntimeRebindRuleGenerator.RUNTIME_REBIND_RULE_SOURCES_BY_SHORT_NAME.clear();
    RuntimeRebindRuleGenerator.runtimeRebindRuleCount = 0;
    compilerContext = new CompilerContext.Builder().module(new MockModuleDef()).build();
    finishSetUpWithCompilerContext();
  }
}
TOP

Related Classes of com.google.gwt.dev.jjs.LibraryJavaToJavaScriptCompilerTest$BrowserShimGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.