Пример #1
0
        public void Execute_AutomaticallyOverridesImportedSingleLineSinglyOccurringDirective_MainDocument()
        {
            // Arrange
            var directive = DirectiveDescriptor.CreateSingleLineDirective(
                "custom",
                builder =>
            {
                builder.AddStringToken();
                builder.Usage = DirectiveUsage.FileScopedSinglyOccurring;
            });
            var phase  = new DefaultRazorIntermediateNodeLoweringPhase();
            var engine = RazorProjectEngine.CreateEmpty(b =>
            {
                b.Phases.Add(phase);
                b.Features.Add(new DefaultRazorCodeGenerationOptionsFeature(designTime: false));
                b.AddDirective(directive);
            });
            var options      = RazorParserOptions.Create(builder => builder.Directives.Add(directive));
            var importSource = TestRazorSourceDocument.Create("@custom \"hello\"", filePath: "import.cshtml");
            var codeDocument = TestRazorCodeDocument.Create("@custom \"world\"");

            codeDocument.SetSyntaxTree(RazorSyntaxTree.Parse(codeDocument.Source, options));
            codeDocument.SetImportSyntaxTrees(new[] { RazorSyntaxTree.Parse(importSource, options) });

            // Act
            phase.Execute(codeDocument);

            // Assert
            var documentNode     = codeDocument.GetDocumentIntermediateNode();
            var customDirectives = documentNode.FindDirectiveReferences(directive);
            var customDirective  = (DirectiveIntermediateNode)Assert.Single(customDirectives).Node;
            var stringToken      = Assert.Single(customDirective.Tokens);

            Assert.Equal("\"world\"", stringToken.Content);
        }
Пример #2
0
        public void Lower_HtmlWithConditionalAttributes()
        {
            // Arrange
            var codeDocument = TestRazorCodeDocument.Create(@"
<html>
    <body>
        <span val=""@Hello World"" />
    </body>
</html>");

            // Act
            var documentNode = Lower(codeDocument);

            // Assert
            Children(documentNode,
                     n => Html(
                         @"
<html>
    <body>
        <span", n),

                     n => ConditionalAttribute(
                         prefix: " val=\"",
                         name: "val",
                         suffix: "\"",
                         node: n,
                         valueValidators: new Action <IntermediateNode>[]
            {
                value => CSharpExpressionAttributeValue(string.Empty, "Hello", value),
                value => LiteralAttributeValue(" ", "World", value)
            }),
                     n => Html(@" />
    </body>
</html>", n));
        }
Пример #3
0
        public void Execute_ErrorsForRazorBlockFileScopedSinglyOccurringDirectives()
        {
            // Arrange
            var directive = DirectiveDescriptor.CreateRazorBlockDirective("custom", b => b.Usage = DirectiveUsage.FileScopedSinglyOccurring);
            var phase     = new DefaultRazorIntermediateNodeLoweringPhase();
            var engine    = RazorProjectEngine.CreateEmpty(b =>
            {
                b.Phases.Add(phase);
                b.Features.Add(new DefaultRazorCodeGenerationOptionsFeature(designTime: false));
                b.AddDirective(directive);
            });
            var options      = RazorParserOptions.Create(builder => builder.Directives.Add(directive));
            var importSource = TestRazorSourceDocument.Create("@custom { }", filePath: "import.cshtml");
            var codeDocument = TestRazorCodeDocument.Create("<p>NonDirective</p>");

            codeDocument.SetSyntaxTree(RazorSyntaxTree.Parse(codeDocument.Source, options));
            codeDocument.SetImportSyntaxTrees(new[] { RazorSyntaxTree.Parse(importSource, options) });
            var expectedDiagnostic = RazorDiagnosticFactory.CreateDirective_BlockDirectiveCannotBeImported("custom");

            // Act
            phase.Execute(codeDocument);

            // Assert
            var documentNode = codeDocument.GetDocumentIntermediateNode();
            var directives   = documentNode.Children.OfType <DirectiveIntermediateNode>();

            Assert.Empty(directives);
            var diagnostic = Assert.Single(documentNode.GetAllDiagnostics());

            Assert.Equal(expectedDiagnostic, diagnostic);
        }
Пример #4
0
        public void Lower_TagHelpers()
        {
            // Arrange
            var codeDocument = TestRazorCodeDocument.Create(@"@addTagHelper *, TestAssembly
<span val=""@Hello World""></span>");
            var tagHelpers   = new[]
            {
                CreateTagHelperDescriptor(
                    tagName: "span",
                    typeName: "SpanTagHelper",
                    assemblyName: "TestAssembly")
            };

            // Act
            var documentNode = Lower(codeDocument, tagHelpers: tagHelpers);

            // Assert
            Children(documentNode,
                     n => Directive(
                         SyntaxConstants.CSharp.AddTagHelperKeyword,
                         n,
                         v => DirectiveToken(DirectiveTokenKind.String, "*, TestAssembly", v)),
                     n => TagHelper(
                         "span",
                         TagMode.StartTagAndEndTag,
                         tagHelpers,
                         n,
                         c => Assert.IsType <TagHelperBodyIntermediateNode>(c),
                         c => TagHelperHtmlAttribute(
                             "val",
                             AttributeStructure.DoubleQuotes,
                             c,
                             v => CSharpExpressionAttributeValue(string.Empty, "Hello", v),
                             v => LiteralAttributeValue(" ", "World", v))));
        }
Пример #5
0
        public void TryComputeNamespace_ForNonRelatedFiles_UsesNamespaceVerbatim()
        {
            // Arrange
            var sourceDocument = TestRazorSourceDocument.Create(
                filePath: "c:\\foo\\bar\\bleh.cshtml",
                relativePath: "bar\\bleh.cshtml");
            var codeDocument = TestRazorCodeDocument.Create(sourceDocument, Array.Empty <RazorSourceDocument>());

            codeDocument.SetSyntaxTree(RazorSyntaxTree.Parse(sourceDocument, RazorParserOptions.Create(options =>
            {
                options.Directives.Add(NamespaceDirective.Directive);
            })));

            var importSourceDocument = TestRazorSourceDocument.Create(
                content: "@namespace Base",
                filePath: "c:\\foo\\baz\\bleh.cshtml",
                relativePath: "baz\\bleh.cshtml");

            codeDocument.SetImportSyntaxTrees(new[]
            {
                RazorSyntaxTree.Parse(importSourceDocument, RazorParserOptions.Create(options =>
                {
                    options.Directives.Add(NamespaceDirective.Directive);
                }))
            });

            // Act
            codeDocument.TryComputeNamespace(fallbackToRootNamespace: true, out var @namespace);

            // Assert
            Assert.Equal("Base", @namespace);
        }
Пример #6
0
        public void Lower_WithMultipleImports_SingleLineFileScopedSinglyOccurring()
        {
            // Arrange
            var source  = TestRazorSourceDocument.Create("<p>Hi!</p>");
            var imports = new[]
            {
                TestRazorSourceDocument.Create("@test value1"),
                TestRazorSourceDocument.Create("@test value2"),
            };

            var codeDocument = TestRazorCodeDocument.Create(source, imports);

            // Act
            var documentNode = Lower(codeDocument, b =>
            {
                b.AddDirective(DirectiveDescriptor.CreateDirective(
                                   "test",
                                   DirectiveKind.SingleLine,
                                   builder =>
                {
                    builder.AddMemberToken();
                    builder.Usage = DirectiveUsage.FileScopedSinglyOccurring;
                }));
            });

            // Assert
            Children(
                documentNode,
                n => Directive("test", n, c => DirectiveToken(DirectiveTokenKind.Member, "value2", c)),
                n => Html("<p>Hi!</p>", n));
        }
Пример #7
0
        public void TryComputeNamespace_RespectsNamespaceDirective()
        {
            // Arrange
            var sourceDocument = TestRazorSourceDocument.Create(
                content: "@namespace My.Custom.NS",
                filePath: "C:\\Hello\\Components\\Test.cshtml",
                relativePath: "\\Components\\Test.cshtml");
            var codeDocument = TestRazorCodeDocument.Create(sourceDocument, Array.Empty <RazorSourceDocument>());

            codeDocument.SetFileKind(FileKinds.Component);
            codeDocument.SetSyntaxTree(RazorSyntaxTree.Parse(sourceDocument, RazorParserOptions.Create(options =>
            {
                options.Directives.Add(NamespaceDirective.Directive);
            })));

            var documentNode = new DocumentIntermediateNode()
            {
                Options = RazorCodeGenerationOptions.Create(c =>
                {
                    c.RootNamespace = "Hello.World";
                })
            };

            codeDocument.SetDocumentIntermediateNode(documentNode);

            // Act
            codeDocument.TryComputeNamespace(fallbackToRootNamespace: true, out var @namespace);

            // Assert
            Assert.Equal("My.Custom.NS", @namespace);
        }
Пример #8
0
        public void TryComputeNamespace_ComputesNamespaceWithSuffix(string basePath, string relativePath, string expectedNamespace)
        {
            // Arrange
            var sourceDocument = TestRazorSourceDocument.Create(
                filePath: Path.Combine(basePath, relativePath),
                relativePath: relativePath);
            var codeDocument = TestRazorCodeDocument.Create(sourceDocument, Array.Empty <RazorSourceDocument>());

            codeDocument.SetSyntaxTree(RazorSyntaxTree.Parse(sourceDocument, RazorParserOptions.Create(options =>
            {
                options.Directives.Add(NamespaceDirective.Directive);
            })));

            var importRelativePath   = "_ViewImports.cshtml";
            var importSourceDocument = TestRazorSourceDocument.Create(
                content: "@namespace Base",
                filePath: Path.Combine(basePath, importRelativePath),
                relativePath: importRelativePath);

            codeDocument.SetImportSyntaxTrees(new[]
            {
                RazorSyntaxTree.Parse(importSourceDocument, RazorParserOptions.Create(options =>
                {
                    options.Directives.Add(NamespaceDirective.Directive);
                }))
            });

            // Act
            codeDocument.TryComputeNamespace(fallbackToRootNamespace: true, out var @namespace);

            // Assert
            Assert.Equal(expectedNamespace, @namespace);
        }
Пример #9
0
        public void Lower_HtmlWithDataDashAttributes()
        {
            // Arrange
            var codeDocument = TestRazorCodeDocument.Create(@"
<html>
    <body>
        <span data-val=""@Hello"" />
    </body>
</html>");

            // Act
            var documentNode = Lower(codeDocument);

            // Assert
            Children(documentNode,
                     n => Html(
                         @"
<html>
    <body>
        <span data-val=""", n),
                     n => CSharpExpression("Hello", n),
                     n => Html(@""" />
    </body>
</html>", n));
        }
Пример #10
0
        public void TryComputeNamespaceAndClass_PrefersOptionsFromCodeDocument_ComputesNamespaceAndClass()
        {
            // Arrange
            var sourceDocument = TestRazorSourceDocument.Create(filePath: "C:\\Hello\\Components\\Test.cshtml", relativePath: "\\Components\\Test.cshtml");
            var codeDocument   = TestRazorCodeDocument.Create(sourceDocument, Array.Empty <RazorSourceDocument>());

            codeDocument.SetCodeGenerationOptions(RazorCodeGenerationOptions.Create(c =>
            {
                c.RootNamespace = "World";
            }));
            var documentNode = new DocumentIntermediateNode()
            {
                Options = RazorCodeGenerationOptions.Create(c =>
                {
                    c.RootNamespace = "Hello";
                })
            };

            codeDocument.SetDocumentIntermediateNode(documentNode);

            // Act
            codeDocument.TryComputeNamespaceAndClass(out var @namespace, out var @class);

            // Assert
            Assert.Equal("World.Components", @namespace);
            Assert.Equal("Test", @class);
        }
Пример #11
0
        public void Execute_CollatesIRDocumentDiagnosticsFromSourceDocument()
        {
            // Arrange
            var phase        = new DefaultRazorCSharpLoweringPhase();
            var engine       = RazorEngine.CreateEmpty(b => b.Phases.Add(phase));
            var codeDocument = TestRazorCodeDocument.Create("<p class=@(");
            var options      = RazorCodeGenerationOptions.CreateDefault();
            var irDocument   = new DocumentIntermediateNode()
            {
                DocumentKind = "test",
                Target       = CodeTarget.CreateDefault(codeDocument, options),
                Options      = options,
            };
            var expectedDiagnostic = RazorDiagnostic.Create(
                new RazorDiagnosticDescriptor("1234", () => "I am an error.", RazorDiagnosticSeverity.Error),
                new SourceSpan("SomeFile.cshtml", 11, 0, 11, 1));

            irDocument.Diagnostics.Add(expectedDiagnostic);
            codeDocument.SetDocumentIntermediateNode(irDocument);

            // Act
            phase.Execute(codeDocument);

            // Assert
            var csharpDocument = codeDocument.GetCSharpDocument();
            var diagnostic     = Assert.Single(csharpDocument.Diagnostics);

            Assert.Same(expectedDiagnostic, diagnostic);
        }
        public void Execute_ParsesImports()
        {
            // Arrange
            var phase  = new DefaultRazorParsingPhase();
            var engine = RazorEngine.CreateEmpty((builder) =>
            {
                builder.Phases.Add(phase);
                builder.Features.Add(new DefaultRazorParserOptionsFeature(designTime: false, version: RazorLanguageVersion.Latest));
                builder.Features.Add(new MyParserOptionsFeature());
            });

            var imports = new[]
            {
                TestRazorSourceDocument.Create(),
                TestRazorSourceDocument.Create(),
            };

            var codeDocument = TestRazorCodeDocument.Create(TestRazorSourceDocument.Create(), imports);

            // Act
            phase.Execute(codeDocument);

            // Assert
            Assert.Collection(
                codeDocument.GetImportSyntaxTrees(),
                t => { Assert.Same(t.Source, imports[0]); Assert.Equal("test", Assert.Single(t.Options.Directives).Directive); },
                t => { Assert.Same(t.Source, imports[1]); Assert.Equal("test", Assert.Single(t.Options.Directives).Directive); });
        }
Пример #13
0
        public void TryComputeNamespace_RelativePathLongerThanFilePath_ReturnsNull()
        {
            // Arrange
            var sourceDocument = TestRazorSourceDocument.Create(filePath: "C:\\Hello\\Test.cshtml", relativePath: "Some\\invalid\\relative\\path\\Test.cshtml");
            var codeDocument   = TestRazorCodeDocument.Create(sourceDocument, Array.Empty <RazorSourceDocument>());

            // Act
            codeDocument.TryComputeNamespace(fallbackToRootNamespace: true, out var @namespace);

            // Assert
            Assert.Null(@namespace);
        }
Пример #14
0
        public void TryComputeNamespace_FilePathNull_ReturnsNull()
        {
            // Arrange
            var sourceDocument = TestRazorSourceDocument.Create(filePath: null, relativePath: "Test.cshtml");
            var codeDocument   = TestRazorCodeDocument.Create(sourceDocument, Array.Empty <RazorSourceDocument>());

            // Act
            codeDocument.TryComputeNamespace(fallbackToRootNamespace: true, out var @namespace);

            // Assert
            Assert.Null(@namespace);
        }
Пример #15
0
        public void Lower_HelloWorld()
        {
            // Arrange
            var codeDocument = TestRazorCodeDocument.Create("Hello, World!");

            // Act
            var documentNode = Lower(codeDocument);

            // Assert
            Children(documentNode,
                     n => Html("Hello, World!", n));
        }
Пример #16
0
        public void TryComputeNamespaceAndClass_RelativePathNull_ReturnsNull()
        {
            // Arrange
            var sourceDocument = TestRazorSourceDocument.Create(filePath: "C:\\Hello\\Test.cshtml", relativePath: null);
            var codeDocument   = TestRazorCodeDocument.Create(sourceDocument, Array.Empty <RazorSourceDocument>());

            // Act
            codeDocument.TryComputeNamespaceAndClass(out var @namespace, out var @class);

            // Assert
            Assert.Null(@namespace);
            Assert.Null(@class);
        }
Пример #17
0
        public void Lower_WithFunctions()
        {
            // Arrange
            var codeDocument = TestRazorCodeDocument.Create(@"@functions { public int Foo { get; set; }}");

            // Act
            var documentNode = Lower(codeDocument);

            // Assert
            Children(documentNode,
                     n => Directive(
                         "functions",
                         n,
                         c => Assert.IsType <CSharpCodeIntermediateNode>(c)));
        }
Пример #18
0
        public void TryComputeNamespace_ComputesNamespace()
        {
            // Arrange
            var sourceDocument = TestRazorSourceDocument.Create(filePath: "C:\\Hello\\Components\\Test.cshtml", relativePath: "\\Components\\Test.cshtml");
            var codeDocument   = TestRazorCodeDocument.Create(sourceDocument, Array.Empty <RazorSourceDocument>());

            codeDocument.SetCodeGenerationOptions(RazorCodeGenerationOptions.Create(c =>
            {
                c.RootNamespace = "Hello";
            }));

            // Act
            codeDocument.TryComputeNamespace(fallbackToRootNamespace: true, out var @namespace);

            // Assert
            Assert.Equal("Hello.Components", @namespace);
        }
Пример #19
0
        public void Lower_WithUsing()
        {
            // Arrange
            var codeDocument           = TestRazorCodeDocument.Create(@"@using System");
            var expectedSourceLocation = new SourceSpan(codeDocument.Source.FilePath, 1, 0, 1, 12);

            // Act
            var documentNode = Lower(codeDocument);

            // Assert
            Children(documentNode,
                     n =>
            {
                Using("System", n);
                Assert.Equal(expectedSourceLocation, n.Source);
            });
        }
Пример #20
0
        public void Lower_TagHelpersWithBoundAttribute()
        {
            // Arrange
            var codeDocument = TestRazorCodeDocument.Create(@"@addTagHelper *, TestAssembly
<input bound='foo' />");
            var tagHelpers   = new[]
            {
                CreateTagHelperDescriptor(
                    tagName: "input",
                    typeName: "InputTagHelper",
                    assemblyName: "TestAssembly",
                    attributes: new Action <BoundAttributeDescriptorBuilder>[]
                {
                    builder => builder
                    .Name("bound")
                    .PropertyName("FooProp")
                    .TypeName("System.String"),
                })
            };

            // Act
            var documentNode = Lower(codeDocument, tagHelpers: tagHelpers);

            // Assert
            Children(
                documentNode,
                n => Directive(
                    SyntaxConstants.CSharp.AddTagHelperKeyword,
                    n,
                    v => DirectiveToken(DirectiveTokenKind.String, "*, TestAssembly", v)),
                n => TagHelper(
                    "input",
                    TagMode.SelfClosing,
                    tagHelpers,
                    n,
                    c => Assert.IsType <TagHelperBodyIntermediateNode>(c),
                    c => SetTagHelperProperty(
                        "bound",
                        "FooProp",
                        AttributeStructure.SingleQuotes,
                        c,
                        v => Html("foo", v))));
        }
Пример #21
0
        public void TryComputeNamespace_NoRootNamespaceFallback_ReturnsNull()
        {
            // Arrange
            var sourceDocument = TestRazorSourceDocument.Create(filePath: "C:\\Hello\\Components\\Test.cshtml", relativePath: "\\Components\\Test.cshtml");
            var codeDocument   = TestRazorCodeDocument.Create(sourceDocument, Array.Empty <RazorSourceDocument>());
            var documentNode   = new DocumentIntermediateNode()
            {
                Options = RazorCodeGenerationOptions.Create(c =>
                {
                    c.RootNamespace = "Hello";
                })
            };

            codeDocument.SetDocumentIntermediateNode(documentNode);

            // Act
            codeDocument.TryComputeNamespace(fallbackToRootNamespace: false, out var @namespace);

            // Assert
            Assert.Null(@namespace);
        }
Пример #22
0
        public void TryComputeNamespace_SanitizesNamespaceName()
        {
            // Arrange
            var sourceDocument = TestRazorSourceDocument.Create(filePath: "C:\\Hello\\Components with space\\Test$name.cshtml", relativePath: "\\Components with space\\Test$name.cshtml");
            var codeDocument   = TestRazorCodeDocument.Create(sourceDocument, Array.Empty <RazorSourceDocument>());
            var documentNode   = new DocumentIntermediateNode()
            {
                Options = RazorCodeGenerationOptions.Create(c =>
                {
                    c.RootNamespace = "Hel?o.World";
                })
            };

            codeDocument.SetDocumentIntermediateNode(documentNode);

            // Act
            codeDocument.TryComputeNamespace(fallbackToRootNamespace: true, out var @namespace);

            // Assert
            Assert.Equal("Hel_o.World.Components_with_space", @namespace);
        }
Пример #23
0
        public void Lower_WithImports_AllowsIdenticalNamespacesInPrimaryDocument()
        {
            // Arrange
            var source  = TestRazorSourceDocument.Create(@"@using System.Threading.Tasks
@using System.Threading.Tasks");
            var imports = new[]
            {
                TestRazorSourceDocument.Create("@using System.Threading.Tasks"),
            };

            var codeDocument = TestRazorCodeDocument.Create(source, imports);

            // Act
            var documentNode = Lower(codeDocument);

            // Assert
            Children(
                documentNode,
                n => Using("System.Threading.Tasks", n),
                n => Using("System.Threading.Tasks", n));
        }
Пример #24
0
        public void Lower_WithImports_IgnoresBlockDirective()
        {
            // Arrange
            var source  = TestRazorSourceDocument.Create("<p>Hi!</p>");
            var imports = new[]
            {
                TestRazorSourceDocument.Create("@block token { }"),
            };

            var codeDocument = TestRazorCodeDocument.Create(source, imports);

            // Act
            var documentNode = Lower(codeDocument, b =>
            {
                b.AddDirective(DirectiveDescriptor.CreateDirective("block", DirectiveKind.RazorBlock, d => d.AddMemberToken()));
            });

            // Assert
            Children(
                documentNode,
                n => Html("<p>Hi!</p>", n));
        }
Пример #25
0
        public void Execute_CollatesSyntaxDiagnosticsFromSourceDocument()
        {
            // Arrange
            var phase  = new DefaultRazorIntermediateNodeLoweringPhase();
            var engine = RazorProjectEngine.CreateEmpty(b =>
            {
                b.Phases.Add(phase);
                b.Features.Add(new DefaultRazorCodeGenerationOptionsFeature(designTime: false));
            });
            var codeDocument = TestRazorCodeDocument.Create("<p class=@(");

            codeDocument.SetSyntaxTree(RazorSyntaxTree.Parse(codeDocument.Source));

            // Act
            phase.Execute(codeDocument);

            // Assert
            var documentNode = codeDocument.GetDocumentIntermediateNode();
            var diagnostic   = Assert.Single(documentNode.Diagnostics);

            Assert.Equal(@"The explicit expression block is missing a closing "")"" character.  Make sure you have a matching "")"" character for all the ""("" characters within this block, and that none of the "")"" characters are being interpreted as markup.",
                         diagnostic.GetMessage(CultureInfo.CurrentCulture));
        }
Пример #26
0
        public void Execute_DoesNotImportNonFileScopedSinglyOccurringDirectives_Block()
        {
            // Arrange
            var codeBlockDirective  = DirectiveDescriptor.CreateCodeBlockDirective("code", b => b.AddStringToken());
            var razorBlockDirective = DirectiveDescriptor.CreateRazorBlockDirective("razor", b => b.AddStringToken());
            var phase  = new DefaultRazorIntermediateNodeLoweringPhase();
            var engine = RazorProjectEngine.CreateEmpty(b =>
            {
                b.Phases.Add(phase);
                b.Features.Add(new DefaultRazorCodeGenerationOptionsFeature(designTime: false));
                b.AddDirective(codeBlockDirective);
                b.AddDirective(razorBlockDirective);
            });
            var options = RazorParserOptions.Create(builder =>
            {
                builder.Directives.Add(codeBlockDirective);
                builder.Directives.Add(razorBlockDirective);
            });
            var importSource = TestRazorSourceDocument.Create(
                @"@code ""code block"" { }
@razor ""razor block"" { }",
                filePath: "testImports.cshtml");
            var codeDocument = TestRazorCodeDocument.Create("<p>NonDirective</p>");

            codeDocument.SetSyntaxTree(RazorSyntaxTree.Parse(codeDocument.Source, options));
            codeDocument.SetImportSyntaxTrees(new[] { RazorSyntaxTree.Parse(importSource, options) });

            // Act
            phase.Execute(codeDocument);

            // Assert
            var documentNode = codeDocument.GetDocumentIntermediateNode();
            var directives   = documentNode.Children.OfType <DirectiveIntermediateNode>();

            Assert.Empty(directives);
        }
Пример #27
0
        public void Lower_WithImports_Using()
        {
            // Arrange
            var source  = TestRazorSourceDocument.Create(@"@using System.Threading.Tasks
<p>Hi!</p>");
            var imports = new[]
            {
                TestRazorSourceDocument.Create("@using System.Globalization"),
                TestRazorSourceDocument.Create("@using System.Text"),
            };

            var codeDocument = TestRazorCodeDocument.Create(source, imports);

            // Act
            var documentNode = Lower(codeDocument);

            // Assert
            Children(
                documentNode,
                n => Using("System.Globalization", n),
                n => Using("System.Text", n),
                n => Using("System.Threading.Tasks", n),
                n => Html("<p>Hi!</p>", n));
        }