Package com.google.template.soy.parsepasses

Source Code of com.google.template.soy.parsepasses.CheckFunctionCallsVisitorTest

/*
* Copyright 2011 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.template.soy.parsepasses;

import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.template.soy.base.SoySyntaxException;
import com.google.template.soy.shared.internal.SharedTestUtils;
import com.google.template.soy.shared.restricted.SoyFunction;
import com.google.template.soy.soytree.SoyFileSetNode;

import junit.framework.TestCase;

import java.util.Map;
import java.util.Set;


/**
* @author Mike Samuel
*/
public class CheckFunctionCallsVisitorTest extends TestCase {


  public final void testPureFunctionOk() throws Exception {
    applyCheckFunctionCallsVisitor(Joiner.on('\n').join(
        "{namespace ns}\n",
        "/**",
        " * @param x",
        " * @param y",
        " */",
        "{template .foo}",
        "  {print min($x, $y)}",
        "{/template}"));
  }


  public final void testIncorrectArity() throws Exception {
    assertFunctionCallsInvalid(
        "In file no-path:7, template ns.foo:" +
            " Function 'min' called with the wrong number of arguments" +
            " (function call \"min($x)\").",
        Joiner.on('\n').join(
            "{namespace ns}\n",
            "/**",
            " * @param x",
            " */",
            "{template .foo}",
            "  {print min($x)}",
            "{/template}"));
    assertFunctionCallsInvalid(
        "In file no-path:6, template ns.foo:" +
            " Function 'index' called with the wrong number of arguments" +
            " (function call \"index()\").",
        Joiner.on('\n').join(
            "{namespace ns}\n",
            "/**",
            " */",
            "{template .foo}",
            "  {print index()}",
            "{/template}"));
  }


  public final void testNestedFunctionCall() throws Exception {
    assertFunctionCallsInvalid(
        "In file no-path:8, template ns.foo:" +
            " Function 'min' called with the wrong number of arguments (function call" +
            " \"min($x)\").",
        Joiner.on('\n').join(
            "{namespace ns}\n",
            "/**",
            " * @param x",
            " * @param y",
            " */",
            "{template .foo}",
            "  {print min(min($x), min($x, $y))}",
            "{/template}"));
  }


  public final void testNotALoopVariable1() throws Exception {
    assertFunctionCallsInvalid(
        "In file no-path:7, template ns.foo:" +
            " Function 'index' must have a foreach loop variable as its argument" +
            " (encountered \"index($x)\").",
        Joiner.on('\n').join(
            "{namespace ns}\n",
            "/**",
            " * @param x",
            " */",
            "{template .foo}",
            "  {print index($x)}",
            "{/template}"));
  }


  public final void testNotALoopVariable2() throws Exception {
    assertFunctionCallsInvalid(
        "In file no-path:7, template ns.foo:" +
            " Function 'index' must have a foreach loop variable as its argument" +
            " (encountered \"index($x.y)\").",
        Joiner.on('\n').join(
            "{namespace ns}\n",
            "/**",
            " * @param x",
            " */",
            "{template .foo}",
            "  {print index($x.y)}",
            "{/template}"));
  }


  public final void testNotALoopVariable3() throws Exception {
    assertFunctionCallsInvalid(
        "In file no-path:6, template ns.foo:" +
            " Function 'index' must have a foreach loop variable as its argument" +
            " (encountered \"index($ij.data)\").",
        Joiner.on('\n').join(
            "{namespace ns}\n",
            "/**",
            " */",
            "{template .foo}",
            "  {print index($ij.data)}",
            "{/template}"));
  }



  public final void testNotAVariable() throws Exception {
    assertFunctionCallsInvalid(
        "In file no-path:7, template ns.foo:" +
            " Function 'index' must have a foreach loop variable as its argument" +
            " (encountered \"index($x + 1)\").",
        Joiner.on('\n').join(
            "{namespace ns}\n",
            "/**",
            " * @param x",
            " */",
            "{template .foo}",
            "  {print index($x + 1)}",
            "{/template}"));
  }


  public final void testLoopVariableOk() throws Exception {
    applyCheckFunctionCallsVisitor(Joiner.on('\n').join(
        "{namespace ns}\n",
        "/**",
        " * @param elements",
        " */",
        "{template .foo}",
        "  {foreach $z in $elements}",
        "    {if isLast($z)}Lorem Ipsum{/if}",
        "  {/foreach}",
        "{/template}"));
  }


  public final void testLoopVariableNotInScopeWhenEmpty() throws Exception {
    assertFunctionCallsInvalid(
        "In file no-path:10, template ns.foo:" +
            " Function 'index' must have a foreach loop variable as its argument" +
            " (encountered \"index($z)\").",
        Joiner.on('\n').join(
            "{namespace ns}\n",
            "/**",
            " * @param elements",
            " */",
            "{template .foo}",
            "  {foreach $z in $elements}",
            "    Lorem Ipsum...",
            "  {ifempty}",
            "    {print index($z)}"// Loop variable not in scope when empty.
            "  {/foreach}",
            "{/template}"));
  }


  public final void testQuoteKeysIfJsFunction() throws Exception {

    applyCheckFunctionCallsVisitor(
        Joiner.on('\n').join(
            "{namespace ns}\n",
            "/***/",
            "{template .foo}",
            "  {let $m: quoteKeysIfJs(['a': 1, 'b': 'blah']) /}",
            "{/template}"));

    assertFunctionCallsInvalid(
        "In file no-path:5, template ns.foo:" +
            " Function quoteKeysIfJs() must have a map literal as its arg" +
            " (encountered \"quoteKeysIfJs('blah')\").",
        Joiner.on('\n').join(
            "{namespace ns}\n",
            "/***/",
            "{template .foo}",
            "  {let $m: quoteKeysIfJs('blah') /}",
            "{/template}"));
  }


  public final void testUnrecognizedFunction() throws Exception {
    assertFunctionCallsInvalid(
        "In file no-path:6, template ns.foo:" +
            " Unrecognized function 'bogus' (encountered function call \"bogus()\").",
        Joiner.on('\n').join(
            "{namespace ns}\n",
            "/**",
            " */",
            "{template .foo}",
            "  {print bogus()}",
            "{/template}"));
  }


  public final void testUnrecognizedFunctionOkInV1() throws Exception {
    applyCheckFunctionCallsVisitor(
        Joiner.on('\n').join(
            "{namespace ns}\n",
            "{template .foo}",
            "  {print bogus()}",
            "{/template}"),
        true);
  }


  private void applyCheckFunctionCallsVisitor(String soyContent) throws Exception {
    applyCheckFunctionCallsVisitor(soyContent, false);
  }


  private void applyCheckFunctionCallsVisitor(String soyContent, boolean allowExterns)
      throws Exception {
    SoyFileSetNode fileSet = SharedTestUtils.parseSoyFiles(soyContent);
    Map<String, SoyFunction> soyFunctions = ImmutableMap.<String, SoyFunction>of(
        "min",
        new SoyFunction() {
          public @Override String getName() {
            return "min";
          }

          public @Override Set<Integer> getValidArgsSizes() {
            return ImmutableSet.of(2);
          }
        });
    CheckFunctionCallsVisitor v = new CheckFunctionCallsVisitor(soyFunctions);
    v.setAllowExternallyDefinedFunctions(allowExterns);
    v.exec(fileSet);
  }


  private void assertFunctionCallsInvalid(String errorMessage, String soyContent) throws Exception {
    try {
      applyCheckFunctionCallsVisitor(soyContent);
      fail("Spurious success.");
    } catch (SoySyntaxException ex) {
      assertEquals(errorMessage, ex.getMessage());
    }
  }

}
TOP

Related Classes of com.google.template.soy.parsepasses.CheckFunctionCallsVisitorTest

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.