Ejemplo n.º 1
0
        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();
        }
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
        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);
        }
Ejemplo n.º 4
0
        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();
        }
Ejemplo n.º 5
0
        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();
        }
Ejemplo n.º 6
0
        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);
        }
Ejemplo n.º 7
0
        [InlineData(@"{$str}")]                // in inline expressions
        public void TestExpressionsAllowsUsingUndeclaredVariables(string testSource)
        {
            var source = CreateTestNode($@"
            {testSource}
            ");

            Compiler.Compile(CompilationJob.CreateFromString("input", source));
        }
Ejemplo n.º 8
0
        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));
        }
Ejemplo n.º 9
0
        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));
        }
Ejemplo n.º 10
0
        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));
        }
Ejemplo n.º 11
0
        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));
        }
Ejemplo n.º 12
0
        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));
        }
Ejemplo n.º 13
0
        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));
        }
Ejemplo n.º 14
0
        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));
        }
Ejemplo n.º 15
0
        [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);
        }
Ejemplo n.º 16
0
        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));
        }
Ejemplo n.º 17
0
        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);
        }
Ejemplo n.º 18
0
        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));
            });
        }
Ejemplo n.º 19
0
        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));
        }
Ejemplo n.º 20
0
        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));
        }
Ejemplo n.º 21
0
        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));
        }
Ejemplo n.º 22
0
        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));
        }
Ejemplo n.º 23
0
        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)
                              );
        }
Ejemplo n.º 24
0
        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);
        }
Ejemplo n.º 25
0
        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));
            });
        }
Ejemplo n.º 26
0
        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);
        }
Ejemplo n.º 27
0
        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);
        }
Ejemplo n.º 28
0
        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();
        }
Ejemplo n.º 29
0
        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)[] {
Ejemplo n.º 30
0
        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));
        }