public void testParseUnionTypes() { assertTypeEquals(UnionType.of(IntType.getInstance(), BoolType.getInstance()), "int|bool"); assertTypeEquals( UnionType.of(IntType.getInstance(), BoolType.getInstance(), StringType.getInstance()), "int|bool|string"); assertTypeEquals(UnionType.of(IntType.getInstance(), BoolType.getInstance()), " int | bool "); }
public void testDataRefTypes() { SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents( constructTemplateSource( "{@param pa: bool}", "{@param pb: list<int>}", "{@param pe: map<int, map<int, string>>}", "{captureType($pa)}", "{captureType($pb)}", "{captureType($pb[0])}", "{captureType($pe)}", "{captureType($pe[0])}", "{captureType($pe[1 + 1][2])}")) .parse() .fileSet(); createResolveNamesVisitorForMaxSyntaxVersion().exec(soyTree); createResolveExpressionTypesVisitorForMaxSyntaxVersion().exec(soyTree); List<SoyType> types = getCapturedTypes(soyTree); assertThat(types.get(0)).isEqualTo(BoolType.getInstance()); assertThat(types.get(1)).isEqualTo(ListType.of(IntType.getInstance())); assertThat(types.get(2)).isEqualTo(IntType.getInstance()); assertThat(types.get(3)) .isEqualTo( MapType.of( IntType.getInstance(), MapType.of(IntType.getInstance(), StringType.getInstance()))); assertThat(types.get(4)).isEqualTo(MapType.of(IntType.getInstance(), StringType.getInstance())); assertThat(types.get(5)).isEqualTo(StringType.getInstance()); }
public void testDataFlowTypeNarrowingFailure() { // Test for places where type narrowing shouldn't work SoyType boolOrNullType = makeNullable(BoolType.getInstance()); SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents( constructTemplateSource( "{@param pa: bool|null}", "{@param pb: bool}", "{if ($pa != null) != ($pb != null)}", " {captureType($pa)}", // #0 don't know "{else}", " {captureType($pa)}", // #1 don't know "{/if}", "{if $pa ?: $pb}", " {captureType($pa)}", // #2 don't know "{/if}", "{if $pb ? $pa : false}", " {captureType($pa)}", // #3 don't know "{/if}")) .parse() .fileSet(); createResolveNamesVisitorForMaxSyntaxVersion().exec(soyTree); createResolveExpressionTypesVisitorForMaxSyntaxVersion().exec(soyTree); List<SoyType> types = getCapturedTypes(soyTree); assertThat(types.get(0)).isEqualTo(boolOrNullType); assertThat(types.get(1)).isEqualTo(boolOrNullType); assertThat(types.get(2)).isEqualTo(boolOrNullType); assertThat(types.get(3)).isEqualTo(boolOrNullType); }
public void testComparisonOps() { SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents( constructTemplateSource( "{@param pa: unknown}", "{@param pi: int}", "{@param pf: float}", "{captureType($pa > $pa)}", "{captureType($pi > $pi)}", "{captureType($pf > $pf)}", "{captureType($pa >= $pa)}", "{captureType($pi >= $pi)}", "{captureType($pf >= $pf)}", "{captureType($pa < $pa)}", "{captureType($pi < $pi)}", "{captureType($pf < $pf)}", "{captureType($pa <= $pa)}", "{captureType($pi <= $pi)}", "{captureType($pf <= $pf)}", "{captureType($pa == $pa)}", "{captureType($pi == $pi)}", "{captureType($pf == $pf)}", "{captureType($pa != $pa)}", "{captureType($pi != $pi)}", "{captureType($pf != $pf)}")) .declaredSyntaxVersion(SyntaxVersion.V2_0) .doRunInitialParsingPasses(false) .typeRegistry(typeRegistry) .parse() .fileSet(); createResolveNamesVisitorForMaxSyntaxVersion().exec(soyTree); createResolveExpressionTypesVisitorForMaxSyntaxVersion().exec(soyTree); ImmutableSet<SoyType> types = ImmutableSet.copyOf(getCapturedTypes(soyTree)); assertThat(types).containsExactly(BoolType.getInstance()); }
public void testParseTypeNames() { assertTypeEquals(AnyType.getInstance(), "any"); assertTypeEquals(AnyType.getInstance(), " any "); assertTypeEquals(IntType.getInstance(), "int"); assertTypeEquals(BoolType.getInstance(), "bool"); assertTypeEquals(FOO_BAR_TYPE, "foo.bar"); assertTypeEquals(FOO_BAR_TYPE, " foo.bar "); assertTypeEquals(FOO_BAR_TYPE, " foo . bar "); assertTypeEquals(UnknownType.getInstance(), "?"); }
public void testDataFlowTypeNarrowing_logicalExpressions() { SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents( constructTemplateSource( "{@param? record: [active : bool|null]}", "{@param? selected: map<string,bool>}", "{$selected and $selected['a']}", "{$selected == null or $selected['a']}", "{if isNonnull($record.active) and (not $record.active)}", " {$record.active}", "{/if}", "")) .parse(); createResolveNamesVisitorForMaxSyntaxVersion().exec(soyTree); createResolveExpressionTypesVisitorForMaxSyntaxVersion().exec(soyTree); List<SoyType> types = getPrintStatementTypes(soyTree); assertThat(types.get(0)).isEqualTo(BoolType.getInstance()); assertThat(types.get(1)).isEqualTo(BoolType.getInstance()); assertThat(types.get(2)).isEqualTo(BoolType.getInstance()); }
public void testOptionalParamTypes() { SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents( constructTemplateSource( "{@param? pa: bool}", "{@param? pb: list<int>}", "{$pa}", "{$pb}")) .parse(); createResolveNamesVisitorForMaxSyntaxVersion().exec(soyTree); createResolveExpressionTypesVisitorForMaxSyntaxVersion().exec(soyTree); List<SoyType> types = getPrintStatementTypes(soyTree); assertThat(types.get(0)).isEqualTo(makeNullable(BoolType.getInstance())); assertThat(types.get(1)).isEqualTo(makeNullable(ListType.of(IntType.getInstance()))); }
public void testFunctionTyping() { SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents( constructTemplateSource( "{@inject list: list<int|null>}", "{foreach $item in $list}", " {index($item)}", " {isLast($item)}", " {isFirst($item)}", " {$item}", " {checkNotNull($item)}", "{/foreach}")) .parse(); createResolveNamesVisitorForMaxSyntaxVersion().exec(soyTree); createResolveExpressionTypesVisitorForMaxSyntaxVersion().exec(soyTree); List<SoyType> types = getPrintStatementTypes(soyTree); assertThat(types.get(0)).isEqualTo(IntType.getInstance()); assertThat(types.get(1)).isEqualTo(BoolType.getInstance()); assertThat(types.get(2)).isEqualTo(BoolType.getInstance()); assertThat(types.get(3)).isEqualTo(makeNullable(IntType.getInstance())); assertThat(types.get(4)).isEqualTo(IntType.getInstance()); }
public void testConditionalOperatorDataFlowTypeNarrowing() { SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents( constructTemplateSource( "{@param pa: bool|null}", "{@param pb: bool}", "{@param pc: [a : int|null]}", "{$pa ? $pa : $pb}", // #0 must be non-null "{$pa != null ?: $pb}", // #1 must be non-null "{$pa ?: $pb}", "{$pc.a ? $pc.a : 0}", "{if not $pc.a}{$pc.a}{/if}")) .parse(); // #2 must be non-null (re-written to (isNonnull($pa) ? $pa : $pb)) createResolveNamesVisitorForMaxSyntaxVersion().exec(soyTree); createResolveExpressionTypesVisitorForMaxSyntaxVersion().exec(soyTree); List<SoyType> types = getPrintStatementTypes(soyTree); assertThat(types.get(0)).isEqualTo(BoolType.getInstance()); assertThat(types.get(1)).isEqualTo(BoolType.getInstance()); assertThat(types.get(2)).isEqualTo(BoolType.getInstance()); assertThat(types.get(3)).isEqualTo(IntType.getInstance()); assertThat(types.get(4)).isEqualTo(makeNullable(IntType.getInstance())); }
public void testInjectedParamTypes() { SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents( constructTemplateSource( "{@inject pa: bool}", "{@inject? pb: list<int>}", "{captureType($pa)}", "{captureType($pb)}")) .parse() .fileSet(); createResolveNamesVisitorForMaxSyntaxVersion().exec(soyTree); createResolveExpressionTypesVisitorForMaxSyntaxVersion().exec(soyTree); List<SoyType> types = getCapturedTypes(soyTree); assertThat(types.get(0)).isEqualTo(BoolType.getInstance()); assertThat(types.get(1)).isEqualTo(makeNullable(ListType.of(IntType.getInstance()))); }
public void testParameterizedTypes() { assertTypeEquals(ListType.of(StringType.getInstance()), "list<string>"); assertTypeEquals(ListType.of(StringType.getInstance()), "list < string > "); assertTypeEquals(MapType.of(IntType.getInstance(), BoolType.getInstance()), "map<int, bool>"); }
@Override public SoyType getType() { return BoolType.getInstance(); }
public void testDataFlowTypeNarrowing() { SoyType boolOrNullType = makeNullable(BoolType.getInstance()); SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents( constructTemplateSource( "{@param pa: bool|null}", "{@param pb: bool}", "{if $pa != null}", " {captureType($pa)}", // #0 must be non-null "{/if}", "{if $pa == null}", " {captureType($pa)}", // #1 must be null "{else}", " {captureType($pa)}", // #2 must be non-null "{/if}", "{if $pa == null or $pb}", " {captureType($pa)}", // #3 don't know "{else}", " {captureType($pa)}", // #4 must be non-null "{/if}", "{if $pa == null and $pb}", " {captureType($pa)}", // #5 must be null "{else}", " {captureType($pa)}", // #6 don't know "{/if}", "{if null != $pa}", // Reverse order " {captureType($pa)}", // #7 must be non-null "{/if}", "{if not ($pa == null)}", // Not operator " {captureType($pa)}", // #8 must be non-null "{/if}", "{if $pa}", // Implicit != null " {captureType($pa)}", // #9 must be non-null "{/if}", "{if $pa and $pb}", // Implicit != null " {captureType($pa)}", // #10 must be non-null "{/if}", "{if $pa}", // Chained conditions "{elseif $pb}", " {captureType($pa)}", // #11 must be falsy "{else}", " {captureType($pa)}", // #12 must be falsy "{/if}", "{if $pa}", // Nested if " {if $pa}", " {captureType($pa)}", // #13 must be non-null " {/if}", "{/if}", "{if isNonnull($pa)}", // isNonnull function " {captureType($pa)}", // #14 must be non-null "{else}", " {captureType($pa)}", // #15 must be null "{/if}", "{if $pb or $pa == null}", " {captureType($pa)}", // #16 don't know "{else}", " {captureType($pa)}", // #17 must be null "{/if}", // TODO(lukes): uncomment this and fix the error // "{if null == null or null != null}{/if}", "")) .parse() .fileSet(); createResolveNamesVisitorForMaxSyntaxVersion().exec(soyTree); createResolveExpressionTypesVisitorForMaxSyntaxVersion().exec(soyTree); List<SoyType> types = getCapturedTypes(soyTree); assertThat(types.get(0)).isEqualTo(BoolType.getInstance()); assertThat(types.get(1)).isEqualTo(NullType.getInstance()); assertThat(types.get(2)).isEqualTo(BoolType.getInstance()); assertThat(types.get(3)).isEqualTo(boolOrNullType); assertThat(types.get(4)).isEqualTo(BoolType.getInstance()); assertThat(types.get(5)).isEqualTo(NullType.getInstance()); assertThat(types.get(6)).isEqualTo(boolOrNullType); assertThat(types.get(7)).isEqualTo(BoolType.getInstance()); assertThat(types.get(8)).isEqualTo(BoolType.getInstance()); assertThat(types.get(9)).isEqualTo(BoolType.getInstance()); assertThat(types.get(10)).isEqualTo(BoolType.getInstance()); assertThat(types.get(11)).isEqualTo(makeNullable(BoolType.getInstance())); assertThat(types.get(12)).isEqualTo(makeNullable(BoolType.getInstance())); assertThat(types.get(13)).isEqualTo(BoolType.getInstance()); assertThat(types.get(14)).isEqualTo(BoolType.getInstance()); assertThat(types.get(15)).isEqualTo(NullType.getInstance()); assertThat(types.get(16)).isEqualTo(makeNullable(BoolType.getInstance())); assertThat(types.get(17)).isEqualTo(BoolType.getInstance()); }
public void testLogicalOps() { String testTemplateContent = constructTemplateSource( "{@param pa: unknown}", "{@param pi: int}", "{@param pf: float}", "{captureType($pa and $pa)}", "{captureType($pi and $pi)}", "{captureType($pf and $pf)}", "{captureType($pa or $pa)}", "{captureType($pi or $pi)}", "{captureType($pf or $pf)}", "{captureType(not $pa)}", "{captureType(not $pi)}", "{captureType(not $pf)}"); SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents(testTemplateContent) .declaredSyntaxVersion(SyntaxVersion.V2_0) .doRunInitialParsingPasses(false) .typeRegistry(typeRegistry) .parse() .fileSet(); createResolveNamesVisitor(SyntaxVersion.V2_0).exec(soyTree); createResolveExpressionTypesVisitor(SyntaxVersion.V2_0).exec(soyTree); List<SoyType> types = getCapturedTypes(soyTree); assertThat(types.get(0)).isEqualTo(UnknownType.getInstance()); assertThat(types.get(1)).isEqualTo(UnknownType.getInstance()); assertThat(types.get(2)).isEqualTo(UnknownType.getInstance()); assertThat(types.get(3)).isEqualTo(UnknownType.getInstance()); assertThat(types.get(4)).isEqualTo(UnknownType.getInstance()); assertThat(types.get(5)).isEqualTo(UnknownType.getInstance()); assertThat(types.get(6)).isEqualTo(BoolType.getInstance()); assertThat(types.get(7)).isEqualTo(BoolType.getInstance()); assertThat(types.get(8)).isEqualTo(BoolType.getInstance()); soyTree = SoyFileSetParserBuilder.forFileContents(testTemplateContent) .declaredSyntaxVersion(SyntaxVersion.V2_3) .doRunInitialParsingPasses(false) .typeRegistry(typeRegistry) .parse() .fileSet(); createResolveNamesVisitor(SyntaxVersion.V2_3).exec(soyTree); createResolveExpressionTypesVisitor(SyntaxVersion.V2_3).exec(soyTree); types = getCapturedTypes(soyTree); assertThat(types.get(0)).isEqualTo(BoolType.getInstance()); assertThat(types.get(1)).isEqualTo(BoolType.getInstance()); assertThat(types.get(2)).isEqualTo(BoolType.getInstance()); assertThat(types.get(3)).isEqualTo(BoolType.getInstance()); assertThat(types.get(4)).isEqualTo(BoolType.getInstance()); assertThat(types.get(5)).isEqualTo(BoolType.getInstance()); assertThat(types.get(6)).isEqualTo(BoolType.getInstance()); assertThat(types.get(7)).isEqualTo(BoolType.getInstance()); assertThat(types.get(8)).isEqualTo(BoolType.getInstance()); }