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); }
public void Execute_SetsTagHelperDocumentContext() { // Arrange var projectEngine = RazorProjectEngine.Create(builder => { builder.Features.Add(new TestTagHelperFeature()); }); var phase = new DefaultRazorTagHelperBinderPhase() { Engine = projectEngine.Engine, }; // No taghelper directives here so nothing is resolved. var sourceDocument = TestRazorSourceDocument.Create("Hello, world"); var codeDocument = RazorCodeDocument.Create(sourceDocument); var originalTree = RazorSyntaxTree.Parse(sourceDocument); codeDocument.SetSyntaxTree(originalTree); // Act phase.Execute(codeDocument); // Assert var context = codeDocument.GetTagHelperContext(); Assert.Null(context.Prefix); Assert.Empty(context.TagHelpers); }
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); }
public void Execute_NoopsWhenNoTagHelperDescriptorsAreResolved() { // Arrange var projectEngine = RazorProjectEngine.Create(builder => { builder.Features.Add(new TestTagHelperFeature()); }); var phase = new DefaultRazorTagHelperBinderPhase() { Engine = projectEngine.Engine, }; // No taghelper directives here so nothing is resolved. var sourceDocument = TestRazorSourceDocument.Create("Hello, world"); var codeDocument = RazorCodeDocument.Create(sourceDocument); var originalTree = RazorSyntaxTree.Parse(sourceDocument); codeDocument.SetSyntaxTree(originalTree); // Act phase.Execute(codeDocument); // Assert var outputTree = codeDocument.GetSyntaxTree(); Assert.Empty(outputTree.Diagnostics); Assert.Same(originalTree, outputTree); }
public void Execute_DirectiveWithQuotes_RewritesTagHelpers_TagHelperMatchesElementTwice() { // Arrange var descriptor = CreateTagHelperDescriptor( tagName: "form", typeName: "TestFormTagHelper", assemblyName: "TestAssembly", ruleBuilders: new Action <TagMatchingRuleDescriptorBuilder>[] { ruleBuilder => ruleBuilder .RequireAttributeDescriptor(attribute => attribute .Name("a") .NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode.FullMatch)), ruleBuilder => ruleBuilder .RequireAttributeDescriptor(attribute => attribute .Name("b") .NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode.FullMatch)), }); var projectEngine = RazorProjectEngine.Create(builder => { builder.AddTagHelpers(new[] { descriptor }); }); var phase = new DefaultRazorTagHelperBinderPhase() { Engine = projectEngine.Engine, }; var content = @" @addTagHelper ""*, TestAssembly"" <form a=""hi"" b=""there""> </form>"; var sourceDocument = TestRazorSourceDocument.Create(content); var codeDocument = RazorCodeDocument.Create(sourceDocument); var originalTree = RazorSyntaxTree.Parse(sourceDocument); codeDocument.SetSyntaxTree(originalTree); // Act phase.Execute(codeDocument); // Assert var rewrittenTree = codeDocument.GetSyntaxTree(); var descendantNodes = rewrittenTree.Root.DescendantNodes(); Assert.Empty(rewrittenTree.Diagnostics); var tagHelperNodes = descendantNodes.Where(n => n is MarkupTagHelperElementSyntax tagHelper).Cast <MarkupTagHelperElementSyntax>().ToArray(); var formTagHelper = Assert.Single(tagHelperNodes); Assert.Equal("form", formTagHelper.TagHelperInfo.TagName); Assert.Equal(2, formTagHelper.TagHelperInfo.BindingResult.GetBoundRules(descriptor).Count()); }
public void Execute_DirectiveWithoutQuotes_RewritesTagHelpers_TagHelperMatchesElementTwice() { // Arrange var descriptor = CreateTagHelperDescriptor( tagName: "form", typeName: "TestFormTagHelper", assemblyName: "TestAssembly", ruleBuilders: new Action <TagMatchingRuleDescriptorBuilder>[] { ruleBuilder => ruleBuilder .RequireAttributeDescriptor(attribute => attribute .Name("a") .NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode.FullMatch)), ruleBuilder => ruleBuilder .RequireAttributeDescriptor(attribute => attribute .Name("b") .NameComparisonMode(RequiredAttributeDescriptor.NameComparisonMode.FullMatch)), }); var engine = RazorEngine.Create(builder => { builder.AddTagHelpers(new[] { descriptor }); }); var phase = new DefaultRazorTagHelperBinderPhase() { Engine = engine, }; var content = @" @addTagHelper *, TestAssembly <form a=""hi"" b=""there""> </form>"; var sourceDocument = TestRazorSourceDocument.Create(content); var codeDocument = RazorCodeDocument.Create(sourceDocument); var originalTree = RazorSyntaxTree.Parse(sourceDocument); codeDocument.SetSyntaxTree(originalTree); // Act phase.Execute(codeDocument); // Assert var rewrittenTree = codeDocument.GetSyntaxTree(); Assert.Empty(rewrittenTree.Diagnostics); Assert.Equal(3, rewrittenTree.Root.Children.Count); var formTagHelper = Assert.IsType <TagHelperBlock>(rewrittenTree.Root.Children[2]); Assert.Equal("form", formTagHelper.TagName); Assert.Equal(2, formTagHelper.Binding.GetBoundRules(descriptor).Count()); }
public void Execute_CombinesErrorsOnRewritingErrors() { // Arrange var engine = RazorEngine.Create(builder => { builder.AddTagHelpers(new[] { CreateTagHelperDescriptor( tagName: "form", typeName: "TestFormTagHelper", assemblyName: "TestAssembly"), CreateTagHelperDescriptor( tagName: "input", typeName: "TestInputTagHelper", assemblyName: "TestAssembly"), }); }); var phase = new DefaultRazorTagHelperBinderPhase() { Engine = engine, }; var content = @" @addTagHelper *, TestAssembly <form> <input value='Hello' type='text' />"; var sourceDocument = TestRazorSourceDocument.Create(content, fileName: null); var codeDocument = RazorCodeDocument.Create(sourceDocument); var originalTree = RazorSyntaxTree.Parse(sourceDocument); var initialError = RazorDiagnostic.Create(new RazorError("Initial test error", SourceLocation.Zero, length: 1)); var expectedRewritingError = RazorDiagnostic.Create( new RazorError( LegacyResources.FormatTagHelpersParseTreeRewriter_FoundMalformedTagHelper("form"), new SourceLocation(Environment.NewLine.Length * 2 + 30, 2, 1), length: 4)); var erroredOriginalTree = RazorSyntaxTree.Create(originalTree.Root, originalTree.Source, new[] { initialError }, originalTree.Options); codeDocument.SetSyntaxTree(erroredOriginalTree); // Act phase.Execute(codeDocument); // Assert var outputTree = codeDocument.GetSyntaxTree(); Assert.Empty(originalTree.Diagnostics); Assert.NotSame(erroredOriginalTree, outputTree); Assert.Equal(new[] { initialError, expectedRewritingError }, outputTree.Diagnostics); }
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); }
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); }
private static RazorSourceDocument CreateTestSourceDocument() { var content = @" @addTagHelper *, TestAssembly <form> <input value='Hello' type='text' /> </form>"; var sourceDocument = TestRazorSourceDocument.Create(content, filePath: null); return(sourceDocument); }
public void ReadFrom_EmptyStream_WithEncoding() { // Arrange var content = TestRazorSourceDocument.CreateStreamContent(content: string.Empty, encoding: Encoding.UTF32); // Act var document = RazorSourceDocument.ReadFrom(content, "file.cshtml", Encoding.UTF32); // Assert Assert.Equal("file.cshtml", document.FilePath); Assert.Same(Encoding.UTF32, Assert.IsType <StreamSourceDocument>(document).Encoding); }
public void ConstructedWithoutEncoding_EmptyStream_DetectsEncoding() { // Arrange var content = TestRazorSourceDocument.CreateStreamContent(content: string.Empty, encoding: Encoding.UTF32); // Act var document = new StreamSourceDocument(content, null, RazorSourceDocumentProperties.Default); // Assert Assert.IsType <StreamSourceDocument>(document); Assert.Equal(Encoding.UTF32, document.Encoding); }
public void Create() { // Arrange var source = TestRazorSourceDocument.Create(); // Act var code = RazorCodeDocument.Create(source); // Assert Assert.Same(source, code.Source); Assert.NotNull(code.Items); }
public void FailsOnMismatchedEncoding() { // Arrange var content = TestRazorSourceDocument.CreateStreamContent(encoding: Encoding.UTF32); var expectedMessage = Resources.FormatMismatchedContentEncoding(Encoding.UTF8.EncodingName, Encoding.UTF32.EncodingName); // Act & Assert var exception = Assert.Throws <InvalidOperationException>( () => new StreamSourceDocument(content, Encoding.UTF8, RazorSourceDocumentProperties.Default)); Assert.Equal(expectedMessage, exception.Message); }
public void ReadFrom() { // Arrange var content = TestRazorSourceDocument.CreateStreamContent(); // Act var document = RazorSourceDocument.ReadFrom(content, "file.cshtml"); // Assert Assert.IsType <StreamSourceDocument>(document); Assert.Equal("file.cshtml", document.FilePath); Assert.Same(Encoding.UTF8, document.Encoding); }
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); }
public void Ctor_AllowsNullForImports() { // Arrange var source = TestRazorSourceDocument.Create(); // Act var code = new DefaultRazorCodeDocument(source, imports: null); // Assert Assert.Same(source, code.Source); Assert.NotNull(code.Items); Assert.Empty(code.Imports); }
public void ConstructedWithoutEncoding_EmptyStream_DetectsEncoding() { // Arrange var content = TestRazorSourceDocument.CreateStreamContent(content: string.Empty, encoding: Encoding.UTF32); // Act var document = new StreamSourceDocument(content, encoding: null, fileName: "file.cshtml"); // Assert Assert.IsType <StreamSourceDocument>(document); Assert.Equal("file.cshtml", document.FilePath); Assert.Equal(Encoding.UTF32, document.Encoding); }
public void Create_WithImports_AllowsNull() { // Arrange var source = TestRazorSourceDocument.Create(); // Act var code = RazorCodeDocument.Create(source, imports: null); // Assert Assert.Same(source, code.Source); Assert.NotNull(code.Items); Assert.Empty(code.Imports); }
public void ReadFrom_WithProperties() { // Arrange var content = TestRazorSourceDocument.CreateStreamContent(encoding: Encoding.UTF32); var properties = new RazorSourceDocumentProperties("c:\\myapp\\filePath.cshtml", "filePath.cshtml"); // Act var document = RazorSourceDocument.ReadFrom(content, Encoding.UTF32, properties); // Assert Assert.Equal("c:\\myapp\\filePath.cshtml", document.FilePath); Assert.Equal("filePath.cshtml", document.RelativePath); Assert.Same(Encoding.UTF32, Assert.IsType <StreamSourceDocument>(document).Encoding); }
public void Process_GeneratesCodeDocumentWithValidCSharpDocument() { // Arrange var sourceDocument = TestRazorSourceDocument.Create(); var projectEngine = RazorProjectEngine.Create(TestRazorProjectFileSystem.Empty); // Act var codeDocument = projectEngine.Process(sourceDocument); // Assert var csharpDocument = codeDocument.GetCSharpDocument(); Assert.NotNull(csharpDocument); Assert.Empty(csharpDocument.Diagnostics); }
public void DetectsSizeOfStreamForLargeContent(int contentLength) { // Arrange var content = new string('a', contentLength); var stream = TestRazorSourceDocument.CreateStreamContent(content); // Act var document = new StreamSourceDocument(stream, null, RazorSourceDocumentProperties.Default); // Assert var streamDocument = Assert.IsType <StreamSourceDocument>(document); Assert.IsType <LargeTextSourceDocument>(streamDocument._innerSourceDocument); Assert.Same(Encoding.UTF8, document.Encoding); Assert.Equal(content, ReadContent(document)); }
public void DirectiveVisitor_ExtractsPrefixFromSyntaxTree( string source, string expectedPrefix) { // Arrange var sourceDocument = TestRazorSourceDocument.Create(source, filePath: "TestFile"); var parser = new RazorParser(); var syntaxTree = parser.Parse(sourceDocument); var visitor = new DefaultRazorTagHelperBinderPhase.DirectiveVisitor(tagHelpers: new List <TagHelperDescriptor>()); // Act visitor.VisitBlock(syntaxTree.Root); // Assert Assert.Equal(expectedPrefix, visitor.TagHelperPrefix); }
public void ProcessDirectives_CanReturnEmptyDescriptorsBasedOnDirectiveDescriptors( string source, object tagHelpers) { // Arrange var sourceDocument = TestRazorSourceDocument.Create(source, filePath: "TestFile"); var parser = new RazorParser(); var syntaxTree = parser.Parse(sourceDocument); var visitor = new DefaultRazorTagHelperBinderPhase.DirectiveVisitor((TagHelperDescriptor[])tagHelpers); // Act visitor.VisitBlock(syntaxTree.Root); // Assert Assert.Empty(visitor.Matches); }
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); }
public void DetectsSizeOfStreamForLargeContent(int contentLength) { // Arrange var content = new string('a', contentLength); var stream = TestRazorSourceDocument.CreateStreamContent(content); // Act var document = new StreamSourceDocument(stream, encoding: null, fileName: "file.cshtml"); // Assert var streamDocument = Assert.IsType <StreamSourceDocument>(document); Assert.IsType <LargeTextSourceDocument>(streamDocument._innerSourceDocument); Assert.Equal("file.cshtml", document.FilePath); Assert.Same(Encoding.UTF8, document.Encoding); Assert.Equal(content, ReadContent(document)); }
public void Execute_CanHandleSingleLengthRemoveTagHelperDirective() { // Arrange var engine = RazorEngine.Create(builder => { builder.AddTagHelpers(new TagHelperDescriptor[0]); }); var phase = new DefaultRazorTagHelperBinderPhase() { Engine = engine, }; var expectedDiagnostics = new[] { RazorDiagnostic.Create( new RazorError( LegacyResources.ParseError_Unterminated_String_Literal, new SourceLocation(17 + Environment.NewLine.Length, 1, 17), length: 1)), RazorDiagnostic.Create( new RazorError( Resources.FormatInvalidTagHelperLookupText("\""), new SourceLocation(17 + Environment.NewLine.Length, 1, 17), length: 1)) }; var content = @" @removeTagHelper """; var sourceDocument = TestRazorSourceDocument.Create(content, fileName: null); var codeDocument = RazorCodeDocument.Create(sourceDocument); var originalTree = RazorSyntaxTree.Parse(sourceDocument); codeDocument.SetSyntaxTree(originalTree); // Act phase.Execute(codeDocument); // Assert var rewrittenTree = codeDocument.GetSyntaxTree(); var directiveValue = rewrittenTree.Root.Children.OfType <Block>().First().Children.Last() as Span; var chunkGenerator = Assert.IsType <RemoveTagHelperChunkGenerator>(directiveValue.ChunkGenerator); Assert.Equal(expectedDiagnostics, chunkGenerator.Diagnostics); }
public void Execute_RewritesWhitespace() { // Assert var content = Environment.NewLine + " @true"; var sourceDocument = TestRazorSourceDocument.Create(content); var originalTree = RazorSyntaxTree.Parse(sourceDocument); var pass = new HtmlNodeOptimizationPass(); var codeDocument = RazorCodeDocument.Create(sourceDocument); // Act var outputTree = pass.Execute(codeDocument, originalTree); // Assert Assert.Equal(4, outputTree.Root.Children.Count); var whitespace = Assert.IsType <Span>(outputTree.Root.Children[1]); Assert.True(whitespace.Content.All(char.IsWhiteSpace)); }
public void TryComputeNamespace_OverrideImportsNamespaceDirective() { // Arrange var sourceDocument = TestRazorSourceDocument.Create( content: "@namespace My.Custom.OverrideNS", 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 importSourceDocument = TestRazorSourceDocument.Create( content: "@namespace My.Custom.NS", filePath: "C:\\Hello\\_Imports.razor", relativePath: "\\_Imports.razor"); codeDocument.SetImportSyntaxTrees(new[] { RazorSyntaxTree.Parse(importSourceDocument, 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.OverrideNS", @namespace); }
public void Execute_DirectiveWithError_PreservesDiagnosticsAndRemovesDirectiveNodeFromDocument() { // Arrange var content = "@custom \"Hello\""; var expectedDiagnostic = RazorDiagnostic.Create(new RazorDiagnosticDescriptor("RZ9999", () => "Some diagnostic message.", RazorDiagnosticSeverity.Error), SourceSpan.Undefined); var sourceDocument = TestRazorSourceDocument.Create(content); var codeDocument = RazorCodeDocument.Create(sourceDocument); var defaultEngine = RazorProjectEngine.Create(b => { b.AddDirective(DirectiveDescriptor.CreateDirective("custom", DirectiveKind.SingleLine, d => d.AddStringToken())); }).Engine; var documentNode = Lower(codeDocument, defaultEngine); // Add the diagnostic to the directive node. var directiveNode = documentNode.FindDescendantNodes <DirectiveIntermediateNode>().Single(); directiveNode.Diagnostics.Add(expectedDiagnostic); var pass = new DirectiveRemovalOptimizationPass() { Engine = defaultEngine, }; // Act pass.Execute(codeDocument, documentNode); // Assert var diagnostic = Assert.Single(documentNode.Diagnostics); Assert.Equal(expectedDiagnostic, diagnostic); Children(documentNode, node => Assert.IsType <NamespaceDeclarationIntermediateNode>(node)); var @namespace = documentNode.Children[0]; Children(@namespace, node => Assert.IsType <ClassDeclarationIntermediateNode>(node)); var @class = @namespace.Children[0]; var method = SingleChild <MethodDeclarationIntermediateNode>(@class); Assert.Empty(method.Children); }