/**
   * Returns the contextually rewritten source.
   *
   * <p>The Soy tree may have multiple files, but only the source code for the first is returned.
   */
  private void assertInjected(String expectedOutput, String input) throws SoyAutoescapeException {
    SoyFileSetNode soyTree = parseAndInjectIntoScriptTags(input, " INJE='CTED'");

    StringBuilder src = new StringBuilder();
    src.append(soyTree.getChild(0).toSourceString());

    String output = src.toString().trim();
    if (output.startsWith("{namespace ns")) {
      output = output.substring(output.indexOf('}') + 1).trim();
    }

    assertThat(output).isEqualTo(expectedOutput);
  }
  public void testFindCalleesNotInFile() {

    String testFileContent =
        ""
            + "{namespace boo.foo autoescape=\"deprecated-noncontextual\"}\n"
            + "\n"
            + "/** Test template 1. */\n"
            + "{template .goo}\n"
            + "  {call .goo data=\"all\" /}\n"
            + "  {call .moo data=\"all\" /}\n"
            + "  {call boo.woo.hoo data=\"all\" /}\n"
            + // not defined in this file
            "{/template}\n"
            + "\n"
            + "/** Test template 2. */\n"
            + "{template .moo}\n"
            + "  {for $i in range(8)}\n"
            + "    {call boo.foo.goo data=\"all\" /}\n"
            + "    {call .too data=\"all\" /}\n"
            + // not defined in this file
            "    {call .goo}"
            + "      {param a}{call .moo /}{/param}"
            + "      {param b}{call .zoo /}{/param}"
            + // not defined in this file
            "    {/call}"
            + "  {/for}\n"
            + "{/template}\n"
            + "\n"
            + "/** Test template 3. */\n"
            + "{deltemplate booHoo}\n"
            + "  {call .goo data=\"all\" /}\n"
            + "  {call .moo data=\"all\" /}\n"
            + "  {call boo.hoo.roo data=\"all\" /}\n"
            + // not defined in this file
            "{/deltemplate}\n";

    ErrorReporter boom = ExplodingErrorReporter.get();
    SoyFileSetNode soyTree =
        SoyFileSetParserBuilder.forFileContents(testFileContent).errorReporter(boom).parse();
    SoyFileNode soyFile = soyTree.getChild(0);

    Set<String> calleesNotInFile = new FindCalleesNotInFileVisitor(boom).exec(soyFile);
    assertThat(calleesNotInFile).doesNotContain("boo.foo.goo");
    assertThat(calleesNotInFile).doesNotContain("boo.foo.moo");
    assertThat(calleesNotInFile).contains("boo.woo.hoo");
    assertThat(calleesNotInFile).contains("boo.foo.too");
    assertThat(calleesNotInFile).contains("boo.foo.zoo");
    assertThat(calleesNotInFile).contains("boo.hoo.roo");
  }
  private SoyFileSetNode parseAndInjectIntoScriptTags(String input, String toInject) {
    String namespace = "{namespace ns autoescape=\"deprecated-contextual\"}\n\n";
    ErrorReporter boom = ExplodingErrorReporter.get();
    SoyFileSetNode soyTree =
        SoyFileSetParserBuilder.forFileContents(namespace + input).errorReporter(boom).parse();

    ContextualAutoescaper contextualAutoescaper =
        new ContextualAutoescaper(SOY_PRINT_DIRECTIVES, boom);
    List<TemplateNode> extras = contextualAutoescaper.rewrite(soyTree);

    SoyFileNode file = soyTree.getChild(soyTree.numChildren() - 1);
    file.addChildren(file.numChildren(), extras);

    insertTextAtEndOfScriptOpenTag(contextualAutoescaper.getSlicedRawTextNodes(), toInject);
    return soyTree;
  }