예제 #1
0
        public void TestPropertyInheritance()
        {
            var scriptObject = new ScriptObject
            {
                { "a", new MyObject {
                      PropertyA = "ClassA"
                  } },
                { "b", new MyObject2 {
                      PropertyA = "ClassB", PropertyC = "ClassB-PropC"
                  } }
            };

            var context = new TemplateContext();

            context.PushGlobal(scriptObject);

            var result = Template.Parse("{{a.property_a}}-{{b.property_a}}-{{b.property_c}}").Render(context);

            EqualityCompareResult compareResult = TextAssert.Equal("ClassA-ClassB-ClassB-PropC", result);

            if (compareResult.VerboseMessage != null && compareResult.VerboseMessage.Count > 0)
            {
                foreach (string vmsg in compareResult.VerboseMessage)
                {
                    _output.WriteLine(vmsg);
                }
            }
            Assert.True(compareResult.IsEqual);
        }
예제 #2
0
        public void TestFrontMatter()
        {
            var options = new LexerOptions()
            {
                Mode = ScriptMode.FrontMatterAndContent
            };
            var input = @"+++
variable = 1
name = 'yes'
+++
This is after the frontmatter: {{ name }}
{{
variable + 1
}}";

            input = input.Replace("\r\n", "\n");
            var template = ParseTemplate(_output, input, options);

            // Make sure that we have a front matter
            Assert.NotNull(template.Page.FrontMatter);

            var context = new TemplateContext();

            // Evaluate front-matter
            var frontResult = context.Evaluate(template.Page.FrontMatter);

            Assert.Null(frontResult);

            // Evaluate page-content
            context.Evaluate(template.Page);
            var pageResult = context.Output.ToString();

            EqualityCompareResult compareResult = TextAssert.Equal("This is after the frontmatter: yes\n2", pageResult);

            if (compareResult.VerboseMessage != null && compareResult.VerboseMessage.Count > 0)
            {
                foreach (string vmsg in compareResult.VerboseMessage)
                {
                    _output.WriteLine(vmsg);
                }
            }
            Assert.True(compareResult.IsEqual);
        }
예제 #3
0
        public void TestDynamicVariable()
        {
            var context = new TemplateContext
            {
                TryGetVariable = (TemplateContext templateContext, SourceSpan span, ScriptVariable variable, out object value) =>
                {
                    value = null;
                    if (variable.Name == "myvar")
                    {
                        value = "yes";
                        return(true);
                    }
                    return(false);
                }
            };

            {
                var template = Template.Parse("Test with a dynamic {{ myvar }}");
                context.Evaluate(template.Page);
                var result = context.Output.ToString();

                EqualityCompareResult compareResult = TextAssert.Equal("Test with a dynamic yes", result);
                if (compareResult.VerboseMessage != null && compareResult.VerboseMessage.Count > 0)
                {
                    foreach (string vmsg in compareResult.VerboseMessage)
                    {
                        _output.WriteLine(vmsg);
                    }
                }
                Assert.True(compareResult.IsEqual);
            }

            {
                // Test StrictVariables
                var template = Template.Parse("Test with a dynamic {{ myvar2 }}");
                context.StrictVariables = true;
                var exception = Assert.Throws <ScriptRuntimeException>(() => context.Evaluate(template.Page));
                var result    = exception.ToString();
                var check     = string.Format(SRS.VariableNotFound, "myvar2");
                Assert.True(result.Contains(check), $"The exception string `{result}` does not contain the expected value");
            }
        }
예제 #4
0
        public void TestNullableArgument()
        {
            var template  = Template.Parse("{{ tester 'input1' 1 }}");
            var context   = new TemplateContext();
            var testerObj = new ScriptObjectWithNullable();

            context.PushGlobal(testerObj);
            var result = template.Render(context);

            EqualityCompareResult compareResult = TextAssert.Equal("input1 Value: 1", result);

            if (compareResult.VerboseMessage != null && compareResult.VerboseMessage.Count > 0)
            {
                foreach (string vmsg in compareResult.VerboseMessage)
                {
                    _output.WriteLine(vmsg);
                }
            }
            Assert.True(compareResult.IsEqual);
        }
예제 #5
0
        public void TestJekyllInclude()
        {
            var input    = "{% include /this/is/a/test.htm %}";
            var template = Template.ParseLiquid(input, lexerOptions: new LexerOptions()
            {
                EnableIncludeImplicitString = true, Mode = ScriptMode.Liquid
            });
            var context = new TemplateContext {
                TemplateLoader = new LiquidCustomTemplateLoader()
            };
            var result = template.Render(context);
            EqualityCompareResult compareResult = TextAssert.Equal("/this/is/a/test.htm", result);

            if (compareResult.VerboseMessage != null && compareResult.VerboseMessage.Count > 0)
            {
                foreach (string vmsg in compareResult.VerboseMessage)
                {
                    _output.WriteLine(vmsg);
                }
            }
            Assert.True(compareResult.IsEqual);
        }
예제 #6
0
        public void TestDynamicMember()
        {
            var template = Template.Parse("Test with a dynamic {{ a.myvar }}");

            var globalObject = new ScriptObject();

            globalObject.SetValue("a", new ScriptObject(), true);

            var context = new TemplateContext
            {
                TryGetMember = (TemplateContext localContext, SourceSpan span, object target, string member, out object value) =>
                {
                    value = null;
                    if (member == "myvar")
                    {
                        value = "yes";
                        return(true);
                    }
                    return(false);
                }
            };

            context.PushGlobal(globalObject);
            context.Evaluate(template.Page);
            var result = context.Output.ToString();

            EqualityCompareResult compareResult = TextAssert.Equal("Test with a dynamic yes", result);

            if (compareResult.VerboseMessage != null && compareResult.VerboseMessage.Count > 0)
            {
                foreach (string vmsg in compareResult.VerboseMessage)
                {
                    _output.WriteLine(vmsg);
                }
            }
            Assert.True(compareResult.IsEqual);
        }
예제 #7
0
        public static TemplateCompareResult TestTemplate(string expected, string input, bool isLiquid = false, bool isRoundtripTest = false, bool supportExactRoundtrip = true, object model = null, bool specialLiquid = false)
        {
            var parserOptions = new ParserOptions()
            {
                ConvertLiquidFunctions = isLiquid
            };
            var lexerOptions = new LexerOptions()
            {
                Mode = isLiquid ? ScriptMode.Liquid : ScriptMode.Default
            };

            if (isRoundtripTest)
            {
                lexerOptions.KeepTrivia = true;
            }

            if (specialLiquid)
            {
                parserOptions.ExpressionDepthLimit = 500;
            }

            List <string> tokensDesc = new List <string>();
            var           lexer      = new Lexer(input, options: lexerOptions);

            foreach (var token in lexer)
            {
                tokensDesc.Add($"{token.Type}: {token.GetText(input)}");
            }

            string        roundtripText  = null;
            List <string> verboseMessage = new List <string>();

            // We loop first on input text, then on rountrip
            while (true)
            {
                bool isRoundtrip = roundtripText != null;
                bool hasErrors   = false;
                if (isRoundtrip)
                {
                    verboseMessage.Add("Rountrip");
                    verboseMessage.Add("======================================");
                    verboseMessage.Add(roundtripText);
                    lexerOptions.Mode = ScriptMode.Default;

                    if (lexerOptions.Mode == ScriptMode.Default && !isLiquid && supportExactRoundtrip)
                    {
                        verboseMessage.Add("Checking Exact Roundtrip - Input");
                        verboseMessage.Add("======================================");
                        EqualityCompareResult equalResult = TextAssert.Equal(input, roundtripText);
                        if (equalResult.VerboseMessage != null && equalResult.VerboseMessage.Count > 0)
                        {
                            verboseMessage.AddRange(equalResult.VerboseMessage);
                        }
                        if (equalResult.IsEqual == false)
                        {
                            return(new TemplateCompareResult()
                            {
                                Tokens = tokensDesc,
                                IsEqual = false,
                                VerboseMessage = verboseMessage,
                                DebugCode = "INPUT_ROUNDTRIP_TEXT_NOT_EQUAL"
                            });
                        }
                    }
                    input = roundtripText;
                }
                else
                {
                    verboseMessage.Add("Input");
                    verboseMessage.Add("======================================");
                    verboseMessage.Add(input);
                }

                var template = Template.Parse(input, "text", parserOptions, lexerOptions);

                var result = string.Empty;
                if (template.HasErrors)
                {
                    hasErrors = true;
                    for (int i = 0; i < template.Messages.Count; i++)
                    {
                        var message = template.Messages[i];
                        if (i > 0)
                        {
                            result += "\n";
                        }
                        result += message;
                    }
                    if (specialLiquid)
                    {
                        throw new InvalidOperationException("Parser errors: " + result);
                    }
                }
                else
                {
                    if (isRoundtripTest)
                    {
                        result = template.ToText();
                    }
                    else
                    {
                        if (template.Page == null)
                        {
                            return(new TemplateCompareResult()
                            {
                                Tokens = tokensDesc,
                                IsEqual = false,
                                VerboseMessage = verboseMessage,
                                DebugCode = "PAGE_IS_NULL",
                                Result = result,
                                Expected = expected
                            });
                        }

                        if (!isRoundtrip)
                        {
                            // Dumps the rountrip version
                            var lexerOptionsForTrivia = lexerOptions;
                            lexerOptionsForTrivia.KeepTrivia = true;
                            var templateWithTrivia = Template.Parse(input, "input", parserOptions, lexerOptionsForTrivia);
                            roundtripText = templateWithTrivia.ToText();
                        }

                        try
                        {
                            // Setup a default model context for the tests
                            if (model == null)
                            {
                                var scriptObj = new ScriptObject
                                {
                                    ["page"] = new ScriptObject {
                                        ["title"] = "This is a title"
                                    },
                                    ["user"] = new ScriptObject {
                                        ["name"] = "John"
                                    },
                                    ["product"] = new ScriptObject {
                                        ["title"] = "Orange", ["type"] = "fruit"
                                    },
                                    ["products"] = new ScriptArray()
                                    {
                                        new ScriptObject {
                                            ["title"] = "Orange", ["type"] = "fruit"
                                        },
                                        new ScriptObject {
                                            ["title"] = "Banana", ["type"] = "fruit"
                                        },
                                        new ScriptObject {
                                            ["title"] = "Apple", ["type"] = "fruit"
                                        },
                                        new ScriptObject {
                                            ["title"] = "Computer", ["type"] = "electronics"
                                        },
                                        new ScriptObject {
                                            ["title"] = "Mobile Phone", ["type"] = "electronics"
                                        },
                                        new ScriptObject {
                                            ["title"] = "Table", ["type"] = "furniture"
                                        },
                                        new ScriptObject {
                                            ["title"] = "Sofa", ["type"] = "furniture"
                                        },
                                    }
                                };
                                scriptObj.Import(typeof(SpecialFunctionProvider));
                                model = scriptObj;
                            }

                            var context = isLiquid
                                ? new LiquidTemplateContext()
                            {
                                TemplateLoader = new LiquidCustomTemplateLoader()
                            }
                                : new TemplateContext()
                            {
                                TemplateLoader = new CustomTemplateLoader()
                            };

                            // We use a custom output to make sure that all output is using the "\n"
                            context.PushOutput(new TextWriterOutput(new StringWriter()
                            {
                                NewLine = "\n"
                            }));

                            var contextObj = new ScriptObject();
                            contextObj.Import(model);
                            context.PushGlobal(contextObj);

                            result = template.Render(context);
                        }
                        catch (Exception exception)
                        {
                            if (specialLiquid)
                            {
                                throw;
                            }
                            else
                            {
                                result = GetReason(exception);
                            }
                        }
                    }
                }

                var testContext = isRoundtrip ? "Roundtrip - " : String.Empty;

                verboseMessage.Add($"{testContext}Result");
                verboseMessage.Add("======================================");
                verboseMessage.Add(result);
                verboseMessage.Add($"{testContext}Expected");
                verboseMessage.Add("======================================");
                verboseMessage.Add(expected);

                EqualityCompareResult testEqualResult = TextAssert.Equal(expected, result);
                if (testEqualResult.VerboseMessage != null && testEqualResult.VerboseMessage.Count > 0)
                {
                    verboseMessage.AddRange(testEqualResult.VerboseMessage);
                }

                if (testEqualResult.IsEqual == false)
                {
                    return(new TemplateCompareResult
                    {
                        IsEqual = false,
                        VerboseMessage = verboseMessage,
                        DebugCode = "UNKNOWN",
                        Tokens = tokensDesc,
                        Result = result,
                        Expected = expected
                    });
                }

                if (isRoundtripTest || isRoundtrip || hasErrors)
                {
                    break;
                }
            }

            return(new TemplateCompareResult
            {
                IsEqual = true,
                VerboseMessage = verboseMessage,
                DebugCode = "",
                Tokens = tokensDesc
            });
        }
예제 #8
0
        public void TestFrontMatterOnly()
        {
            var options = new ParserOptions();

            var input = @"+++
variable = 1
name = 'yes'
+++
This is after the frontmatter: {{ name }}
{{
variable + 1
}}";

            input = input.Replace("\r\n", "\n");

            var lexer = new Lexer(input, null, new LexerOptions()
            {
                Mode = ScriptMode.FrontMatterOnly
            });
            var parser = new Parser(lexer, options);

            var page = parser.Run();

            foreach (var message in parser.Messages)
            {
                _output.WriteLine(message.Message);
            }
            Assert.False(parser.HasErrors);

            // Check that the parser finished parsing on the first code exit }}
            // and hasn't tried to run the lexer on the remaining text
            Assert.Equal(new TextPosition(30, 3, 0), parser.CurrentSpan.Start);
            Assert.Equal(new TextPosition(33, 3, 3), parser.CurrentSpan.End);

            var startPositionAfterFrontMatter = parser.CurrentSpan.End.NextLine();

            // Make sure that we have a front matter
            Assert.NotNull(page.FrontMatter);
            Assert.Null(page.Body);

            var context = new TemplateContext();

            // Evaluate front-matter
            var frontResult = context.Evaluate(page.FrontMatter);

            Assert.Null(frontResult);

            lexer = new Lexer(input, null, new LexerOptions()
            {
                StartPosition = startPositionAfterFrontMatter
            });
            parser = new Parser(lexer);
            page   = parser.Run();
            foreach (var message in parser.Messages)
            {
                _output.WriteLine(message.Message);
            }
            Assert.False(parser.HasErrors);
            context.Evaluate(page);
            var pageResult = context.Output.ToString();

            EqualityCompareResult compareResult = TextAssert.Equal("This is after the frontmatter: yes\n2", pageResult);

            if (compareResult.VerboseMessage != null && compareResult.VerboseMessage.Count > 0)
            {
                foreach (string vmsg in compareResult.VerboseMessage)
                {
                    _output.WriteLine(vmsg);
                }
            }
            Assert.True(compareResult.IsEqual);
        }
예제 #9
0
        public void TestJson()
        {
            System.Data.DataTable dataTable = new System.Data.DataTable();
            dataTable.Columns.Add("Column1");
            dataTable.Columns.Add("Column2");

            System.Data.DataRow dataRow = dataTable.NewRow();
            dataRow["Column1"] = "Hello";
            dataRow["Column2"] = "World";
            dataTable.Rows.Add(dataRow);

            dataRow            = dataTable.NewRow();
            dataRow["Column1"] = "Bonjour";
            dataRow["Column2"] = "le monde";
            dataTable.Rows.Add(dataRow);

            string json = JsonConvert.SerializeObject(dataTable);

            _output.WriteLine("Json: " + json);

            var parsed = JsonConvert.DeserializeObject(json);

            _output.WriteLine("Parsed: " + parsed);

            string myTemplate = @"
[
  { {{ for tbr in tb }}
    ""N"": {{tbr.Column1}},
    ""M"": {{tbr.Column2}}
    {{ end }}
  },
]
{{tb}}
";

            // Parse the template
            var template = Template.Parse(myTemplate);

            // Render
            var context = new TemplateContext {
                MemberRenamer = member => member.Name
            };
            var scriptObject = new ScriptObject();

            scriptObject.Import(new { tb = parsed });
            context.PushGlobal(scriptObject);
            var result = template.Render(context);

            context.PopGlobal();

            var expected =
                @"
[
  { 
    ""N"": Hello,
    ""M"": World
    
    ""N"": Bonjour,
    ""M"": le monde
    
  },
]
[[[Hello], [World]], [[Bonjour], [le monde]]]
";

            TextAssert.Equal(expected, result);
        }