Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
4963384
RazorProjectEngineBuilderExtensions: Clean up
DustinCampbell Feb 12, 2025
4038433
Merge RazorProjectEngineBuilderExtensions classes in compiler
DustinCampbell Feb 12, 2025
35dc0ea
Add ConfigureParserOptions and ConfigureCodeGenerationOptions helpers
DustinCampbell Feb 12, 2025
14231d0
Remove ConfigureRazorCodeGenerationOptions class
DustinCampbell Feb 12, 2025
dc7307c
Remove ConfigureRazorParserOptions class
DustinCampbell Feb 12, 2025
3dcba46
Remove most IConfigureRazorParserOptionsFeature implementations
DustinCampbell Feb 12, 2025
a96b9b0
Remove most IConfigureRazorCodeGenerationOptionsFeature implementations
DustinCampbell Feb 12, 2025
a188d28
Rewrite DefaultRazorDirectiveFeature as ConfigureDirectivesFeature
DustinCampbell Feb 12, 2025
3e33e6f
Rationalize RazorProjectEngineBuilder.AddDirective(...) extension method
DustinCampbell Feb 12, 2025
41a935a
Make RazorProejctEngineBuilder.AddDefaultImports(...) helper test-only
DustinCampbell Feb 12, 2025
f5bd2d7
Remove or hide RazorProjectEngineBuilderExtensions methods
DustinCampbell Feb 12, 2025
e8512b7
Ensure that options configuration features are always ordered
DustinCampbell Feb 12, 2025
5a92650
Remove redundant parameters from Default options features
DustinCampbell Feb 12, 2025
e66a33c
Rationalize RazorCodeGenerationOptions and builder
DustinCampbell Feb 12, 2025
5aa10b9
Rationalize RazorParserOptions and builder
DustinCampbell Feb 12, 2025
3ef4a51
Update code unnecessarily passing CSharpParserOptions.Default
DustinCampbell Feb 12, 2025
8d25331
RazorParserOptions: Nest builder and flags
DustinCampbell Feb 12, 2025
c4a02f2
RazorCodeGenerationOptions: Nest builder and flags
DustinCampbell Feb 13, 2025
b3fa89d
Roll RazorParserFeatureFlags into RazorParserOptions
DustinCampbell Feb 13, 2025
815c45e
Remove project engine features for parse and code generation options
DustinCampbell Feb 13, 2025
11044eb
Add RazorLanguageVersion and FileKind to RazorCodeGenerationOptions
DustinCampbell Feb 13, 2025
cd192c3
Move Get/Set Parser/CodeGenerationOptions methods to RazorCodeDocument
DustinCampbell Feb 13, 2025
4955122
Remove TestRazorCodeDocument.Create(Source, Imports) test helper
DustinCampbell Feb 13, 2025
cd5a228
Replace get/set parser and codegen options methods with readonly props
DustinCampbell Feb 13, 2025
45e62cb
Fix DefaultRazorParsingPhaseTest
DustinCampbell Feb 14, 2025
ae96df5
Ensure RazorProjectEngine.CreateCodeDocument is called within compile…
DustinCampbell Feb 14, 2025
ab97efc
RazorProjectEngineTestBase: Remove CreateEngine()
DustinCampbell Feb 14, 2025
5e1cd9d
ModelDirectiveTest: Update to create code document from project engine
DustinCampbell Feb 18, 2025
c6382d8
ModelDirectiveTest: Fix incorrect test assertions
DustinCampbell Feb 18, 2025
22ec9bd
Refactor to share more test infrastructure
DustinCampbell Feb 18, 2025
4d5954c
PageDirectiveTest: Move to new test infrastructure
DustinCampbell Feb 18, 2025
ff5c526
Clean up Version1_X tests
DustinCampbell Feb 18, 2025
601d9be
Clean up Version2_X tests
DustinCampbell Feb 19, 2025
fa98b37
Finish cleaning up MS.ANC.Mvc.Razor.Extensions.Test
DustinCampbell Feb 19, 2025
209fa7e
Refactor and improve the testing API of RazorProjectEngineTestBase
DustinCampbell Feb 20, 2025
55a3731
Rename IntermediateNode test helpers and unneeded remove null assertions
DustinCampbell Feb 20, 2025
8f2a0f3
Remove RazorCodeDocument.Create(...) calls from compiler tests
DustinCampbell Feb 20, 2025
9e4db21
Remove RazorCodeDocument.Create(...) calls from tooling code
DustinCampbell Feb 20, 2025
0c41c15
Remove unused RazorCodeDocument.Create(...) overloads
DustinCampbell Feb 20, 2025
f6caaea
Make RazorCodeDocument.ParserOptions non-nullable
DustinCampbell Feb 20, 2025
e20b855
Make RazorCodeDocument.CodeGenerationOptions non--nullable
DustinCampbell Feb 20, 2025
2243678
Clean up and document RazorProjectEngineTestBase
DustinCampbell Feb 20, 2025
620b3e2
Rationalize RazorCodeDocument.Create(...) API
DustinCampbell Feb 20, 2025
d2eaec8
Enable nullability for IConfigureXXXOptions interfaces
DustinCampbell Feb 20, 2025
e523968
Merge branch 'main' into compiler-options-config
DustinCampbell Feb 21, 2025
7489b4f
Don't use compound null-coalescing assignment unnecessarily
DustinCampbell Feb 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,41 +1,51 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable disable

using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
using Xunit;

namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X;

public class InjectDirectiveTest
public class InjectDirectiveTest : RazorProjectEngineTestBase
{
protected override RazorLanguageVersion Version => RazorLanguageVersion.Version_1_1;

protected override void ConfigureProjectEngine(RazorProjectEngineBuilder builder)
{
// Notice we're not registering the InjectDirective.Pass here so we can run it on demand.
builder.AddDirective(InjectDirective.Directive);
builder.AddDirective(ModelDirective.Directive);

builder.Features.Add(new RazorPageDocumentClassifierPass());
builder.Features.Add(new MvcViewDocumentClassifierPass());
}

protected override void ConfigureCodeDocumentProcessor(RazorCodeDocumentProcessor processor)
{
processor.ExecutePhasesThrough<IRazorDocumentClassifierPhase>();
}

[Fact]
public void InjectDirectivePass_Execute_DefinesProperty()
{
// Arrange
var codeDocument = CreateDocument(@"
var codeDocument = ProjectEngine.CreateCodeDocument(@"
@inject PropertyType PropertyName
");

var engine = CreateEngine();
var pass = new InjectDirective.Pass()
{
Engine = engine,
};

var irDocument = CreateIRDocument(engine, codeDocument);
var processor = CreateCodeDocumentProcessor(codeDocument);

// Act
pass.Execute(codeDocument, irDocument);
processor.ExecutePass<InjectDirective.Pass>();

// Assert
var @class = FindClassNode(irDocument);
Assert.NotNull(@class);
Assert.Equal(2, @class.Children.Count);
var documentNode = processor.GetDocumentNode();
var classNode = documentNode.GetClassNode();

var node = Assert.IsType<InjectIntermediateNode>(@class.Children[1]);
Assert.Equal(2, classNode.Children.Count);

var node = Assert.IsType<InjectIntermediateNode>(classNode.Children[1]);
Assert.Equal("PropertyType", node.TypeName);
Assert.Equal("PropertyName", node.MemberName);
}
Expand All @@ -44,28 +54,23 @@ @inject PropertyType PropertyName
public void InjectDirectivePass_Execute_DedupesPropertiesByName()
{
// Arrange
var codeDocument = CreateDocument(@"
var codeDocument = ProjectEngine.CreateCodeDocument(@"
@inject PropertyType PropertyName
@inject PropertyType2 PropertyName
");

var engine = CreateEngine();
var pass = new InjectDirective.Pass()
{
Engine = engine,
};

var irDocument = CreateIRDocument(engine, codeDocument);
var processor = CreateCodeDocumentProcessor(codeDocument);

// Act
pass.Execute(codeDocument, irDocument);
processor.ExecutePass<InjectDirective.Pass>();

// Assert
var @class = FindClassNode(irDocument);
Assert.NotNull(@class);
Assert.Equal(2, @class.Children.Count);
var documentNode = processor.GetDocumentNode();
var classNode = documentNode.GetClassNode();

Assert.Equal(2, classNode.Children.Count);

var node = Assert.IsType<InjectIntermediateNode>(@class.Children[1]);
var node = Assert.IsType<InjectIntermediateNode>(classNode.Children[1]);
Assert.Equal("PropertyType2", node.TypeName);
Assert.Equal("PropertyName", node.MemberName);
}
Expand All @@ -74,27 +79,22 @@ @inject PropertyType2 PropertyName
public void InjectDirectivePass_Execute_ExpandsTModel_WithDynamic()
{
// Arrange
var codeDocument = CreateDocument(@"
var codeDocument = ProjectEngine.CreateCodeDocument(@"
@inject PropertyType<TModel> PropertyName
");

var engine = CreateEngine();
var pass = new InjectDirective.Pass()
{
Engine = engine,
};

var irDocument = CreateIRDocument(engine, codeDocument);
var processor = CreateCodeDocumentProcessor(codeDocument);

// Act
pass.Execute(codeDocument, irDocument);
processor.ExecutePass<InjectDirective.Pass>();

// Assert
var @class = FindClassNode(irDocument);
Assert.NotNull(@class);
Assert.Equal(2, @class.Children.Count);
var documentNode = processor.GetDocumentNode();
var classNode = documentNode.GetClassNode();

Assert.Equal(2, classNode.Children.Count);

var node = Assert.IsType<InjectIntermediateNode>(@class.Children[1]);
var node = Assert.IsType<InjectIntermediateNode>(classNode.Children[1]);
Assert.Equal("PropertyType<dynamic>", node.TypeName);
Assert.Equal("PropertyName", node.MemberName);
}
Expand All @@ -103,28 +103,23 @@ @inject PropertyType<TModel> PropertyName
public void InjectDirectivePass_Execute_ExpandsTModel_WithModelTypeFirst()
{
// Arrange
var codeDocument = CreateDocument(@"
var codeDocument = ProjectEngine.CreateCodeDocument(@"
@model ModelType
@inject PropertyType<TModel> PropertyName
");

var engine = CreateEngine();
var pass = new InjectDirective.Pass()
{
Engine = engine,
};

var irDocument = CreateIRDocument(engine, codeDocument);
var processor = CreateCodeDocumentProcessor(codeDocument);

// Act
pass.Execute(codeDocument, irDocument);
processor.ExecutePass<InjectDirective.Pass>();

// Assert
var @class = FindClassNode(irDocument);
Assert.NotNull(@class);
Assert.Equal(2, @class.Children.Count);
var documentNode = processor.GetDocumentNode();
var classNode = documentNode.GetClassNode();

Assert.Equal(2, classNode.Children.Count);

var node = Assert.IsType<InjectIntermediateNode>(@class.Children[1]);
var node = Assert.IsType<InjectIntermediateNode>(classNode.Children[1]);
Assert.Equal("PropertyType<ModelType>", node.TypeName);
Assert.Equal("PropertyName", node.MemberName);
}
Expand All @@ -133,81 +128,24 @@ @inject PropertyType<TModel> PropertyName
public void InjectDirectivePass_Execute_ExpandsTModel_WithModelType()
{
// Arrange
var codeDocument = CreateDocument(@"
var codeDocument = ProjectEngine.CreateCodeDocument(@"
@inject PropertyType<TModel> PropertyName
@model ModelType
");

var engine = CreateEngine();
var pass = new InjectDirective.Pass()
{
Engine = engine,
};

var irDocument = CreateIRDocument(engine, codeDocument);
var processor = CreateCodeDocumentProcessor(codeDocument);

// Act
pass.Execute(codeDocument, irDocument);
processor.ExecutePass<InjectDirective.Pass>();

// Assert
var @class = FindClassNode(irDocument);
Assert.NotNull(@class);
Assert.Equal(2, @class.Children.Count);
var documentNode = processor.GetDocumentNode();
var classNode = documentNode.GetClassNode();

Assert.Equal(2, classNode.Children.Count);

var node = Assert.IsType<InjectIntermediateNode>(@class.Children[1]);
var node = Assert.IsType<InjectIntermediateNode>(classNode.Children[1]);
Assert.Equal("PropertyType<ModelType>", node.TypeName);
Assert.Equal("PropertyName", node.MemberName);
}

private RazorCodeDocument CreateDocument(string content)
{
var source = RazorSourceDocument.Create(content, "test.cshtml");
return RazorCodeDocument.Create(source);
}

private ClassDeclarationIntermediateNode FindClassNode(IntermediateNode node)
{
var visitor = new ClassNodeVisitor();
visitor.Visit(node);
return visitor.Node;
}

private RazorEngine CreateEngine()
{
var configuration = new RazorConfiguration(RazorLanguageVersion.Version_1_1, "test", Extensions: []);
return RazorProjectEngine.Create(configuration, RazorProjectFileSystem.Empty, b =>
{
// Notice we're not registering the InjectDirective.Pass here so we can run it on demand.
b.AddDirective(InjectDirective.Directive);
b.AddDirective(ModelDirective.Directive);

b.Features.Add(new RazorPageDocumentClassifierPass());
b.Features.Add(new MvcViewDocumentClassifierPass());
}).Engine;
}

private DocumentIntermediateNode CreateIRDocument(RazorEngine engine, RazorCodeDocument codeDocument)
{
foreach (var phase in engine.Phases)
{
phase.Execute(codeDocument);

if (phase is IRazorDocumentClassifierPhase)
{
break;
}
}

return codeDocument.GetDocumentIntermediateNode();
}

private class ClassNodeVisitor : IntermediateNodeWalker
{
public ClassDeclarationIntermediateNode Node { get; set; }

public override void VisitClassDeclaration(ClassDeclarationIntermediateNode node)
{
Node = node;
}
}
}
Loading