public void testDataRefTypesWithUnknown() { // Test that data with the 'unknown' type is allowed to function as a map or list. SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents( constructTemplateSource( "{@param pa: unknown}", "{@param pb: map<string, float>}", "{@param pc: map<int, string>}", "{captureType($pa[0])}", "{captureType($pa.xxx)}", "{captureType($pa.xxx.yyy)}", "{captureType($pb[$pa])}", "{captureType($pc[$pa])}")) .declaredSyntaxVersion(SyntaxVersion.V2_0) .doRunInitialParsingPasses(false) .typeRegistry(typeRegistry) .parse() .fileSet(); createResolveNamesVisitorForMaxSyntaxVersion().exec(soyTree); createResolveExpressionTypesVisitorForMaxSyntaxVersion().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(FloatType.getInstance()); assertThat(types.get(4)).isEqualTo(StringType.getInstance()); }
@Override public SoyType getType(String typeName, SoyTypeRegistry typeRegistry) { if (typeName.equals("unknown")) { return UnknownType.getInstance(); } return null; }
public void testNullCoalescingAndConditionalOps() { SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents( constructTemplateSource( "{@param pa: unknown}", "{@param pi: int}", "{@param pf: float}", "{@param? ni: int}", "{captureType($pa ?: $pi)}", "{captureType($pi ?: $pf)}", "{captureType($pa ? $pi : $pf)}", "{captureType($ni ?: 0)}")) .declaredSyntaxVersion(SyntaxVersion.V2_0) .doRunInitialParsingPasses(false) .typeRegistry(typeRegistry) .parse() .fileSet(); createResolveNamesVisitorForMaxSyntaxVersion().exec(soyTree); createResolveExpressionTypesVisitorForMaxSyntaxVersion().exec(soyTree); List<SoyType> types = getCapturedTypes(soyTree); assertThat(types.get(0)).isEqualTo(UnknownType.getInstance()); assertThat(types.get(1)) .isEqualTo(UnionType.of(IntType.getInstance(), FloatType.getInstance())); assertThat(types.get(2)) .isEqualTo(UnionType.of(IntType.getInstance(), FloatType.getInstance())); assertThat(types.get(3)).isEqualTo(IntType.getInstance()); }
public void testStringConcatenation() { SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents( constructTemplateSource( "{@param ps: string}", "{@param pi: int}", "{@param pf: float}", "{@param pb: bool}", "{captureType($ps + $ps)}", "{captureType($ps + $pi)}", "{captureType($ps + $pf)}", "{captureType($ps + $pb)}", "{captureType($pi + $ps)}", "{captureType($pf + $ps)}", "{captureType($pb + $ps)}", "{captureType($pb + $pi)}")) .declaredSyntaxVersion(SyntaxVersion.V2_0) .doRunInitialParsingPasses(false) .typeRegistry(typeRegistry) .parse() .fileSet(); createResolveNamesVisitorForMaxSyntaxVersion().exec(soyTree); createResolveExpressionTypesVisitorForMaxSyntaxVersion().exec(soyTree); List<SoyType> types = getCapturedTypes(soyTree); assertThat(types.get(0)).isEqualTo(StringType.getInstance()); assertThat(types.get(1)).isEqualTo(StringType.getInstance()); assertThat(types.get(2)).isEqualTo(StringType.getInstance()); assertThat(types.get(3)).isEqualTo(StringType.getInstance()); assertThat(types.get(4)).isEqualTo(StringType.getInstance()); assertThat(types.get(5)).isEqualTo(StringType.getInstance()); assertThat(types.get(6)).isEqualTo(StringType.getInstance()); // Actual value of this one is backend specific. aka undefined behavior assertThat(types.get(7)).isEqualTo(UnknownType.getInstance()); }
public void testArithmeticOps() { SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents( constructTemplateSource( "{@param pa: unknown}", "{@param pi: int}", "{@param pf: float}", "{@param ps: string}", "{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)}", "{captureType(-$pi)}", "{captureType(-$pf)}", // The remainder are all logically template errors but are not enforced by the // compiler "{captureType(-$ps)}", "{captureType($ps / $pf)}")) .declaredSyntaxVersion(SyntaxVersion.V2_0) .typeRegistry(typeRegistry) .parse() .fileSet(); createResolveNamesVisitorForMaxSyntaxVersion().exec(soyTree); createResolveExpressionTypesVisitorForMaxSyntaxVersion().exec(soyTree); List<SoyType> types = getCapturedTypes(soyTree); assertThat(types.get(0)).isEqualTo(UnknownType.getInstance()); assertThat(types.get(1)).isEqualTo(IntType.getInstance()); assertThat(types.get(2)).isEqualTo(FloatType.getInstance()); assertThat(types.get(3)).isEqualTo(UnknownType.getInstance()); assertThat(types.get(4)).isEqualTo(IntType.getInstance()); assertThat(types.get(5)).isEqualTo(FloatType.getInstance()); assertThat(types.get(6)).isEqualTo(UnknownType.getInstance()); assertThat(types.get(7)).isEqualTo(IntType.getInstance()); assertThat(types.get(8)).isEqualTo(FloatType.getInstance()); assertThat(types.get(9)).isEqualTo(FloatType.getInstance()); assertThat(types.get(10)).isEqualTo(FloatType.getInstance()); assertThat(types.get(11)).isEqualTo(FloatType.getInstance()); assertThat(types.get(12)).isEqualTo(UnknownType.getInstance()); assertThat(types.get(13)).isEqualTo(IntType.getInstance()); assertThat(types.get(14)).isEqualTo(FloatType.getInstance()); assertThat(types.get(15)).isEqualTo(UnknownType.getInstance()); assertThat(types.get(16)).isEqualTo(IntType.getInstance()); assertThat(types.get(17)).isEqualTo(FloatType.getInstance()); // These are the 'error' cases assertThat(types.get(18)).isEqualTo(UnknownType.getInstance()); assertThat(types.get(19)).isEqualTo(UnknownType.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_deadExpression() { SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents( constructTemplateSource( "{@param record: ?}", "{if $record.unknownField}", " {$record.unknownField}", "{else}", " {if $record.unknownField}", " {$record.unknownField}", // This code is dead, but we can't prove it " {/if}", "{/if}", "")) .parse(); createResolveNamesVisitorForMaxSyntaxVersion().exec(soyTree); createResolveExpressionTypesVisitorForMaxSyntaxVersion().exec(soyTree); List<SoyType> types = getPrintStatementTypes(soyTree); assertThat(types.get(0)).isEqualTo(UnknownType.getInstance()); assertThat(types.get(1)).isEqualTo(UnknownType.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()); }
public void testArithmeticOps() { SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents( constructTemplateSource( "{@param pa: unknown}", "{@param pi: int}", "{@param pf: float}", "{$pa + $pa}", "{$pi + $pi}", "{$pf + $pf}", "{$pa - $pa}", "{$pi - $pi}", "{$pf - $pf}", "{$pa * $pa}", "{$pi * $pi}", "{$pf * $pf}", "{$pa / $pa}", "{$pi / $pi}", "{$pf / $pf}", "{$pa % $pa}", "{$pi % $pi}", "{$pf % $pf}", "{-$pa}", "{-$pi}", "{-$pf}")) .declaredSyntaxVersion(SyntaxVersion.V2_0) .doRunInitialParsingPasses(false) .typeRegistry(typeRegistry) .parse(); createResolveNamesVisitorForMaxSyntaxVersion().exec(soyTree); createResolveExpressionTypesVisitorForMaxSyntaxVersion().exec(soyTree); List<SoyType> types = getPrintStatementTypes(soyTree); assertThat(types.get(0)).isEqualTo(UnknownType.getInstance()); assertThat(types.get(1)).isEqualTo(IntType.getInstance()); assertThat(types.get(2)).isEqualTo(FloatType.getInstance()); assertThat(types.get(3)).isEqualTo(UnknownType.getInstance()); assertThat(types.get(4)).isEqualTo(IntType.getInstance()); assertThat(types.get(5)).isEqualTo(FloatType.getInstance()); assertThat(types.get(6)).isEqualTo(UnknownType.getInstance()); assertThat(types.get(7)).isEqualTo(IntType.getInstance()); assertThat(types.get(8)).isEqualTo(FloatType.getInstance()); assertThat(types.get(9)).isEqualTo(UnknownType.getInstance()); assertThat(types.get(10)).isEqualTo(IntType.getInstance()); assertThat(types.get(11)).isEqualTo(FloatType.getInstance()); assertThat(types.get(12)).isEqualTo(UnknownType.getInstance()); assertThat(types.get(13)).isEqualTo(IntType.getInstance()); assertThat(types.get(14)).isEqualTo(FloatType.getInstance()); assertThat(types.get(15)).isEqualTo(UnknownType.getInstance()); assertThat(types.get(16)).isEqualTo(IntType.getInstance()); assertThat(types.get(17)).isEqualTo(FloatType.getInstance()); }
public void testListLiteral() { SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents( constructTemplateSource( "{@param pi: int}", "{@param pf: float}", "{let $list: [$pi, $pf]/}", "{captureType($list)}", "{captureType(length($list))}")) .declaredSyntaxVersion(SyntaxVersion.V2_0) .typeRegistry(typeRegistry) .parse() .fileSet(); createResolveNamesVisitorForMaxSyntaxVersion().exec(soyTree); createResolveExpressionTypesVisitorForMaxSyntaxVersion().exec(soyTree); List<SoyType> types = getCapturedTypes(soyTree); assertThat(types.get(0)) .isEqualTo(ListType.of(UnionType.of(IntType.getInstance(), FloatType.getInstance()))); assertThat(types.get(1)).isEqualTo(UnknownType.getInstance()); }