public void TestInitialValues() { var source = CreateTestNode(@" <<declare $int = 42>> <<declare $str = ""Hello"">> <<declare $bool = true>> // internal decls {$int} {$str} {$bool} // external decls {$external_int} {$external_str} {$external_bool} "); testPlan = new TestPlanBuilder() // internal decls .AddLine("42") .AddLine("Hello") .AddLine("True") // external decls .AddLine("42") .AddLine("Hello") .AddLine("True") .GetPlan(); CompilationJob compilationJob = CompilationJob.CreateFromString("input", source, dialogue.Library); compilationJob.VariableDeclarations = new[] { new Declaration { Name = "$external_str", Type = BuiltinTypes.String, DefaultValue = "Hello", }, new Declaration { Name = "$external_int", Type = BuiltinTypes.Boolean, DefaultValue = true, }, new Declaration { Name = "$external_bool", Type = BuiltinTypes.Number, DefaultValue = 42, }, }; var result = Compiler.Compile(compilationJob); Assert.Empty(result.Diagnostics); this.storage.SetValue("$external_str", "Hello"); this.storage.SetValue("$external_int", 42); this.storage.SetValue("$external_bool", true); dialogue.SetProgram(result.Program); stringTable = result.StringTable; RunStandardTestcase(); }
public void TestDeclarationFilesAreGenerated() { // Parsing a file that contains variable declarations should be // able to turned back into a string containing the same // information. var originalText = @"title: Program tags: one two custom: yes --- <<declare $str = ""str"" ""str desc"">> <<declare $num = 2 ""num desc"">> <<declare $bool = true ""bool desc"">> === "; var job = CompilationJob.CreateFromString("input", originalText); var result = Compiler.Compile(job); var headers = new Dictionary <string, string> { { "custom", "yes" } }; string[] tags = new[] { "one", "two" }; var generatedOutput = Utility.GenerateYarnFileWithDeclarations(result.Declarations, "Program", tags, headers); Assert.Equal(originalText, generatedOutput); }
public void TestFunctionSignatures(string source) { dialogue.Library.RegisterFunction("func_void_bool", () => true); dialogue.Library.RegisterFunction("func_int_bool", (int i) => true); dialogue.Library.RegisterFunction("func_int_int_bool", (int i, int j) => true); dialogue.Library.RegisterFunction("func_string_string_bool", (string i, string j) => true); var correctSource = CreateTestNode(source); // Should compile with no exceptions var result = Compiler.Compile(CompilationJob.CreateFromString("input", correctSource, dialogue.Library)); Assert.Empty(result.Diagnostics); // The variable '$bool' should have an implicit declaration. var variableDeclarations = result.Declarations.Where(d => d.Name == "$bool"); Assert.Single(variableDeclarations); var variableDeclaration = variableDeclarations.First(); // The type of the variable should be Boolean, because that's // the return type of all of the functions we declared. Assert.Same(BuiltinTypes.Boolean, variableDeclaration.Type); }
public void TestNestedImplicitFunctionDeclarations() { var source = CreateTestNode(@" {func_bool_bool(bool(func_int_bool(1)))} "); dialogue.Library.RegisterFunction("func_int_bool", (int i) => i == 1); dialogue.Library.RegisterFunction("func_bool_bool", (bool b) => b); testPlan = new TestPlanBuilder() .AddLine("True") .GetPlan(); // the library is NOT attached to this compilation job; all // functions will be implicitly declared var compilationJob = CompilationJob.CreateFromString("input", source); var result = Compiler.Compile(compilationJob); Assert.Empty(result.Diagnostics); Assert.Equal(2, result.Declarations.Count()); // Both declarations that resulted from the compile should be functions found on line 1 foreach (var decl in result.Declarations) { Assert.Equal(3, decl.Range.Start.Line); Assert.IsType <FunctionType>(decl.Type); } dialogue.SetProgram(result.Program); stringTable = result.StringTable; RunStandardTestcase(); }
public void TestTypeConversion() { var source = CreateTestNode(@" string + string(number): {""1"" + string(1)} string + string(bool): {""1"" + string(true)} number + number(string): {1 + number(""1"")} number + number(bool): {1 + number(true)} bool and bool(string): {true and bool(""true"")} bool and bool(number): {true and bool(1)} "); testPlan = new TestPlanBuilder() .AddLine("string + string(number): 11") .AddLine("string + string(bool): 1True") .AddLine("number + number(string): 2") .AddLine("number + number(bool): 2") .AddLine("bool and bool(string): True") .AddLine("bool and bool(number): True") .GetPlan(); var result = Compiler.Compile(CompilationJob.CreateFromString("input", source, dialogue.Library)); Assert.Empty(result.Diagnostics); dialogue.SetProgram(result.Program); stringTable = result.StringTable; RunStandardTestcase(); }
public void TestImportingVariableDeclarations() { var source = CreateTestNode(@" <<set $int = 6>> // no error; declaration is imported "); var declarations = new[] { new Declaration { Name = "$int", Type = BuiltinTypes.Number, DefaultValue = 0, } }; CompilationJob compilationJob = CompilationJob.CreateFromString("input", source); // Provide the declarations compilationJob.VariableDeclarations = declarations; // Should compile with no errors because $int was declared var result = Compiler.Compile(compilationJob); Assert.Empty(result.Diagnostics); // No variables are declared in the source code, so we should // expect an empty collection of variable declarations Assert.Empty(result.Declarations); }
[InlineData(@"{$str}")] // in inline expressions public void TestExpressionsAllowsUsingUndeclaredVariables(string testSource) { var source = CreateTestNode($@" {testSource} "); Compiler.Compile(CompilationJob.CreateFromString("input", source)); }
public void TestExplicitTypesMustMatchValue(string test) { var source = CreateTestNode(test); var result = Compiler.Compile(CompilationJob.CreateFromString("input", source, dialogue.Library)); Assert.Collection(result.Diagnostics, p => Assert.Matches(@"Type \w+ does not match", p.Message)); }
public void TestInvalidFunctionCall() { var source = CreateTestNode("<<if someFunction(>><<endif>>"); var result = Compiler.Compile(CompilationJob.CreateFromString("<input>", source)); Assert.Collection(result.Diagnostics, d => Assert.Contains(@"Unexpected "">>"" while reading a function call", d.Message)); }
public void TestMalformedIfStatement() { var source = CreateTestNode(@"<<if true>> // error: no endif"); var result = Compiler.Compile(CompilationJob.CreateFromString("<input>", source)); Assert.Collection(result.Diagnostics, d => Assert.Contains("Expected an <<endif>> to match the <<if>> statement on line 3", d.Message)); }
public void TestExplicitTypesMustMatchValue(string test) { var source = CreateTestNode(test); var result = Compiler.Compile(CompilationJob.CreateFromString("input", source, dialogue.Library)); Assert.Collection(result.Diagnostics, diag => Assert.Matches(@"Type \w+ does not match", diag.Message), diag => Assert.Matches(@"Can't figure out the type of variable \$\w+ given its context. Specify its type with a <<declare>> statement.", diag.Message)); }
public void TestFailingFunctionDeclarationParameterType() { dialogue.Library.RegisterFunction("func_invalid_param", (List <int> listOfInts) => true); var source = CreateTestNode(@"Hello"); var result = Compiler.Compile(CompilationJob.CreateFromString("input", source, dialogue.Library)); Assert.Collection(result.Diagnostics, p => Assert.Contains("parameter listOfInts's type (System.Collections.Generic.List`1[System.Int32]) cannot be used in Yarn functions", p.Message)); }
public void TestNullNotAllowed() { var source = CreateTestNode(@" <<declare $err = null>> // error, null not allowed "); var result = Compiler.Compile(CompilationJob.CreateFromString("input", source)); Assert.Collection(result.Diagnostics, p => Assert.Contains("Null is not a permitted type", p.Message)); }
public void TestExplicitTypes() { var source = CreateTestNode(@" <<declare $str = ""hello"" as string>> <<declare $int = 1 as number>> <<declare $bool = false as bool>> "); Compiler.Compile(CompilationJob.CreateFromString("input", source, dialogue.Library)); }
[InlineData(@"{$str + 1}")] // in inline expressions public void TestExpressionsAllowsUsingUndeclaredVariables(string testSource) { var source = CreateTestNode($@" {testSource} "); var result = Compiler.Compile(CompilationJob.CreateFromString("input", source)); Assert.Empty(result.Diagnostics); }
public void TestExpressionsDisallowMismatchedTypes() { var source = CreateTestNode(@" <<declare $int = 5>> <<set $int = ""5"">> // error, can't assign string to a variable declared int "); var result = Compiler.Compile(CompilationJob.CreateFromString("input", source)); Assert.Collection(result.Diagnostics, p => Assert.Contains("$int (Number) cannot be assigned a String", p.Message)); }
public void TestExplicitTypesMustMatchValue(string test) { var source = CreateTestNode(test); var ex = Assert.Throws <TypeException>(() => { var result = Compiler.Compile(CompilationJob.CreateFromString("input", source, dialogue.Library)); }); Assert.Matches(@"Type \w+ does not match", ex.Message); }
public void TestFailingFunctionDeclarationParameterType() { dialogue.Library.RegisterFunction("func_invalid_param", (List <int> i) => true); var source = CreateTestNode(@"Hello"); Assert.Throws <TypeException>(() => { Compiler.Compile(CompilationJob.CreateFromString("input", source, dialogue.Library)); }); }
public void TestMultipleImplicitRedeclarationsOfFunctionParameterTypeFail() { var source = CreateTestNode(@" {func(1)} {func(true)} // wrong type of parameter (previous decl had number) "); var result = Compiler.Compile(CompilationJob.CreateFromString("input", source)); Assert.Collection(result.Diagnostics, p => Assert.Contains("expects a Number, not a Bool", p.Message)); }
public void TestMultipleImplicitRedeclarationsOfFunctionParameterCountFail() { var source = CreateTestNode(@" {func(1)} {func(2, 2)} // wrong number of parameters (previous decl had 1) "); var result = Compiler.Compile(CompilationJob.CreateFromString("input", source)); Assert.Collection(result.Diagnostics, p => Assert.Contains("expects 1 parameter, but received 2", p.Message)); }
void TestVariableDeclarationsDisallowDuplicates() { var source = CreateTestNode(@" <<declare $int = 5>> <<declare $int = 6>> // error! redeclaration of $int "); var result = Compiler.Compile(CompilationJob.CreateFromString("input", source)); Assert.Collection(result.Diagnostics, p => Assert.Contains("$int has already been declared", p.Message)); }
public void TestFailingFunctionDeclarationReturnType() { dialogue.Library.RegisterFunction("func_invalid_return", () => new List <int> { 1, 2, 3 }); var source = CreateTestNode(@"Hello"); var result = Compiler.Compile(CompilationJob.CreateFromString("input", source, dialogue.Library)); Assert.Collection(result.Diagnostics, p => Assert.Contains("not a valid return type", p.Message)); }
public void TestEmptyCommand() { var source = CreateTestNode(@" <<>> "); var result = Compiler.Compile(CompilationJob.CreateFromString("<input>", source)); Assert.Collection(result.Diagnostics, d => Assert.Contains("Command text expected", d.Message) ); }
public void TestNullNotAllowed() { var source = CreateTestNode(@" <<declare $err = null>> // error, null not allowed "); var ex = Assert.Throws <TypeException>(() => { Compiler.Compile(CompilationJob.CreateFromString("input", source)); }); Assert.Contains("Null is not a permitted type", ex.Message); }
public void TestFailingFunctionDeclarationReturnType() { dialogue.Library.RegisterFunction("func_invalid_return", () => new List <int> { 1, 2, 3 }); var source = CreateTestNode(@"Hello"); Assert.Throws <TypeException>(() => { Compiler.Compile(CompilationJob.CreateFromString("input", source, dialogue.Library)); }); }
public void TestMultipleImplicitRedeclarationsOfFunctionParameterCountFail() { var source = CreateTestNode(@" {func(1)} {func(2, 2)} // wrong number of parameters (previous decl had 1) "); var ex = Assert.Throws <TypeException>(() => { Compiler.Compile(CompilationJob.CreateFromString("input", source)); }); Assert.Contains("expects 1 parameter, but received 2", ex.Message); }
public void TestMultipleImplicitRedeclarationsOfFunctionParameterTypeFail() { var source = CreateTestNode(@" {func(1)} {func(true)} // wrong type of parameter (previous decl had number) "); var ex = Assert.Throws <TypeException>(() => { Compiler.Compile(CompilationJob.CreateFromString("input", source)); }); Assert.Contains("expects a Number, not a Bool", ex.Message); }
public void TestImplicitFunctionDeclarations() { var source = CreateTestNode(@" {func_void_bool()} {func_void_bool() and bool(func_void_bool())} { 1 + func_void_int() } { ""he"" + func_void_str() } {func_int_bool(1)} {true and func_int_bool(1)} {func_bool_bool(false)} {true and func_bool_bool(false)} {func_str_bool(""hello"")} {true and func_str_bool(""hello"")} "); dialogue.Library.RegisterFunction("func_void_bool", () => true); dialogue.Library.RegisterFunction("func_void_int", () => 1); dialogue.Library.RegisterFunction("func_void_str", () => "llo"); dialogue.Library.RegisterFunction("func_int_bool", (int i) => true); dialogue.Library.RegisterFunction("func_bool_bool", (bool b) => true); dialogue.Library.RegisterFunction("func_str_bool", (string s) => true); testPlan = new TestPlanBuilder() .AddLine("True") .AddLine("True") .AddLine("2") .AddLine("hello") .AddLine("True") .AddLine("True") .AddLine("True") .AddLine("True") .AddLine("True") .AddLine("True") .GetPlan(); // the library is NOT attached to this compilation job; all // functions will be implicitly declared var compilationJob = CompilationJob.CreateFromString("input", source); var result = Compiler.Compile(compilationJob); Assert.Empty(result.Diagnostics); dialogue.SetProgram(result.Program); stringTable = result.StringTable; RunStandardTestcase(); }
public void TestLineTagsAreAdded() { // Arrange var originalText = @"title: Program --- // A comment. No line tag is added. A single line, with no line tag. A single line, with a line tag. #line:expected_abc123 -> An option, with no line tag. -> An option, with a line tag. #line:expected_def456 A line with no tag, but a comment at the end. // a comment A line with a tag, and a comment. #line:expected_ghi789 // a comment // A comment with no text: // // A comment with a single space: // ==="; // Act var output = Utility.AddTagsToLines(originalText); var compilationJob = CompilationJob.CreateFromString("input", output); compilationJob.CompilationType = CompilationJob.Type.StringsOnly; var compilationResult = Compiler.Compile(compilationJob); // Assert var lineTagRegex = new Regex(@"#line:\w+"); var lineTagAfterComment = new Regex(@"\/\/.*#line:\w+"); // Ensure that the right number of tags in total is present var expectedExistingTags = 3; var expectedNewTags = 3; var expectedTotalTags = expectedExistingTags + expectedNewTags; Assert.Equal(expectedTotalTags, lineTagRegex.Matches(output).Count); // No tags were added after a comment foreach (var line in output.Split('\n')) { Assert.False(lineTagAfterComment.IsMatch(line), $"'{line}' should not contain a tag after a comment"); } var expectedResults = new (string tag, string line)[] {
public void TestImplicitVariableDeclarations(string value, string typeName) { var source = CreateTestNode($@" <<set $v = {value}>> "); var result = Compiler.Compile(CompilationJob.CreateFromString("<input>", source)); Assert.Empty(result.Diagnostics); var declarations = result.Declarations.Where(d => d.Name == "$v"); Assert.Collection(declarations, d => Assert.Equal(d.Type.Name, typeName)); }