Package com.google.caja.plugin

Source Code of com.google.caja.plugin.PipelineCacheTest

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

package com.google.caja.plugin;

import com.google.caja.lang.css.CssSchema;
import com.google.caja.lang.html.HtmlSchema;
import com.google.caja.lexer.InputSource;
import com.google.caja.parser.ParseTreeNode;
import com.google.caja.parser.js.CajoledModule;
import com.google.caja.parser.js.Statement;
import com.google.caja.parser.quasiliteral.ModuleManager;
import com.google.caja.parser.quasiliteral.RewriterMessageType;
import com.google.caja.plugin.stages.JobCache;
import com.google.caja.plugin.stages.JobCache.Key;
import com.google.caja.plugin.stages.JobCache.Keys;
import com.google.caja.plugin.stages.PipelineStageTestCase;
import com.google.caja.plugin.stages.PipelineStoreStage;
import com.google.caja.reporting.EchoingMessageQueue;
import com.google.caja.reporting.MessageLevel;
import com.google.caja.reporting.TestBuildInfo;
import com.google.caja.util.ContentType;
import com.google.caja.util.Join;
import com.google.caja.util.Lists;
import com.google.caja.util.Maps;
import com.google.caja.util.Pipeline;
import com.google.caja.util.Sets;

import java.net.URI;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;

public class PipelineCacheTest extends PipelineStageTestCase {
  private TestJobCache cache;

  static final class TestKey implements JobCache.Key {
    final ContentType type;
    final String content;

    TestKey(ContentType type, String content) {
      this.type = type;
      this.content = content;
    }

    public Keys asSingleton() {
      return new TestKeys(Collections.singleton(this));
    }

    @Override
    public boolean equals(Object o) {
      if (!(o instanceof TestKey)) { return false; }
      TestKey that = (TestKey) o;
      return this.type == that.type && this.content.equals(that.content);
    }

    @Override public int hashCode() { return content.hashCode(); }

    @Override public String toString() {
      return "(Key " + type + " " + (content.hashCode() & 0xffffffffL) + " : "
          + content.replace("\n", "\\n") + ")";
    }
  }

  static final class TestKeys implements JobCache.Keys {
    final Set<TestKey> keys;

    TestKeys(Set<TestKey> keys) { this.keys = keys; }

    public Keys union(Keys other) {
      if (!other.iterator().hasNext()) { return this; }
      Set<TestKey> all = Sets.newHashSet();
      all.addAll(keys);
      all.addAll(((TestKeys) other).keys);
      return new TestKeys(all);
    }

    public Iterator<JobCache.Key> iterator() {
      final Iterator<TestKey> it = keys.iterator();
      return new Iterator<JobCache.Key>() {
        public boolean hasNext() { return it.hasNext(); }
        public Key next() { return it.next(); }
        public void remove() { throw new UnsupportedOperationException(); }
      };
    }

    @Override public String toString() {
      return keys.toString();
    }

    @Override
    public int hashCode() { return keys.hashCode(); }

    @Override
    public boolean equals(Object o) {
      return o instanceof TestKeys && keys.equals(((TestKeys) o).keys);
    }
  }

  static final class TestJobCache extends JobCache {
    final Map<TestKey, List<Job>> jobMap = Maps.newLinkedHashMap();
    int nServedFromCache = 0;

    @Override public List<Job> fetch(Key k) {
      List<Job> cached = jobMap.get(k);
      if (cached == null) { return null; }
      nServedFromCache += cached.size();
      System.err.println("FETCHING " + k);
      // HACK DEBUG
      for (Job job : cached) {
        System.err.println("    " + render(job.getRoot()).replace("\n", "\\n"));
      }
      // END HACK
      return cloneJobList(cached);
    }

    private List<Job> cloneJobList(List<? extends Job> jobs) {
      List<Job> out = Lists.newArrayList();
      for (Job job : jobs) {
        out.add(Job.job(job.getRoot().clone(), job.getBaseUri()));
      }
      return out;
    }

    @Override
    public Key forJob(ContentType type, ParseTreeNode node) {
      return new TestKey(type, render(node));
    }

    @Override
    public void store(Key k, List<? extends Job> derivatives) {
      System.err.println("STORING  " + k);
      for (Job derivative : derivatives) {
        System.err.println(
            "    " + render(derivative.getRoot()).replace("\n", "\\n"));
      }
      List<Job> old = jobMap.put((TestKey) k, cloneJobList(derivatives));
      if (old != null) {
        throw new IllegalStateException(
            "Tests shouldn't overwrite cache entries");
      }
    }
  }

  @Override protected PluginMeta createPluginMeta() {
    PluginMeta meta = super.createPluginMeta();
    meta.setIdClass("foo123___");
    return meta;
  }

  @Override protected void setUp() throws Exception {
    super.setUp();
    cache = new TestJobCache();
    is = new InputSource(URI.create(
        "test://example.org/" + getClass().getSimpleName()));
  }

  @Override protected void tearDown() throws Exception {
    super.tearDown();
    cache = null;
  }

  private static final String CACHEABLE_HELLO_WORLD_CSS
      = "<style>b { color: blue; font-weight: inherit }</style>";
  private static final String REWRITTEN_HELLO_WORLD_CSS = Join.join(
      "\n",
      "<style type=\"text/css\">",
      ".foo123___ b {",
      "  color: blue;",
      "  font-weight: inherit",
      "}</style>");

  private static final String CACHEABLE_HELLO_WORLD_CSS_VARIANT
      = "<style>p { color: purple }</style>";
  private static final String REWRITTEN_HELLO_WORLD_CSS_VARIANT = Join.join(
      "\n",
      "<style type=\"text/css\">",
      ".foo123___ p {",
      "  color: purple",
      "}</style>");

  private static final String REWRITTEN_HELLO_WORLD_CSS_AND_VARIANT = Join.join(
      "\n",
      "<style type=\"text/css\">",
      ".foo123___ b {",
      "  color: blue;",
      "  font-weight: inherit",
      "}",
      ".foo123___ p {",
      "  color: purple",
      "}</style>");

  private static final String REWRITTEN_HELLO_WORLD_VARIANT_AND_CSS = Join.join(
      "\n",
      "<style type=\"text/css\">",
      ".foo123___ p {",
      "  color: purple",
      "}",
      ".foo123___ b {",
      "  color: blue;",
      "  font-weight: inherit",
      "}</style>");


  private static final String jsModulePrefix(
      String[] importMembers, String[] vars) {
    StringBuilder sb = new StringBuilder();
    sb.append("{\n");
    sb.append("  var dis___ = IMPORTS___;\n");
    for (String importMember : importMembers) {
      sb.append(importMember).append("\n");
    }
    sb.append("  var moduleResult___");
    for (String var : vars) {
      sb.append(", ").append(var);
    }
    sb.append(";\n");
    sb.append("  moduleResult___ = ___.NO_RESULT;\n");
    return sb.toString();
  }

  private static final String JS_MODULE_SUFFIX = Join.join(
      "\n",
      "",
      "    el___ = emitter___.finish();",
      "    emitter___.signalLoaded();",
      "  }",
      "  return moduleResult___;",
      "}");

  private static final String CACHEABLE_HELLO_WORLD_HTML
      = "<b onclick=alert('Hello')>Hello, World!</b>";
  private static final String REWRITTEN_HELLO_WORLD_HTML
      = "<b id=\"id_3___\">Hello, World!</b>";
  private static final String REWRITTEN_HELLO_WORLD_HTML_HELPER_JS
      = jsModulePrefix(
          new String[] {},
          new String[] { "el___", "emitter___", "c_2___" })
      + Join.join(
      "\n",
      "  {",
      "    emitter___ = IMPORTS___.htmlEmitter___;",
      "    el___ = emitter___.byId('id_3___');",
      "    c_2___ = ___.markFuncFreeze(function (event, thisNode___) {",
      "        (IMPORTS___.alert_v___? IMPORTS___.alert:"
        + " ___.ri(IMPORTS___, 'alert'))",
      "        .i___('Hello');",
      "      });",
      "    el___.onclick = function (event) {",
      ("      return ___.plugin_dispatchEvent___"
       + "(this, event, ___.getId(IMPORTS___),"),
      "        c_2___);",
      "    };",
      "    emitter___.rmAttr(el___, 'id');")
      + JS_MODULE_SUFFIX;

  private static final String REWRITTEN_HELLO_WORLD_HTML_HELPER_JS_NO_LOAD
      = REWRITTEN_HELLO_WORLD_HTML_HELPER_JS
        .replaceFirst("\n *emitter___\\.signalLoaded\\(\\);", "");


  private static final String CACHEABLE_HELLO_WORLD_JS
      = "<script>alert('Hello');</script>";
  private static final String CACHEABLE_HELLO_WORLD_JS_DEFERRED
      = "<script defer>alert('Hello');</script>";
  private static final String REWRITTEN_HELLO_WORLD_JS
      = jsModulePrefix(
          new String[] {},
          new String[] {})
      + Join.join(
      "\n",
      "  try {",
      "    {",
      "      moduleResult___ = (IMPORTS___.alert_v___? IMPORTS___.alert:",
      "        ___.ri(IMPORTS___, 'alert')).i___('Hello');",
      "    }",
      "  } catch (ex___) {",
      "    ___.getNewModuleHandler().handleUncaughtException(ex___,",
      "      IMPORTS___.onerror_v___? IMPORTS___.onerror: ___.ri(IMPORTS___,",
      "        'onerror'), 'PipelineCacheTest', '1');",
      "  }",
      "  return moduleResult___;",
      "}");

  private static final String CACHEABLE_HELLO_WORLD_JS_VARIANT
      = "<script>alert('Howdy');</script>";
  private static final String CACHEABLE_HELLO_WORLD_JS_VARIANT_DEFERRED
      = "<script defer>alert('Howdy');</script>";
  private static final String REWRITTEN_HELLO_WORLD_JS_VARIANT
      = jsModulePrefix(
          new String[] {},
          new String[] {})
      + Join.join(
      "\n",
      "  try {",
      "    {",
      "      moduleResult___ = (IMPORTS___.alert_v___? IMPORTS___.alert:",
      "        ___.ri(IMPORTS___, 'alert')).i___('Howdy');",
      "    }",
      "  } catch (ex___) {",
      "    ___.getNewModuleHandler().handleUncaughtException(ex___,",
      "      IMPORTS___.onerror_v___? IMPORTS___.onerror: ___.ri(IMPORTS___,",
      "        'onerror'), 'PipelineCacheTest', '1');",
      "  }",
      "  return moduleResult___;",
      "}");

  private static final String SIGNAL_LOADED_JS = Join.join(
      "\n",
      "{",
      "  var dis___ = IMPORTS___;",
      "  var moduleResult___;",
      "  moduleResult___ = ___.NO_RESULT;",
      "  {",
      "    IMPORTS___.htmlEmitter___.signalLoaded();",
      "  }",
      "  return moduleResult___;",
      "}");

  public final void testEmptyCache() throws Exception {
    ((EchoingMessageQueue) mq).setDumpStack(true);
    JobStub[] golden = new JobStub[] {
        job(REWRITTEN_HELLO_WORLD_CSS, ContentType.HTML),
        job(REWRITTEN_HELLO_WORLD_HTML, ContentType.HTML),
        job(REWRITTEN_HELLO_WORLD_JS, ContentType.JS),
        job(REWRITTEN_HELLO_WORLD_HTML_HELPER_JS, ContentType.JS),
        //job(SIGNAL_LOADED_JS, ContentType.JS),
    };
    assertPipeline(
        job(
            CACHEABLE_HELLO_WORLD_CSS + CACHEABLE_HELLO_WORLD_JS
            + CACHEABLE_HELLO_WORLD_HTML,
            ContentType.HTML),
        golden);
    assertEquals(0, cache.nServedFromCache);

    meta = createPluginMeta();
    assertPipeline(
        job(
            CACHEABLE_HELLO_WORLD_CSS + CACHEABLE_HELLO_WORLD_JS
            + CACHEABLE_HELLO_WORLD_HTML,
            ContentType.HTML),
        golden);
    // The CSS and JS are served from the cache, but not the HTML since the JS
    // has to be integrated back into the HTML.
    assertEquals(2, cache.nServedFromCache);
  }

  public final void testMixAndMatchJs() throws Exception {
    // Prime the cache.
    assertPipeline(
        job(
            CACHEABLE_HELLO_WORLD_CSS + CACHEABLE_HELLO_WORLD_HTML
            + CACHEABLE_HELLO_WORLD_JS,
            ContentType.HTML),
        job(REWRITTEN_HELLO_WORLD_CSS, ContentType.HTML),
        job(REWRITTEN_HELLO_WORLD_HTML, ContentType.HTML),
        job(REWRITTEN_HELLO_WORLD_HTML_HELPER_JS_NO_LOAD, ContentType.JS),
        job(REWRITTEN_HELLO_WORLD_JS, ContentType.JS),
        job(SIGNAL_LOADED_JS, ContentType.JS));
    assertEquals(0, cache.nServedFromCache);

    meta = createPluginMeta();
    assertPipeline(
        job(
            CACHEABLE_HELLO_WORLD_CSS + CACHEABLE_HELLO_WORLD_HTML
            + CACHEABLE_HELLO_WORLD_JS_VARIANT,
            ContentType.HTML),
        job(REWRITTEN_HELLO_WORLD_CSS, ContentType.HTML),
        job(REWRITTEN_HELLO_WORLD_HTML, ContentType.HTML),
        job(REWRITTEN_HELLO_WORLD_HTML_HELPER_JS_NO_LOAD, ContentType.JS),
        job(REWRITTEN_HELLO_WORLD_JS_VARIANT, ContentType.JS),
        job(SIGNAL_LOADED_JS, ContentType.JS));
    // Some compiled JS was served from the cache.
    assertEquals(2, cache.nServedFromCache);
  }

  public final void testMixAndMatchCss() throws Exception {
    // Prime the cache.
    assertPipeline(
        job(
            CACHEABLE_HELLO_WORLD_CSS + CACHEABLE_HELLO_WORLD_HTML
            + CACHEABLE_HELLO_WORLD_JS,
            ContentType.HTML),
        job(REWRITTEN_HELLO_WORLD_CSS, ContentType.HTML),
        job(REWRITTEN_HELLO_WORLD_HTML, ContentType.HTML),
        job(REWRITTEN_HELLO_WORLD_HTML_HELPER_JS_NO_LOAD, ContentType.JS),
        job(REWRITTEN_HELLO_WORLD_JS, ContentType.JS),
        job(SIGNAL_LOADED_JS, ContentType.JS));
    assertEquals(0, cache.nServedFromCache);
    System.err.println("Done");

    meta = createPluginMeta();
    assertPipeline(
        job(
            CACHEABLE_HELLO_WORLD_CSS_VARIANT + CACHEABLE_HELLO_WORLD_HTML
            + CACHEABLE_HELLO_WORLD_JS,
            ContentType.HTML),
        job(REWRITTEN_HELLO_WORLD_CSS_VARIANT, ContentType.HTML),
        job(REWRITTEN_HELLO_WORLD_HTML, ContentType.HTML),
        job(REWRITTEN_HELLO_WORLD_HTML_HELPER_JS_NO_LOAD, ContentType.JS),
        job(REWRITTEN_HELLO_WORLD_JS, ContentType.JS),
        job(SIGNAL_LOADED_JS, ContentType.JS));
    // The JS was served from the cache, but not the CSS.
    assertEquals(3, cache.nServedFromCache);
  }

  public final void testCssCacheOrdering() throws Exception {
    // Prime the cache.
    assertPipeline(
        job(
            CACHEABLE_HELLO_WORLD_CSS + CACHEABLE_HELLO_WORLD_CSS_VARIANT
            + CACHEABLE_HELLO_WORLD_HTML + CACHEABLE_HELLO_WORLD_JS,
            ContentType.HTML),
        job(REWRITTEN_HELLO_WORLD_CSS_AND_VARIANT, ContentType.HTML),
        job(REWRITTEN_HELLO_WORLD_HTML, ContentType.HTML),
        job(REWRITTEN_HELLO_WORLD_HTML_HELPER_JS_NO_LOAD, ContentType.JS),
        job(REWRITTEN_HELLO_WORLD_JS, ContentType.JS),
        job(SIGNAL_LOADED_JS, ContentType.JS));
    assertEquals(0, cache.nServedFromCache);

    // Now render, but with the order of CSS changed.
    // CSS order is significant because when rule overlap, the later one wins.
    // So the text is blue in
    //   <style>p{color:red}</style><style>p{color:blue}</style><p>Hi</p>.
    meta = createPluginMeta();
    assertPipeline(
        job(
            CACHEABLE_HELLO_WORLD_CSS_VARIANT + CACHEABLE_HELLO_WORLD_CSS
            + CACHEABLE_HELLO_WORLD_HTML + CACHEABLE_HELLO_WORLD_JS,
            ContentType.HTML),
        job(REWRITTEN_HELLO_WORLD_VARIANT_AND_CSS, ContentType.HTML),
        job(REWRITTEN_HELLO_WORLD_HTML, ContentType.HTML),
        job(REWRITTEN_HELLO_WORLD_HTML_HELPER_JS_NO_LOAD, ContentType.JS),
        job(REWRITTEN_HELLO_WORLD_JS, ContentType.JS),
        job(SIGNAL_LOADED_JS, ContentType.JS));
    // The JS was served from the cache as well as both CSS blocks.
    assertEquals(3, cache.nServedFromCache);
  }

  private static String rewriteGeneratedIds(String src) {
    return src.replaceAll("\\bc_2___\\b", "c_3___")
        .replaceAll("\\bid_3___\\b", "id_4___");
  }

  public final void testDeferredJsCacheOrdering() throws Exception {
    // Prime the cache.
    assertPipeline(
        job(
            CACHEABLE_HELLO_WORLD_JS + CACHEABLE_HELLO_WORLD_JS_VARIANT_DEFERRED
            + CACHEABLE_HELLO_WORLD_HTML,
            ContentType.HTML),
        job(rewriteGeneratedIds(REWRITTEN_HELLO_WORLD_HTML), ContentType.HTML),
        job(REWRITTEN_HELLO_WORLD_JS, ContentType.JS),
        job(rewriteGeneratedIds(REWRITTEN_HELLO_WORLD_HTML_HELPER_JS_NO_LOAD),
            ContentType.JS),
        job(REWRITTEN_HELLO_WORLD_JS_VARIANT, ContentType.JS),
        job(SIGNAL_LOADED_JS, ContentType.JS));
    assertEquals(0, cache.nServedFromCache);

    // Make sure deferring scripts doesn't cause them to execute out of order.
    meta = createPluginMeta();
    assertPipeline(
        job(
            CACHEABLE_HELLO_WORLD_JS_DEFERRED + CACHEABLE_HELLO_WORLD_JS_VARIANT
            + CACHEABLE_HELLO_WORLD_HTML,
            ContentType.HTML),
        job(rewriteGeneratedIds(REWRITTEN_HELLO_WORLD_HTML), ContentType.HTML),
        job(REWRITTEN_HELLO_WORLD_JS_VARIANT, ContentType.JS),
        job(rewriteGeneratedIds(REWRITTEN_HELLO_WORLD_HTML_HELPER_JS_NO_LOAD),
            ContentType.JS),
        job(REWRITTEN_HELLO_WORLD_JS, ContentType.JS),
        job(SIGNAL_LOADED_JS, ContentType.JS));
    // Little JS blocks were served from the cache.
    assertEquals(4, cache.nServedFromCache);
  }

  public final void testJsCacheOrdering() throws Exception {
    // Prime the cache.
    assertPipeline(
        job(
            CACHEABLE_HELLO_WORLD_JS + CACHEABLE_HELLO_WORLD_JS_VARIANT
            + CACHEABLE_HELLO_WORLD_HTML,
            ContentType.HTML),
        job(rewriteGeneratedIds(REWRITTEN_HELLO_WORLD_HTML), ContentType.HTML),
        job(REWRITTEN_HELLO_WORLD_JS, ContentType.JS),
        job(REWRITTEN_HELLO_WORLD_JS_VARIANT, ContentType.JS),
        job(rewriteGeneratedIds(REWRITTEN_HELLO_WORLD_HTML_HELPER_JS),
            ContentType.JS));
    assertEquals(0, cache.nServedFromCache);

    // Make sure reordering scripts doesn't cause them to execute out of order.
    meta = createPluginMeta();
    assertPipeline(
        job(
            CACHEABLE_HELLO_WORLD_JS_VARIANT + CACHEABLE_HELLO_WORLD_JS
            + CACHEABLE_HELLO_WORLD_HTML,
            ContentType.HTML),
        job(rewriteGeneratedIds(REWRITTEN_HELLO_WORLD_HTML), ContentType.HTML),
        job(REWRITTEN_HELLO_WORLD_JS_VARIANT, ContentType.JS),
        job(REWRITTEN_HELLO_WORLD_JS, ContentType.JS),
        job(rewriteGeneratedIds(REWRITTEN_HELLO_WORLD_HTML_HELPER_JS),
            ContentType.JS));
    // Some JS blocks were served from the cache.
    assertEquals(3, cache.nServedFromCache);
  }

  public final void testIhabsHeadache() throws Exception {
    JobStub[] goldens = {
        job("<p id=\"id_2___\">1337</p>", ContentType.HTML),
        job(jsModulePrefix(
            new String[] {},
            new String[] { "el___", "emitter___", "c_1___" })
            + Join.join(
                "\n",
                "  {",
                "    emitter___ = IMPORTS___.htmlEmitter___;",
                "    el___ = emitter___.byId('id_2___');",
                "    c_1___ = ___.markFuncFreeze(function (event, thisNode___) {",
                "        (IMPORTS___.alert_v___? IMPORTS___.alert:"
                + " ___.ri(IMPORTS___, 'alert'))",
                "        .i___(1337);",
                "      });",
                "    el___.onclick = function (event) {",
                "      return ___.plugin_dispatchEvent___(this, event, ___.getId(IMPORTS___),",
                "        c_1___);",
                "    };",
                "    emitter___.rmAttr(el___, 'id');")
                + JS_MODULE_SUFFIX, ContentType.JS)
    };

    // Prime the cache.
    assertPipeline(
        job("<p onclick=\"alert(1337);\">1337</p>", ContentType.HTML),
        goldens);
    assertEquals(0, cache.nServedFromCache);

    // Make sure that rerunning doesn't cause problems.
    meta = createPluginMeta();
    assertPipeline(
        job("<p onclick=\"alert(1337);\">1337</p>", ContentType.HTML),
        goldens);
    // The JS block was served from the cache.
    assertEquals(1, cache.nServedFromCache);
  }

  public final void testCachedRewriterError() throws Exception {
    assertPipelineFails(
        job("with(e){}", ContentType.JS));
    assertMessage(
        true, RewriterMessageType.WITH_BLOCKS_NOT_ALLOWED,
        MessageLevel.ERROR);
    assertNoWarnings();

    assertPipelineFails(
        job("with(e){}", ContentType.JS));
    assertMessage(
        true, RewriterMessageType.WITH_BLOCKS_NOT_ALLOWED,
        MessageLevel.ERROR);
    assertNoWarnings();
  }


  @Override
  protected boolean runPipeline(Jobs jobs) throws Exception {
    Pipeline<Jobs> pl = new Pipeline<Jobs>();
    PipelineMaker plm = new PipelineMaker(
        CssSchema.getDefaultCss21Schema(mq),
        HtmlSchema.getDefault(mq),
        new ModuleManager(
            meta, TestBuildInfo.getInstance(), UriFetcher.NULL_NETWORK, mq),
        cache,
        PipelineMaker.DEFAULT_PRECONDS,
        PipelineMaker.CAJOLED_MODULES.with(PipelineMaker.HTML_SAFE_STATIC)
            .with(PipelineMaker.SANITY_CHECK)
        );
    plm.populate(pl.getStages());
    pl.getStages().add(new PipelineStoreStage(cache));
    pl.getStages().add(new Pipeline.Stage<Jobs>() {
      public boolean apply(Jobs jobs) {
        for (ListIterator<JobEnvelope> it = jobs.getJobs().listIterator();
             it.hasNext();) {
          JobEnvelope env = it.next();
          Job j = env.job;
          if (env.fromCache || j.getType() != ContentType.JS) { continue; }
          if (!(j.getRoot() instanceof CajoledModule)) {
            throw new IllegalStateException("Some content not cajoled");
          }
          CajoledModule m = (CajoledModule) j.getRoot();
          Statement body = m.getInstantiateMethod().getBody();
          it.set(env.withJob(Job.jsJob(body, j.getBaseUri())));
        }
        return true;
      }
    });
    return pl.apply(jobs);
  }
}
TOP

Related Classes of com.google.caja.plugin.PipelineCacheTest

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.