diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_CompoundAssignment_ReportsError.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_CompoundAssignment_ReportsError.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_CompoundAssignment_ReportsError.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_CompoundAssignment_ReportsError.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_IfWithoutElse_ImplicitReturn.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_IfWithoutElse_ImplicitReturn.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_IfWithoutElse_ImplicitReturn.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_IfWithoutElse_ImplicitReturn.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_IfWithoutElse_UsesDefault.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_IfWithoutElse_UsesDefault.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_IfWithoutElse_UsesDefault.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_IfWithoutElse_UsesDefault.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_IncrementOperator_ReportsError.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_IncrementOperator_ReportsError.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_IncrementOperator_ReportsError.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_IncrementOperator_ReportsError.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_LocalInIfCondition.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_LocalInIfCondition.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_LocalInIfCondition.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_LocalInIfCondition.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_LocalInSwitchExpression.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_LocalInSwitchExpression.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_LocalInSwitchExpression.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_LocalInSwitchExpression.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_LocalsInNestedBlock_ProducesDiagnostic.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_LocalsInNestedBlock_ProducesDiagnostic.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_LocalsInNestedBlock_ProducesDiagnostic.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_LocalsInNestedBlock_ProducesDiagnostic.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_NonProjectableMethodCall_ReportsWarning.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_NonProjectableMethodCall_ReportsWarning.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_NonProjectableMethodCall_ReportsWarning.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_NonProjectableMethodCall_ReportsWarning.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_PropertyAssignment_ReportsError.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_PropertyAssignment_ReportsError.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_PropertyAssignment_ReportsError.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_PropertyAssignment_ReportsError.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SimpleReturn.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_SimpleReturn.verified.txt similarity index 94% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SimpleReturn.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_SimpleReturn.verified.txt index eeb0754..87a1cad 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SimpleReturn.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_SimpleReturn.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using EntityFrameworkCore.Projectables; @@ -14,4 +14,4 @@ namespace EntityFrameworkCore.Projectables.Generated return (global::Foo.C @this) => 42; } } -} +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SwitchStatement_Simple.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_SwitchStatement_Simple.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SwitchStatement_Simple.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_SwitchStatement_Simple.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SwitchStatement_WithMultipleCases.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_SwitchStatement_WithMultipleCases.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SwitchStatement_WithMultipleCases.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_SwitchStatement_WithMultipleCases.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SwitchStatement_WithoutDefault.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_SwitchStatement_WithoutDefault.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_SwitchStatement_WithoutDefault.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_SwitchStatement_WithoutDefault.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithAndPattern.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithAndPattern.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithAndPattern.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithAndPattern.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithConstantPattern.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithConstantPattern.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithConstantPattern.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithConstantPattern.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithIfElse.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithIfElse.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithIfElse.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithIfElse.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithIfElseAndCondition.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithIfElseAndCondition.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithIfElseAndCondition.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithIfElseAndCondition.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithLocalVariable.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithLocalVariable.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithLocalVariable.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithLocalVariable.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithMultipleParameters.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithMultipleParameters.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithMultipleParameters.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithMultipleParameters.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithNestedIfElse.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithNestedIfElse.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithNestedIfElse.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithNestedIfElse.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithNotPattern.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithNotPattern.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithNotPattern.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithNotPattern.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithOrPattern.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithOrPattern.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithOrPattern.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithOrPattern.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithPatternMatching.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithPatternMatching.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithPatternMatching.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithPatternMatching.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithPropertyAccess.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithPropertyAccess.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithPropertyAccess.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithPropertyAccess.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithRelationalPattern.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithRelationalPattern.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithRelationalPattern.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithRelationalPattern.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithTransitiveLocalVariables.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithTransitiveLocalVariables.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BlockBodiedMethod_WithTransitiveLocalVariables.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.BlockBodiedMethod_WithTransitiveLocalVariables.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.cs b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.cs new file mode 100644 index 0000000..d9caa24 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/BlockBodyTests.cs @@ -0,0 +1,916 @@ +using System.Linq; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using VerifyXunit; +using Xunit; +using Xunit.Abstractions; + +namespace EntityFrameworkCore.Projectables.Generator.Tests; + +[UsesVerify] +public class BlockBodyTests : ProjectionExpressionGeneratorTestsBase +{ + public BlockBodyTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + [Fact] + public void BlockBodiedMethod_NoLongerRaisesDiagnostics() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + [Projectable(AllowBlockBody = true)] + public int Foo() + { + return 1; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + } + + [Fact] + public void BlockBodiedMethod_WithoutAllowFlag_EmitsWarning() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; + +namespace Foo { + class C { + public int Value { get; set; } + + [Projectable] + public int GetDouble() + { + return Value * 2; + } + } +} +"); + var result = RunGenerator(compilation); + + var diagnostic = Assert.Single(result.Diagnostics); + Assert.Equal("EFP0001", diagnostic.Id); + Assert.Equal(DiagnosticSeverity.Warning, diagnostic.Severity); + } + + [Fact] + public void BlockBodiedMethod_WithAllowFlag_NoWarning() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; + +namespace Foo { + class C { + public int Value { get; set; } + + [Projectable(AllowBlockBody = true)] + public int GetDouble() + { + return Value * 2; + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + } + + [Fact] + public Task BlockBodiedMethod_SimpleReturn() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + [Projectable(AllowBlockBody = true)] + public int Foo() + { + return 42; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_WithPropertyAccess() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable(AllowBlockBody = true)] + public int Foo() + { + return Bar + 10; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_WithIfElse() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable(AllowBlockBody = true)] + public int Foo() + { + if (Bar > 10) + { + return 1; + } + else + { + return 0; + } + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_WithNestedIfElse() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable(AllowBlockBody = true)] + public string Foo() + { + if (Bar > 10) + { + return ""High""; + } + else if (Bar > 5) + { + return ""Medium""; + } + else + { + return ""Low""; + } + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_WithLocalVariable() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable(AllowBlockBody = true)] + public int Foo() + { + var temp = Bar * 2; + return temp + 5; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_WithTransitiveLocalVariables() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable(AllowBlockBody = true)] + public int Foo() + { + var a = Bar * 2; + var b = a + 5; + return b + 10; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_LocalInIfCondition() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable(AllowBlockBody = true)] + public int Foo() + { + var threshold = Bar * 2; + if (threshold > 10) + { + return 1; + } + else + { + return 0; + } + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_LocalInSwitchExpression() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable(AllowBlockBody = true)] + public string Foo() + { + var value = Bar * 2; + switch (value) + { + case 2: + return ""Two""; + case 4: + return ""Four""; + default: + return ""Other""; + } + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_LocalsInNestedBlock_ProducesDiagnostic() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable(AllowBlockBody = true)] + public int Foo() + { + if (Bar > 10) + { + var temp = Bar * 2; + return temp; + } + return 0; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.NotEmpty(result.Diagnostics); + Assert.Contains(result.Diagnostics, d => d.Id == "EFP0003"); + + return Verifier.Verify(result.Diagnostics.Select(d => d.ToString())); + } + + [Fact] + public Task BlockBodiedMethod_WithMultipleParameters() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + [Projectable(AllowBlockBody = true)] + public int Add(int a, int b) + { + return a + b; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_WithIfElseAndCondition() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + public bool IsActive { get; set; } + + [Projectable(AllowBlockBody = true)] + public int Foo() + { + if (IsActive && Bar > 0) + { + return Bar * 2; + } + else + { + return 0; + } + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_IfWithoutElse_UsesDefault() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable(AllowBlockBody = true)] + public int Foo() + { + if (Bar > 10) + { + return 1; + } + return 0; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_IfWithoutElse_ImplicitReturn() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable(AllowBlockBody = true)] + public int? Foo() + { + if (Bar > 10) + { + return 1; + } + + return null; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_SwitchStatement_Simple() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable(AllowBlockBody = true)] + public string Foo() + { + switch (Bar) + { + case 1: + return ""One""; + case 2: + return ""Two""; + default: + return ""Other""; + } + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_SwitchStatement_WithMultipleCases() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable(AllowBlockBody = true)] + public string Foo() + { + switch (Bar) + { + case 1: + case 2: + return ""Low""; + case 3: + case 4: + case 5: + return ""Medium""; + default: + return ""High""; + } + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_SwitchStatement_WithoutDefault() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable(AllowBlockBody = true)] + public string? Foo() + { + switch (Bar) + { + case 1: + return ""One""; + case 2: + return ""Two""; + } + + return null; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_PropertyAssignment_ReportsError() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable(AllowBlockBody = true)] + public int Foo() + { + Bar = 10; + return Bar; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.NotEmpty(result.Diagnostics); + Assert.Contains(result.Diagnostics, d => d.Id == "EFP0004"); + + return Verifier.Verify(result.Diagnostics.Select(d => d.ToString())); + } + + [Fact] + public Task BlockBodiedMethod_CompoundAssignment_ReportsError() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable(AllowBlockBody = true)] + public int Foo() + { + Bar += 10; + return Bar; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.NotEmpty(result.Diagnostics); + Assert.Contains(result.Diagnostics, d => d.Id == "EFP0004"); + + return Verifier.Verify(result.Diagnostics.Select(d => d.ToString())); + } + + [Fact] + public Task BlockBodiedMethod_IncrementOperator_ReportsError() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable(AllowBlockBody = true)] + public int Foo() + { + var x = 5; + x++; + return x; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.NotEmpty(result.Diagnostics); + Assert.Contains(result.Diagnostics, d => d.Id == "EFP0004"); + + return Verifier.Verify(result.Diagnostics.Select(d => d.ToString())); + } + + [Fact] + public Task BlockBodiedMethod_NonProjectableMethodCall_ReportsWarning() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable(AllowBlockBody = true)] + public int Foo() + { + Console.WriteLine(""test""); + return Bar; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.NotEmpty(result.Diagnostics); + Assert.Contains(result.Diagnostics, d => d.Id == "EFP0005"); + + return Verifier.Verify(result.Diagnostics.Select(d => d.ToString())); + } + + [Fact] + public Task BlockBodiedMethod_WithPatternMatching() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class Entity { + public bool IsActive { get; set; } + public int Value { get; set; } + } + + static class Extensions { + [Projectable(AllowBlockBody = true)] + public static string GetComplexCategory(this Entity entity) + { + if (entity is { IsActive: true, Value: > 100 }) + { + return ""Active High""; + } + return ""Other""; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_WithRelationalPattern() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class Entity { + public int Value { get; set; } + } + + static class Extensions { + [Projectable(AllowBlockBody = true)] + public static string GetCategory(this Entity entity) + { + if (entity.Value is > 100) + { + return ""High""; + } + return ""Low""; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_WithConstantPattern() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class Entity { + public string Status { get; set; } + } + + static class Extensions { + [Projectable(AllowBlockBody = true)] + public static bool IsNull(this Entity entity) + { + if (entity is null) + { + return true; + } + return false; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_WithNotPattern() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class Entity { + public string Name { get; set; } + } + + static class Extensions { + [Projectable(AllowBlockBody = true)] + public static bool IsNotNull(this Entity entity) + { + if (entity is not null) + { + return true; + } + return false; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_WithAndPattern() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; + +namespace Foo { + class Entity { + public int Value { get; set; } + } + + static class Extensions { + [Projectable(AllowBlockBody = true)] + public static bool IsInRange(this Entity entity) + { + if (entity.Value is >= 1 and <= 100) + { + return true; + } + return false; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BlockBodiedMethod_WithOrPattern() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; + +namespace Foo { + class Entity { + public string Status { get; set; } + } + + static class Extensions { + [Projectable(AllowBlockBody = true)] + public static bool IsTerminal(this Entity entity) + { + if (entity.Status is ""Cancelled"" or ""Completed"") + { + return true; + } + return false; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_BodyAssignments.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_BodyAssignments.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_BodyAssignments.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_BodyAssignments.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_Overloads.DotNet8_0.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_Overloads.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_Overloads.DotNet8_0.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_Overloads.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ReferencingBasePropertyInDerivedBody.DotNet8_0.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_ReferencingBasePropertyInDerivedBody.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ReferencingBasePropertyInDerivedBody.DotNet8_0.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_ReferencingBasePropertyInDerivedBody.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ReferencingPreviouslyAssignedInBaseCtor.DotNet8_0.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_ReferencingPreviouslyAssignedInBaseCtor.verified.txt similarity index 93% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ReferencingPreviouslyAssignedInBaseCtor.DotNet8_0.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_ReferencingPreviouslyAssignedInBaseCtor.verified.txt index fc89a79..4570ef5 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ReferencingPreviouslyAssignedInBaseCtor.DotNet8_0.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_ReferencingPreviouslyAssignedInBaseCtor.verified.txt @@ -18,7 +18,7 @@ namespace EntityFrameworkCore.Projectables.Generated /// public Base(int x, int y) /// { /// X = x; - /// Y = x + y; // Y depends on X's assigned value (x) + /// Y = x + y; /// } /// /// diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ReferencingPreviouslyAssignedProperty.DotNet8_0.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_ReferencingPreviouslyAssignedProperty.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ReferencingPreviouslyAssignedProperty.DotNet8_0.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_ReferencingPreviouslyAssignedProperty.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ReferencingStaticConstMember.DotNet8_0.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_ReferencingStaticConstMember.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ReferencingStaticConstMember.DotNet8_0.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_ReferencingStaticConstMember.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_ChainedThisAndBase.DotNet8_0.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_ThisInitializer_ChainedThisAndBase.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_ChainedThisAndBase.DotNet8_0.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_ThisInitializer_ChainedThisAndBase.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_RefPreviouslyAssignedProperty.DotNet8_0.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_ThisInitializer_RefPreviouslyAssignedProperty.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_RefPreviouslyAssignedProperty.DotNet8_0.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_ThisInitializer_RefPreviouslyAssignedProperty.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_SimpleOverload.DotNet8_0.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_ThisInitializer_SimpleOverload.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_SimpleOverload.DotNet8_0.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_ThisInitializer_SimpleOverload.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_WithBodyAfter.DotNet8_0.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_ThisInitializer_WithBodyAfter.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_WithBodyAfter.DotNet8_0.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_ThisInitializer_WithBodyAfter.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_WithIfElseInDelegated.DotNet8_0.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_ThisInitializer_WithIfElseInDelegated.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_WithIfElseInDelegated.DotNet8_0.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_ThisInitializer_WithIfElseInDelegated.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithBaseInitializer.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithBaseInitializer.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithBaseInitializer.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithBaseInitializer.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithBaseInitializerAndIfElse.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithBaseInitializerAndIfElse.verified.txt similarity index 97% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithBaseInitializerAndIfElse.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithBaseInitializerAndIfElse.verified.txt index dad38a9..4ab74e1 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithBaseInitializerAndIfElse.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithBaseInitializerAndIfElse.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using EntityFrameworkCore.Projectables; using Foo; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithBaseInitializerExpression.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithBaseInitializerExpression.verified.txt similarity index 97% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithBaseInitializerExpression.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithBaseInitializerExpression.verified.txt index d207be7..8856d78 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithBaseInitializerExpression.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithBaseInitializerExpression.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using EntityFrameworkCore.Projectables; using Foo; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithBaseInitializer_AndIfElse_InDerivedBody.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithBaseInitializer_AndIfElse_InDerivedBody.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithBaseInitializer_AndIfElse_InDerivedBody.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithBaseInitializer_AndIfElse_InDerivedBody.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithClassArgument.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithClassArgument.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithClassArgument.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithClassArgument.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithDeepNestedIf.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithDeepNestedIf.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithDeepNestedIf.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithDeepNestedIf.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithElseIfChain.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithElseIfChain.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithElseIfChain.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithElseIfChain.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithExplicitParameterlessConstructor_Succeeds.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithExplicitParameterlessConstructor_Succeeds.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithExplicitParameterlessConstructor_Succeeds.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithExplicitParameterlessConstructor_Succeeds.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithIfElseLogic.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithIfElseLogic.verified.txt similarity index 97% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithIfElseLogic.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithIfElseLogic.verified.txt index 02c183c..5eeaf75 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithIfElseLogic.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithIfElseLogic.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using EntityFrameworkCore.Projectables; using Foo; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithIfInsideLocalScope_AndElse.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithIfInsideLocalScope_AndElse.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithIfInsideLocalScope_AndElse.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithIfInsideLocalScope_AndElse.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithIfNoElse.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithIfNoElse.verified.txt similarity index 97% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithIfNoElse.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithIfNoElse.verified.txt index 24a3e55..3a469f0 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithIfNoElse.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithIfNoElse.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using EntityFrameworkCore.Projectables; using Foo; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithLocalVariable.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithLocalVariable.verified.txt similarity index 97% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithLocalVariable.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithLocalVariable.verified.txt index bf93d90..d233058 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithLocalVariable.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithLocalVariable.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using EntityFrameworkCore.Projectables; using Foo; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithLocalVariableUsedInCondition.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithLocalVariableUsedInCondition.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithLocalVariableUsedInCondition.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithLocalVariableUsedInCondition.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithMultipleClassArguments.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithMultipleClassArguments.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithMultipleClassArguments.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithMultipleClassArguments.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithMultipleLocalVariables.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithMultipleLocalVariables.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithMultipleLocalVariables.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithMultipleLocalVariables.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithNestedIfElse.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithNestedIfElse.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithNestedIfElse.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithNestedIfElse.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithNullCoalescing.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithNullCoalescing.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithNullCoalescing.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithNullCoalescing.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithNullableParameter.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithNullableParameter.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithNullableParameter.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithNullableParameter.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithSequentialIfs.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithSequentialIfs.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithSequentialIfs.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithSequentialIfs.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithSwitchExpression.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithSwitchExpression.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithSwitchExpression.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithSwitchExpression.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithSwitchExpression_AndExtraProperty.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithSwitchExpression_AndExtraProperty.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithSwitchExpression_AndExtraProperty.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithSwitchExpression_AndExtraProperty.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithTernaryAssignment.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithTernaryAssignment.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithTernaryAssignment.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithTernaryAssignment.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithThisInitializer_AndElseIfInBody.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithThisInitializer_AndElseIfInBody.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_WithThisInitializer_AndElseIfInBody.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.ProjectableConstructor_WithThisInitializer_AndElseIfInBody.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.cs b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.cs new file mode 100644 index 0000000..3f9648e --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ConstructorTests.cs @@ -0,0 +1,1295 @@ +using System.Linq; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using VerifyXunit; +using Xunit; +using Xunit.Abstractions; + +namespace EntityFrameworkCore.Projectables.Generator.Tests; + +[UsesVerify] +public class ConstructorTests : ProjectionExpressionGeneratorTestsBase +{ + public ConstructorTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + [Fact] + public Task ProjectableConstructor_BodyAssignments() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class PointDto { + public int X { get; set; } + public int Y { get; set; } + + public PointDto() { } + + [Projectable] + public PointDto(int x, int y) { + X = x; + Y = y; + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_WithBaseInitializer() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class Base { + public int Id { get; set; } + public Base(int id) { Id = id; } + + protected Base() { } + } + + class Child : Base { + public string Name { get; set; } + + public Child() { } + + [Projectable] + public Child(int id, string name) : base(id) { + Name = name; + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_Overloads() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class PersonDto { + public string FirstName { get; set; } + public string LastName { get; set; } + + public PersonDto() { } + + [Projectable] + public PersonDto(string firstName, string lastName) { + FirstName = firstName; + LastName = lastName; + } + + [Projectable] + public PersonDto(string fullName) { + FirstName = fullName; + LastName = string.Empty; + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Equal(2, result.GeneratedTrees.Length); + + return Verifier.Verify(result.GeneratedTrees.OrderBy(t => t.FilePath).Select(t => t.ToString())); + } + + [Fact] + public Task ProjectableConstructor_WithClassArgument() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class SourceEntity { + public int Id { get; set; } + public string Name { get; set; } + } + + class PersonDto { + public int Id { get; set; } + public string Name { get; set; } + + public PersonDto() { } + + [Projectable] + public PersonDto(SourceEntity source) { + Id = source.Id; + Name = source.Name; + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_WithMultipleClassArguments() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class NamePart { + public string Value { get; set; } + } + + class PersonDto { + public string FirstName { get; set; } + public string LastName { get; set; } + + public PersonDto() { } + + [Projectable] + public PersonDto(NamePart first, NamePart last) { + FirstName = first.Value; + LastName = last.Value; + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_WithIfElseLogic() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class PersonDto { + public string Label { get; set; } + public int Score { get; set; } + + public PersonDto() { } + + [Projectable] + public PersonDto(int score) { + Score = score; + if (score >= 90) { + Label = ""A""; + } else { + Label = ""B""; + } + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_WithLocalVariable() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class PersonDto { + public string FullName { get; set; } + + public PersonDto() { } + + [Projectable] + public PersonDto(string first, string last) { + var full = first + "" "" + last; + FullName = full; + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_WithBaseInitializerExpression() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class Base { + public string Code { get; set; } + public Base(string code) { Code = code; } + + protected Base() { } + } + + class Child : Base { + public string Name { get; set; } + + public Child() { } + + [Projectable] + public Child(string name, string rawCode) : base(rawCode.ToUpper()) { + Name = name; + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_WithBaseInitializerAndIfElse() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class Base { + public int Id { get; set; } + public Base(int id) { + if (id < 0) { + Id = 0; + } else { + Id = id; + } + } + + protected Base() { } + } + + class Child : Base { + public string Name { get; set; } + + public Child() { } + + [Projectable] + public Child(int id, string name) : base(id) { + Name = name; + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_WithIfNoElse() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class PersonDto { + public string Label { get; set; } + + public PersonDto() { } + + [Projectable] + public PersonDto(int score) { + Label = ""none""; + if (score >= 90) { + Label = ""A""; + } + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_ReferencingPreviouslyAssignedProperty() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class PersonDto { + public string FirstName { get; set; } + public string LastName { get; set; } + public string FullName { get; set; } + + public PersonDto() { } + + [Projectable] + public PersonDto(string firstName, string lastName) { + FirstName = firstName; + LastName = lastName; + FullName = FirstName + "" "" + LastName; + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_ReferencingBasePropertyInDerivedBody() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class Base { + public string Code { get; set; } + public Base(string code) { Code = code; } + + protected Base() { } + } + + class Child : Base { + public string Label { get; set; } + + public Child() { } + + [Projectable] + public Child(string code) : base(code) { + Label = ""["" + Code + ""]""; + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_ReferencingStaticConstMember() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class PersonDto { + internal const string Separator = "" - ""; + public string FullName { get; set; } + + public PersonDto() { } + + [Projectable] + public PersonDto(string first, string last) { + FullName = first + Separator + last; + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_ReferencingPreviouslyAssignedInBaseCtor() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class Base { + public int X { get; set; } + public int Y { get; set; } + public Base(int x, int y) { + X = x; + Y = x + y; + } + + protected Base() { } + } + + class Child : Base { + public int Sum { get; set; } + + public Child() { } + + [Projectable] + public Child(int a, int b) : base(a, b) { + Sum = X + Y; + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_ThisInitializer_SimpleOverload() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class PersonDto { + public string FirstName { get; set; } + public string LastName { get; set; } + + public PersonDto() { } + + public PersonDto(string firstName, string lastName) { + FirstName = firstName; + LastName = lastName; + } + + [Projectable] + public PersonDto(string fullName) : this(fullName.Split(' ')[0], fullName.Split(' ')[1]) { + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_ThisInitializer_WithBodyAfter() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class PersonDto { + public string FirstName { get; set; } + public string LastName { get; set; } + public string FullName { get; set; } + + public PersonDto() { } + + public PersonDto(string firstName, string lastName) { + FirstName = firstName; + LastName = lastName; + } + + [Projectable] + public PersonDto(string fn, string ln, bool upper) : this(fn, ln) { + FullName = upper ? (FirstName + "" "" + LastName).ToUpper() : FirstName + "" "" + LastName; + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_ThisInitializer_WithIfElseInDelegated() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class PersonDto { + public string Label { get; set; } + public int Score { get; set; } + + public PersonDto() { } + + public PersonDto(int score) { + Score = score; + if (score >= 90) { + Label = ""A""; + } else { + Label = ""B""; + } + } + + [Projectable] + public PersonDto(int score, string prefix) : this(score) { + Label = prefix + Label; + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_ThisInitializer_ChainedThisAndBase() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class Base { + public int Id { get; set; } + public Base(int id) { Id = id; } + } + + class Child : Base { + public string Name { get; set; } + + public Child() : base(0) { } + + public Child(int id, string name) : base(id) { + Name = name; + } + + [Projectable] + public Child(int id, string name, string suffix) : this(id, name) { + Name = Name + suffix; + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_ThisInitializer_RefPreviouslyAssignedProperty() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class PersonDto { + public string FirstName { get; set; } + public string LastName { get; set; } + public string FullName { get; set; } + + public PersonDto() { } + + public PersonDto(string firstName, string lastName) { + FirstName = firstName; + LastName = lastName; + FullName = FirstName + "" "" + LastName; + } + + [Projectable] + public PersonDto(string firstName) : this(firstName, ""Doe"") { + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public void ProjectableConstructor_WithoutParameterlessConstructor_EmitsDiagnostic() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class PersonDto { + public string Name { get; set; } + + [Projectable] + public PersonDto(string name) { + Name = name; + } + } +} +"); + var result = RunGenerator(compilation); + + var diagnostic = Assert.Single(result.Diagnostics); + Assert.Equal("EFP0008", diagnostic.Id); + Assert.Equal(DiagnosticSeverity.Error, diagnostic.Severity); + Assert.Empty(result.GeneratedTrees); + } + + [Fact] + public Task ProjectableConstructor_WithExplicitParameterlessConstructor_Succeeds() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class PersonDto { + public string Name { get; set; } + + public PersonDto() { } + + [Projectable] + public PersonDto(string name) { + Name = name; + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_WithElseIfChain() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class GradeDto { + public string Grade { get; set; } + + public GradeDto() { } + + [Projectable] + public GradeDto(int score) { + if (score >= 90) { + Grade = ""A""; + } else if (score >= 75) { + Grade = ""B""; + } else if (score >= 60) { + Grade = ""C""; + } else { + Grade = ""F""; + } + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_WithNestedIfElse() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class StatusDto { + public string Status { get; set; } + + public StatusDto() { } + + [Projectable] + public StatusDto(bool isActive, bool isPremium) { + if (isActive) { + if (isPremium) { + Status = ""Active Premium""; + } else { + Status = ""Active Free""; + } + } else { + Status = ""Inactive""; + } + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public void ProjectableConstructor_WithEarlyReturn_GuardClause_EmitsDiagnostic() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class ItemDto { + public string Name { get; set; } + public string Category { get; set; } + + public ItemDto() { } + + [Projectable] + public ItemDto(string name, string category) { + Name = name; + if (string.IsNullOrEmpty(category)) { + Category = ""Unknown""; + return; + } + Category = category; + } + } +} +"); + var result = RunGenerator(compilation); + + var diagnostic = Assert.Single(result.Diagnostics); + Assert.Equal("EFP0003", diagnostic.Id); + Assert.Equal(DiagnosticSeverity.Warning, diagnostic.Severity); + } + + [Fact] + public void ProjectableConstructor_WithMultipleEarlyReturns_EmitsDiagnostic() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class PriorityDto { + public string Level { get; set; } + + public PriorityDto() { } + + [Projectable] + public PriorityDto(int value) { + if (value < 0) { + Level = ""Invalid""; + return; + } + if (value == 0) { + Level = ""None""; + return; + } + if (value <= 5) { + Level = ""Low""; + return; + } + Level = ""High""; + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.NotEmpty(result.Diagnostics); + Assert.All(result.Diagnostics, d => Assert.Equal("EFP0003", d.Id)); + Assert.All(result.Diagnostics, d => Assert.Equal(DiagnosticSeverity.Warning, d.Severity)); + } + + [Fact] + public Task ProjectableConstructor_WithSequentialIfs() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class FlagDto { + public string Tag { get; set; } + public bool IsVerified { get; set; } + public bool IsAdmin { get; set; } + + public FlagDto() { } + + [Projectable] + public FlagDto(string role, bool verified) { + Tag = role; + if (verified) { + IsVerified = true; + } + if (role == ""admin"") { + IsAdmin = true; + } + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_WithTernaryAssignment() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class LabelDto { + public string Label { get; set; } + public string Display { get; set; } + + public LabelDto() { } + + [Projectable] + public LabelDto(string name, bool uppercase) { + Label = name; + Display = uppercase ? name.ToUpper() : name.ToLower(); + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_WithNullCoalescing() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class ProductDto { + public string Name { get; set; } + public string Description { get; set; } + + public ProductDto() { } + + [Projectable] + public ProductDto(string name, string description) { + Name = name ?? ""Unnamed""; + Description = description ?? string.Empty; + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_WithSwitchExpression() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class SeasonDto { + public string Name { get; set; } + public string Description { get; set; } + + public SeasonDto() { } + + [Projectable] + public SeasonDto(int month) { + Name = month switch { + 12 or 1 or 2 => ""Winter"", + 3 or 4 or 5 => ""Spring"", + 6 or 7 or 8 => ""Summer"", + _ => ""Autumn"" + }; + Description = ""Month: "" + month; + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_WithMultipleLocalVariables() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class AddressDto { + public string Street { get; set; } + public string City { get; set; } + public string Full { get; set; } + + public AddressDto() { } + + [Projectable] + public AddressDto(string street, string city, string country) { + var trimmedStreet = street.Trim(); + var trimmedCity = city.Trim(); + Street = trimmedStreet; + City = trimmedCity; + Full = trimmedStreet + "", "" + trimmedCity + "", "" + country; + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_WithNullableParameter() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class MeasurementDto { + public double Value { get; set; } + public string Unit { get; set; } + + public MeasurementDto() { } + + [Projectable] + public MeasurementDto(double? value, string unit) { + Value = value ?? 0.0; + Unit = unit ?? ""m""; + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_WithLocalVariableUsedInCondition() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class RangeDto { + public int Min { get; set; } + public int Max { get; set; } + public bool IsValid { get; set; } + + public RangeDto() { } + + [Projectable] + public RangeDto(int a, int b) { + var lo = a < b ? a : b; + var hi = a < b ? b : a; + Min = lo; + Max = hi; + if (hi - lo > 0) { + IsValid = true; + } else { + IsValid = false; + } + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_WithBaseInitializer_AndIfElse_InDerivedBody() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class Animal { + public string Species { get; set; } + public Animal(string species) { Species = species; } + protected Animal() { } + } + + class Pet : Animal { + public string Name { get; set; } + public string Nickname { get; set; } + + public Pet() { } + + [Projectable] + public Pet(string species, string name, bool useShortName) : base(species) { + Name = name; + if (useShortName) { + Nickname = name.Length > 3 ? name.Substring(0, 3) : name; + } else { + Nickname = name; + } + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public void ProjectableConstructor_WithBaseInitializer_AndEarlyReturn_EmitsDiagnostic() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class Vehicle { + public string Type { get; set; } + public Vehicle(string type) { Type = type; } + protected Vehicle() { } + } + + class Car : Vehicle { + public string Model { get; set; } + public int Year { get; set; } + + public Car() { } + + [Projectable] + public Car(string model, int year) : base(""Car"") { + Model = model; + if (year <= 0) { + Year = 2000; + return; + } + Year = year; + } + } +} +"); + var result = RunGenerator(compilation); + + var diagnostic = Assert.Single(result.Diagnostics); + Assert.Equal("EFP0003", diagnostic.Id); + Assert.Equal(DiagnosticSeverity.Warning, diagnostic.Severity); + } + + [Fact] + public Task ProjectableConstructor_WithDeepNestedIf() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class AccessDto { + public string Access { get; set; } + + public AccessDto() { } + + [Projectable] + public AccessDto(bool isLoggedIn, bool isVerified, bool isAdmin) { + if (isLoggedIn) { + if (isVerified) { + if (isAdmin) { + Access = ""Full""; + } else { + Access = ""Verified""; + } + } else { + Access = ""Unverified""; + } + } else { + Access = ""Guest""; + } + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_WithIfInsideLocalScope_AndElse() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class OrderDto { + public string Status { get; set; } + public string Note { get; set; } + public bool NeedsReview { get; set; } + + public OrderDto() { } + + [Projectable] + public OrderDto(int amount, bool flagged) { + if (flagged) { + Status = ""Flagged""; + Note = ""Requires manual review""; + NeedsReview = true; + } else { + Status = amount > 1000 ? ""Large"" : ""Normal""; + Note = string.Empty; + NeedsReview = false; + } + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_WithThisInitializer_AndElseIfInBody() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class EventDto { + public string Title { get; set; } + public string Tag { get; set; } + public string Priority { get; set; } + + public EventDto() { } + + public EventDto(string title, string tag) { + Title = title; + Tag = tag; + } + + [Projectable] + public EventDto(string title, string tag, int urgency) : this(title, tag) { + if (urgency >= 10) { + Priority = ""Critical""; + } else if (urgency >= 5) { + Priority = ""High""; + } else { + Priority = ""Normal""; + } + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableConstructor_WithSwitchExpression_AndExtraProperty() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class ShapeDto { + public string ShapeType { get; set; } + public int Sides { get; set; } + public string Description { get; set; } + + public ShapeDto() { } + + [Projectable] + public ShapeDto(int sides) { + Sides = sides; + ShapeType = sides switch { + 3 => ""Triangle"", + 4 => ""Rectangle"", + 5 => ""Pentagon"", + _ => ""Polygon"" + }; + Description = ShapeType + "" with "" + sides + "" sides""; + } + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExpandEnumMethodsOnNavigationProperty.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/EnumTests.ExpandEnumMethodsOnNavigationProperty.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExpandEnumMethodsOnNavigationProperty.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/EnumTests.ExpandEnumMethodsOnNavigationProperty.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExpandEnumMethodsReturningBoolean.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/EnumTests.ExpandEnumMethodsReturningBoolean.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExpandEnumMethodsReturningBoolean.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/EnumTests.ExpandEnumMethodsReturningBoolean.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExpandEnumMethodsReturningInteger.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/EnumTests.ExpandEnumMethodsReturningInteger.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExpandEnumMethodsReturningInteger.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/EnumTests.ExpandEnumMethodsReturningInteger.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExpandEnumMethodsWithDescriptionAttribute.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/EnumTests.ExpandEnumMethodsWithDescriptionAttribute.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExpandEnumMethodsWithDescriptionAttribute.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/EnumTests.ExpandEnumMethodsWithDescriptionAttribute.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExpandEnumMethodsWithDisplayAttribute.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/EnumTests.ExpandEnumMethodsWithDisplayAttribute.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExpandEnumMethodsWithDisplayAttribute.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/EnumTests.ExpandEnumMethodsWithDisplayAttribute.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExpandEnumMethodsWithMultipleParameters.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/EnumTests.ExpandEnumMethodsWithMultipleParameters.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExpandEnumMethodsWithMultipleParameters.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/EnumTests.ExpandEnumMethodsWithMultipleParameters.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExpandEnumMethodsWithNullableEnum.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/EnumTests.ExpandEnumMethodsWithNullableEnum.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExpandEnumMethodsWithNullableEnum.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/EnumTests.ExpandEnumMethodsWithNullableEnum.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExpandEnumMethodsWithParameter.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/EnumTests.ExpandEnumMethodsWithParameter.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExpandEnumMethodsWithParameter.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/EnumTests.ExpandEnumMethodsWithParameter.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/EnumTests.cs b/tests/EntityFrameworkCore.Projectables.Generator.Tests/EnumTests.cs new file mode 100644 index 0000000..6046f45 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/EnumTests.cs @@ -0,0 +1,369 @@ +using System.Threading.Tasks; +using VerifyXunit; +using Xunit; +using Xunit.Abstractions; + +namespace EntityFrameworkCore.Projectables.Generator.Tests; + +[UsesVerify] +public class EnumTests : ProjectionExpressionGeneratorTestsBase +{ + public EnumTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + [Fact] + public Task ExpandEnumMethodsWithDisplayAttribute() + { + var compilation = CreateCompilation(@" +using System; +using System.ComponentModel.DataAnnotations; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public enum CustomEnum + { + [Display(Name = ""Value 1"")] + Value1, + + [Display(Name = ""Value 2"")] + Value2, + } + + public static class EnumExtensions + { + public static string GetDisplayName(this CustomEnum value) + { + return value.ToString(); + } + } + + public record Entity + { + public int Id { get; set; } + public CustomEnum MyValue { get; set; } + + [Projectable(ExpandEnumMethods = true)] + public string MyEnumName => MyValue.GetDisplayName(); + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ExpandEnumMethodsWithNullableEnum() + { + var compilation = CreateCompilation(@" +using System; +using System.ComponentModel.DataAnnotations; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public enum CustomEnum + { + [Display(Name = ""First Value"")] + First, + + [Display(Name = ""Second Value"")] + Second, + } + + public static class EnumExtensions + { + public static string GetDisplayName(this CustomEnum value) + { + return value.ToString(); + } + } + + public record Entity + { + public int Id { get; set; } + public CustomEnum? MyValue { get; set; } + + [Projectable(ExpandEnumMethods = true)] + public string MyEnumName => MyValue.HasValue ? MyValue.Value.GetDisplayName() : null; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ExpandEnumMethodsWithDescriptionAttribute() + { + var compilation = CreateCompilation(@" +using System; +using System.ComponentModel; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public enum Status + { + [Description(""The item is pending"")] + Pending, + + [Description(""The item is approved"")] + Approved, + + [Description(""The item is rejected"")] + Rejected, + } + + public static class EnumExtensions + { + public static string GetDescription(this Status value) + { + return value.ToString(); + } + } + + public record Entity + { + public int Id { get; set; } + public Status Status { get; set; } + + [Projectable(ExpandEnumMethods = true)] + public string StatusDescription => Status.GetDescription(); + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ExpandEnumMethodsOnNavigationProperty() + { + var compilation = CreateCompilation(@" +using System; +using System.ComponentModel.DataAnnotations; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public enum OrderStatus + { + [Display(Name = ""Pending Review"")] + Pending, + + [Display(Name = ""Approved"")] + Approved, + } + + public static class EnumExtensions + { + public static string GetDisplayName(this OrderStatus value) + { + return value.ToString(); + } + } + + public record Order + { + public int Id { get; set; } + public OrderStatus Status { get; set; } + } + + public record OrderItem + { + public int Id { get; set; } + public Order Order { get; set; } + + [Projectable(ExpandEnumMethods = true)] + public string OrderStatusName => Order.Status.GetDisplayName(); + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ExpandEnumMethodsReturningBoolean() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public enum Status + { + Pending, + Approved, + Rejected, + } + + public static class EnumExtensions + { + public static bool IsApproved(this Status value) + { + return value == Status.Approved; + } + } + + public record Entity + { + public int Id { get; set; } + public Status Status { get; set; } + + [Projectable(ExpandEnumMethods = true)] + public bool IsStatusApproved => Status.IsApproved(); + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ExpandEnumMethodsReturningInteger() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public enum Priority + { + Low, + Medium, + High, + } + + public static class EnumExtensions + { + public static int GetSortOrder(this Priority value) + { + return (int)value; + } + } + + public record Entity + { + public int Id { get; set; } + public Priority Priority { get; set; } + + [Projectable(ExpandEnumMethods = true)] + public int PrioritySortOrder => Priority.GetSortOrder(); + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ExpandEnumMethodsWithParameter() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public enum Status + { + Pending, + Approved, + Rejected, + } + + public static class EnumExtensions + { + public static string GetDisplayNameWithPrefix(this Status value, string prefix) + { + return prefix + value.ToString(); + } + } + + public record Entity + { + public int Id { get; set; } + public Status Status { get; set; } + + [Projectable(ExpandEnumMethods = true)] + public string StatusWithPrefix => Status.GetDisplayNameWithPrefix(""Status: ""); + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ExpandEnumMethodsWithMultipleParameters() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public enum Status + { + Pending, + Approved, + Rejected, + } + + public static class EnumExtensions + { + public static string Format(this Status value, string prefix, string suffix) + { + return prefix + value.ToString() + suffix; + } + } + + public record Entity + { + public int Id { get; set; } + public Status Status { get; set; } + + [Projectable(ExpandEnumMethods = true)] + public string FormattedStatus => Status.Format(""["", ""]""); + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberMethod.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMemberTests.ExtensionMemberMethod.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberMethod.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMemberTests.ExtensionMemberMethod.verified.txt index e0d8932..fe2e82e 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberMethod.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMemberTests.ExtensionMemberMethod.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using EntityFrameworkCore.Projectables; @@ -14,4 +14,4 @@ namespace EntityFrameworkCore.Projectables.Generated return (global::Foo.Entity @this) => @this.Id * 3; } } -} +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberMethodWithParameters.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMemberTests.ExtensionMemberMethodWithParameters.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberMethodWithParameters.DotNet10_0.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMemberTests.ExtensionMemberMethodWithParameters.verified.txt index 837945b..0b278df 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberMethodWithParameters.DotNet10_0.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMemberTests.ExtensionMemberMethodWithParameters.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using EntityFrameworkCore.Projectables; @@ -14,4 +14,4 @@ namespace EntityFrameworkCore.Projectables.Generated return (global::Foo.Entity @this, int factor) => @this.Id * factor; } } -} +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberOnInterface.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMemberTests.ExtensionMemberOnInterface.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberOnInterface.DotNet10_0.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMemberTests.ExtensionMemberOnInterface.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberOnPrimitive.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMemberTests.ExtensionMemberOnPrimitive.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberOnPrimitive.DotNet10_0.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMemberTests.ExtensionMemberOnPrimitive.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberProperty.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMemberTests.ExtensionMemberProperty.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberProperty.DotNet10_0.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMemberTests.ExtensionMemberProperty.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberWithBlockBody.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMemberTests.ExtensionMemberWithBlockBody.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberWithBlockBody.DotNet10_0.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMemberTests.ExtensionMemberWithBlockBody.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberWithIsPatternExpression.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMemberTests.ExtensionMemberWithIsPatternExpression.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberWithIsPatternExpression.DotNet10_0.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMemberTests.ExtensionMemberWithIsPatternExpression.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberWithMemberAccess.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMemberTests.ExtensionMemberWithMemberAccess.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberWithMemberAccess.DotNet10_0.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMemberTests.ExtensionMemberWithMemberAccess.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberWithSwitchExpression.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMemberTests.ExtensionMemberWithSwitchExpression.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberWithSwitchExpression.DotNet10_0.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMemberTests.ExtensionMemberWithSwitchExpression.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMemberTests.cs b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMemberTests.cs new file mode 100644 index 0000000..e8552be --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMemberTests.cs @@ -0,0 +1,285 @@ +using System.Threading.Tasks; +using VerifyXunit; +using Xunit; +using Xunit.Abstractions; + +namespace EntityFrameworkCore.Projectables.Generator.Tests; + +[UsesVerify] +public class ExtensionMemberTests : ProjectionExpressionGeneratorTestsBase +{ + public ExtensionMemberTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + +#if NET10_0_OR_GREATER + [Fact] + public Task ExtensionMemberProperty() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; + +namespace Foo { + class Entity { + public int Id { get; set; } + } + + static class EntityExtensions { + extension(Entity e) { + [Projectable] + public int DoubleId => e.Id * 2; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ExtensionMemberMethod() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; + +namespace Foo { + class Entity { + public int Id { get; set; } + } + + static class EntityExtensions { + extension(Entity e) { + [Projectable] + public int TripleId() => e.Id * 3; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ExtensionMemberMethodWithParameters() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; + +namespace Foo { + class Entity { + public int Id { get; set; } + } + + static class EntityExtensions { + extension(Entity e) { + [Projectable] + public int Multiply(int factor) => e.Id * factor; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ExtensionMemberOnPrimitive() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; + +static class IntExtensions { + extension(int i) { + [Projectable] + public int Squared => i * i; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ExtensionMemberWithMemberAccess() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; + +namespace Foo { + class Entity { + public int Id { get; set; } + public string Name { get; set; } + } + + static class EntityExtensions { + extension(Entity e) { + [Projectable] + public string IdAndName => e.Id + "": "" + e.Name; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ExtensionMemberWithBlockBody() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; + +namespace Foo { + class Entity { + public int Value { get; set; } + public bool IsActive { get; set; } + } + + static class EntityExtensions { + extension(Entity e) { + [Projectable(AllowBlockBody = true)] + public string GetStatus() + { + if (e.IsActive && e.Value > 0) + { + return ""Active""; + } + return ""Inactive""; + } + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ExtensionMemberWithSwitchExpression() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; + +namespace Foo { + class Entity { + public int Score { get; set; } + } + + static class EntityExtensions { + extension(Entity e) { + [Projectable] + public string GetGrade() => e.Score switch + { + >= 90 => ""A"", + >= 80 => ""B"", + >= 70 => ""C"", + _ => ""F"", + }; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ExtensionMemberOnInterface() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; + +namespace Foo { + interface IEntity { + int Id { get; } + string Name { get; } + } + + static class IEntityExtensions { + extension(IEntity e) { + [Projectable] + public string Label => e.Id + "": "" + e.Name; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ExtensionMemberWithIsPatternExpression() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; + +namespace Foo { + class Entity { + public int Value { get; set; } + } + + static class EntityExtensions { + extension(Entity e) { + [Projectable] + public bool IsHighValue => e.Value is > 100; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } +#endif +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableExtensionMethod.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMethodTests.ProjectableExtensionMethod.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableExtensionMethod.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMethodTests.ProjectableExtensionMethod.verified.txt index 8e8012f..f473738 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableExtensionMethod.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMethodTests.ProjectableExtensionMethod.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableExtensionMethod2.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMethodTests.ProjectableExtensionMethod2.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableExtensionMethod2.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMethodTests.ProjectableExtensionMethod2.verified.txt index b17f73b..c6d1a9d 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableExtensionMethod2.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMethodTests.ProjectableExtensionMethod2.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableExtensionMethod3.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMethodTests.ProjectableExtensionMethod3.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableExtensionMethod3.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMethodTests.ProjectableExtensionMethod3.verified.txt index bf3ca9c..25e7d8a 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableExtensionMethod3.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMethodTests.ProjectableExtensionMethod3.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableExtensionMethod4.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMethodTests.ProjectableExtensionMethod4.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableExtensionMethod4.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMethodTests.ProjectableExtensionMethod4.verified.txt index 03de978..3ea7b53 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableExtensionMethod4.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMethodTests.ProjectableExtensionMethod4.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMethodTests.cs b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMethodTests.cs new file mode 100644 index 0000000..54e36af --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ExtensionMethodTests.cs @@ -0,0 +1,109 @@ +using System.Threading.Tasks; +using VerifyXunit; +using Xunit; +using Xunit.Abstractions; + +namespace EntityFrameworkCore.Projectables.Generator.Tests; + +[UsesVerify] +public class ExtensionMethodTests : ProjectionExpressionGeneratorTestsBase +{ + public ExtensionMethodTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + [Fact] + public Task ProjectableExtensionMethod() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using EntityFrameworkCore.Projectables; +namespace Foo { + class D { } + + static class C { + [Projectable] + public static int Foo(this D d) => 1; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableExtensionMethod2() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using EntityFrameworkCore.Projectables; +namespace Foo { + static class C { + [Projectable] + public static int Foo(this int i) => i; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableExtensionMethod3() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using EntityFrameworkCore.Projectables; +namespace Foo { + static class C { + [Projectable] + public static int Foo1(this int i) => i; + + [Projectable] + public static int Foo2(this int i) => i.Foo1(); + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Equal(2, result.GeneratedTrees.Length); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableExtensionMethod4() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using EntityFrameworkCore.Projectables; +namespace Foo { + static class C { + [Projectable] + public static object Foo1(this object i) => i.Foo1(); + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.GenericClassesWithContraints_AreRewritten.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/GenericTests.GenericClassesWithContraints_AreRewritten.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.GenericClassesWithContraints_AreRewritten.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/GenericTests.GenericClassesWithContraints_AreRewritten.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.GenericClassesWithTypeContraints_AreRewritten.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/GenericTests.GenericClassesWithTypeContraints_AreRewritten.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.GenericClassesWithTypeContraints_AreRewritten.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/GenericTests.GenericClassesWithTypeContraints_AreRewritten.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.GenericMethods_AreRewritten.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/GenericTests.GenericMethods_AreRewritten.verified.txt similarity index 96% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.GenericMethods_AreRewritten.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/GenericTests.GenericMethods_AreRewritten.verified.txt index 973cde3..aa77e0e 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.GenericMethods_AreRewritten.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/GenericTests.GenericMethods_AreRewritten.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.GenericTypes.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/GenericTests.GenericTypes.verified.txt similarity index 94% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.GenericTypes.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/GenericTests.GenericTypes.verified.txt index 4c06e39..e496376 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.GenericTypes.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/GenericTests.GenericTypes.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using EntityFrameworkCore.Projectables; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.GenericTypesWithConstraints.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/GenericTests.GenericTypesWithConstraints.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.GenericTypesWithConstraints.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/GenericTests.GenericTypesWithConstraints.verified.txt index 8fd234b..bf57240 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.GenericTypesWithConstraints.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/GenericTests.GenericTypesWithConstraints.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using EntityFrameworkCore.Projectables; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/GenericTests.cs b/tests/EntityFrameworkCore.Projectables.Generator.Tests/GenericTests.cs new file mode 100644 index 0000000..3bc651b --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/GenericTests.cs @@ -0,0 +1,151 @@ +using System.Threading.Tasks; +using VerifyXunit; +using Xunit; +using Xunit.Abstractions; + +namespace EntityFrameworkCore.Projectables.Generator.Tests; + +[UsesVerify] +public class GenericTests : ProjectionExpressionGeneratorTestsBase +{ + public GenericTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + [Fact] + public Task GenericMethods_AreRewritten() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using System.Collections.Generic; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public static class EntityExtensions + { + public record Entity + { + public int Id { get; set; } + public string? FullName { get; set; } + } + + [Projectable] + public static string EnforceString(T value) where T : unmanaged + => value.ToString(); + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task GenericClassesWithContraints_AreRewritten() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using System.Collections.Generic; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public class TypedObject where TEnum : struct, System.Enum + { + public TEnum SomeProp { get; set; } + } + + public abstract class Entitywhere T : TypedObject where TEnum : struct, System.Enum + { + public int Id { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public T SomeSubobject { get; set; } + + [Projectable] + public string FullName => $""{FirstName} {LastName} {SomeSubobject.SomeProp}""; + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task GenericClassesWithTypeContraints_AreRewritten() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using System.Collections.Generic; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public abstract class Entity where T : notnull + { + public int Id { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public T SomeSubobject { get; set; } + + [Projectable] + public string FullName => $""{FirstName} {LastName} {SomeSubobject}""; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task GenericTypes() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +class EntiyBase { + [Projectable] + public static TId GetId() => default; +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task GenericTypesWithConstraints() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; + +class EntityBase where TId : ICloneable, new() { + [Projectable] + public static TId GetId() => default; +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.DefaultExplicitInterfaceMember.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/InterfaceTests.DefaultExplicitInterfaceMember.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.DefaultExplicitInterfaceMember.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/InterfaceTests.DefaultExplicitInterfaceMember.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.DefaultInterfaceMember.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/InterfaceTests.DefaultInterfaceMember.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.DefaultInterfaceMember.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/InterfaceTests.DefaultInterfaceMember.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExplicitInterfaceImplementation.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/InterfaceTests.ExplicitInterfaceImplementation.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExplicitInterfaceImplementation.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/InterfaceTests.ExplicitInterfaceImplementation.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExplicitInterfaceMember.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/InterfaceTests.ExplicitInterfaceMember.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExplicitInterfaceMember.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/InterfaceTests.ExplicitInterfaceMember.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/InterfaceTests.cs b/tests/EntityFrameworkCore.Projectables.Generator.Tests/InterfaceTests.cs new file mode 100644 index 0000000..5e46b48 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/InterfaceTests.cs @@ -0,0 +1,141 @@ +using System.Threading.Tasks; +using VerifyXunit; +using Xunit; +using Xunit.Abstractions; + +namespace EntityFrameworkCore.Projectables.Generator.Tests; + +[UsesVerify] +public class InterfaceTests : ProjectionExpressionGeneratorTestsBase +{ + public InterfaceTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + [Fact] + public Task ExplicitInterfaceMember() + { + var compilation = CreateCompilation( + """ + using System; + using EntityFrameworkCore.Projectables; + + public interface IBase + { + int ComputedProperty { get; } + } + + public class Concrete : IBase + { + public int Id { get; } + + [Projectable] + int IBase.ComputedProperty => Id + 1; + } + """); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task DefaultInterfaceMember() + { + var compilation = CreateCompilation( + """ + using System; + using EntityFrameworkCore.Projectables; + + public interface IBase + { + int Id { get; } + int ComputedProperty { get; } + int ComputedMethod(); + } + + public interface IDefaultBase : IBase + { + [Projectable] + int Default => ComputedProperty * 2; + } + """); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task DefaultExplicitInterfaceMember() + { + var compilation = CreateCompilation( + """ + using System; + using EntityFrameworkCore.Projectables; + + public interface IBase + { + int Id { get; } + int ComputedProperty { get; } + int ComputedMethod(); + } + + public interface IDefaultBase + { + int Default { get; } + } + + public interface IDefaultBaseImplementation : IDefaultBase, IBase + { + [Projectable] + int IDefaultBase.Default => ComputedProperty * 2; + } + """); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ExplicitInterfaceImplementation() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public interface IStringId + { + string Id { get; } + } + + public class Item : IStringId + { + public int Id { get; set; } + + // Explicit interface implementation without [Projectable] + string IStringId.Id => Id.ToString(); + + [Projectable] + public string FormattedId => ((IStringId)this).Id; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ArgumentlessProjectableComputedMethod.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.ArgumentlessProjectableComputedMethod.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ArgumentlessProjectableComputedMethod.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.ArgumentlessProjectableComputedMethod.verified.txt index fa2d4ec..2d48bd4 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ArgumentlessProjectableComputedMethod.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.ArgumentlessProjectableComputedMethod.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using EntityFrameworkCore.Projectables; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BaseMemberExplicitReference.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.BaseMemberExplicitReference.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BaseMemberExplicitReference.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.BaseMemberExplicitReference.verified.txt index 682df68..6544cf9 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BaseMemberExplicitReference.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.BaseMemberExplicitReference.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using EntityFrameworkCore.Projectables; using Projectables.Repro; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BaseMemberImplicitReference.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.BaseMemberImplicitReference.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BaseMemberImplicitReference.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.BaseMemberImplicitReference.verified.txt index 682df68..6544cf9 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BaseMemberImplicitReference.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.BaseMemberImplicitReference.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using EntityFrameworkCore.Projectables; using Projectables.Repro; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BaseMethorImplicitReference.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.BaseMethodExplicitReference.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BaseMethorImplicitReference.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.BaseMethodExplicitReference.verified.txt index fe999c7..56ee353 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BaseMethorImplicitReference.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.BaseMethodExplicitReference.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using EntityFrameworkCore.Projectables; using Projectables.Repro; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BaseMethodExplicitReference.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.BaseMethorImplicitReference.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BaseMethodExplicitReference.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.BaseMethorImplicitReference.verified.txt index fe999c7..56ee353 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BaseMethodExplicitReference.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.BaseMethorImplicitReference.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using EntityFrameworkCore.Projectables; using Projectables.Repro; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.Cast.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.Cast.verified.txt similarity index 96% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.Cast.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.Cast.verified.txt index cf931bf..525720b 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.Cast.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.Cast.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using EntityFrameworkCore.Projectables; using Projectables.Repro; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ConstMember3.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.ConstMember.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ConstMember3.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.ConstMember.verified.txt index d467476..191ae28 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ConstMember3.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.ConstMember.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.StaticMembers2.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.ConstMember2.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.StaticMembers2.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.ConstMember2.verified.txt index 5c768e9..e2d943d 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.StaticMembers2.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.ConstMember2.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.StaticMembers.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.ConstMember3.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.StaticMembers.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.ConstMember3.verified.txt index d467476..191ae28 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.StaticMembers.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.ConstMember3.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.DeclarationTypeNamesAreGettingFullyQualified.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.DeclarationTypeNamesAreGettingFullyQualified.verified.txt similarity index 96% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.DeclarationTypeNamesAreGettingFullyQualified.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.DeclarationTypeNamesAreGettingFullyQualified.verified.txt index cec10d1..153a1f1 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.DeclarationTypeNamesAreGettingFullyQualified.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.DeclarationTypeNamesAreGettingFullyQualified.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.DefaultValuesGetRemoved.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.DefaultValuesGetRemoved.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.DefaultValuesGetRemoved.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.DefaultValuesGetRemoved.verified.txt index b0c3e64..57bce24 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.DefaultValuesGetRemoved.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.DefaultValuesGetRemoved.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using EntityFrameworkCore.Projectables; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.EnumAccessor.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.EnumAccessor.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.EnumAccessor.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.EnumAccessor.verified.txt index d108871..1dc6812 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.EnumAccessor.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.EnumAccessor.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using EntityFrameworkCore.Projectables; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.InheritedMembers.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.InheritedMembers.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.InheritedMembers.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.InheritedMembers.verified.txt index f2157d2..dbe94a4 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.InheritedMembers.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.InheritedMembers.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.IsOperator.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.IsOperator.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.IsOperator.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.IsOperator.verified.txt index 55a8bc3..382a881 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.IsOperator.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.IsOperator.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.MethodOverloads_WithDifferentParameterCounts.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.MethodOverloads_WithDifferentParameterCounts.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.MethodOverloads_WithDifferentParameterCounts.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.MethodOverloads_WithDifferentParameterCounts.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.MethodOverloads_WithDifferentParameterTypes.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.MethodOverloads_WithDifferentParameterTypes.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.MethodOverloads_WithDifferentParameterTypes.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.MethodOverloads_WithDifferentParameterTypes.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.MixPrimaryConstructorAndProperties.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.MixPrimaryConstructorAndProperties.verified.txt similarity index 97% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.MixPrimaryConstructorAndProperties.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.MixPrimaryConstructorAndProperties.verified.txt index 84bf825..eb39b4b 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.MixPrimaryConstructorAndProperties.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.MixPrimaryConstructorAndProperties.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ParamsModifiedGetsRemoved.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.ParamsModifiedGetsRemoved.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ParamsModifiedGetsRemoved.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.ParamsModifiedGetsRemoved.verified.txt index 4231778..c9bfda4 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ParamsModifiedGetsRemoved.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.ParamsModifiedGetsRemoved.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using EntityFrameworkCore.Projectables; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableComputedMethodWithMultipleArguments.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.ProjectableComputedMethodWithMultipleArguments.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableComputedMethodWithMultipleArguments.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.ProjectableComputedMethodWithMultipleArguments.verified.txt index 6a50a32..cc9ef2b 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableComputedMethodWithMultipleArguments.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.ProjectableComputedMethodWithMultipleArguments.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using EntityFrameworkCore.Projectables; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableComputedMethodWithSingleArgument.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.ProjectableComputedMethodWithSingleArgument.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableComputedMethodWithSingleArgument.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.ProjectableComputedMethodWithSingleArgument.verified.txt index 864fb95..c6344cb 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableComputedMethodWithSingleArgument.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.ProjectableComputedMethodWithSingleArgument.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using EntityFrameworkCore.Projectables; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.RequiredNamespace.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.RequiredNamespace.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.RequiredNamespace.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.RequiredNamespace.verified.txt index 08e611e..a2fab55 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.RequiredNamespace.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.RequiredNamespace.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using EntityFrameworkCore.Projectables; using One.Two; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectablePropertyWithExplicitBlockGetter.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.SimpleProjectableMethod.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectablePropertyWithExplicitBlockGetter.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.SimpleProjectableMethod.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ConstMember.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.StaticMembers.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ConstMember.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.StaticMembers.verified.txt index d467476..191ae28 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ConstMember.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.StaticMembers.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ConstMember2.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.StaticMembers2.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ConstMember2.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.StaticMembers2.verified.txt index 5c768e9..e2d943d 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ConstMember2.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.StaticMembers2.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.StaticMethodWithNoParameters.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.StaticMethodWithNoParameters.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.StaticMethodWithNoParameters.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.StaticMethodWithNoParameters.verified.txt index e170859..4e25fd2 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.StaticMethodWithNoParameters.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.StaticMethodWithNoParameters.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.StaticMethodWithParameters.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.StaticMethodWithParameters.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.StaticMethodWithParameters.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.StaticMethodWithParameters.verified.txt index f5a9570..e1745ef 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.StaticMethodWithParameters.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.StaticMethodWithParameters.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.StringInterpolationWithParenthesis_NoParenthesisAdded.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.StringInterpolationWithParenthesis_NoParenthesisAdded.verified.txt similarity index 96% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.StringInterpolationWithParenthesis_NoParenthesisAdded.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.StringInterpolationWithParenthesis_NoParenthesisAdded.verified.txt index 6e33afa..caf66f8 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.StringInterpolationWithParenthesis_NoParenthesisAdded.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.StringInterpolationWithParenthesis_NoParenthesisAdded.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.StringInterpolationWithStaticCall_IsBeingRewritten.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.StringInterpolationWithStaticCall_IsBeingRewritten.verified.txt similarity index 96% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.StringInterpolationWithStaticCall_IsBeingRewritten.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.StringInterpolationWithStaticCall_IsBeingRewritten.verified.txt index 6e33afa..caf66f8 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.StringInterpolationWithStaticCall_IsBeingRewritten.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.StringInterpolationWithStaticCall_IsBeingRewritten.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.TypesInBodyGetsFullyQualified.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.TypesInBodyGetsFullyQualified.verified.txt similarity index 96% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.TypesInBodyGetsFullyQualified.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.TypesInBodyGetsFullyQualified.verified.txt index 06f2ded..6b3e666 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.TypesInBodyGetsFullyQualified.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.TypesInBodyGetsFullyQualified.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.cs b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.cs new file mode 100644 index 0000000..ef3da1a --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/MethodTests.cs @@ -0,0 +1,804 @@ +using System.Linq; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using VerifyXunit; +using Xunit; +using Xunit.Abstractions; + +namespace EntityFrameworkCore.Projectables.Generator.Tests; + +[UsesVerify] +public class MethodTests : ProjectionExpressionGeneratorTestsBase +{ + public MethodTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + [Fact] + public Task SimpleProjectableMethod() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + [Projectable] + public int Foo() => 1; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ArgumentlessProjectableComputedMethod() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + [Projectable] + public int Foo() => 0; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableComputedMethodWithSingleArgument() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + [Projectable] + public int Foo(int i) => i; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableComputedMethodWithMultipleArguments() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + [Projectable] + public int Foo(int a, string b, object d) => a; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task StaticMethodWithNoParameters() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using System.Collections.Generic; +using EntityFrameworkCore.Projectables; + +public static class Foo { + [Projectable] + public static int Zero() => 0; +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task StaticMethodWithParameters() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using System.Collections.Generic; +using EntityFrameworkCore.Projectables; + +public static class Foo { + [Projectable] + public static int Zero(int x) => 0; +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task StaticMembers() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using System.Collections.Generic; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public class Foo { + public static int Bar { get; set; } + + public int Id { get; set; } + + [Projectable] + public int IdWithBar() => Id + Bar; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task StaticMembers2() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using System.Collections.Generic; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public static class Constants { + public static readonly int Bar = 1; + } + + public class Foo { + public int Id { get; set; } + + [Projectable] + public int IdWithBar() => Id + Constants.Bar; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ConstMember() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using System.Collections.Generic; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public class Foo { + public const int Bar = 1; + + public int Id { get; set; } + + [Projectable] + public int IdWithBar() => Id + Bar; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ConstMember2() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using System.Collections.Generic; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public static class Constants { + public const int Bar = 1; + } + + public class Foo { + public int Id { get; set; } + + [Projectable] + public int IdWithBar() => Id + Constants.Bar; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ConstMember3() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using System.Collections.Generic; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public class Foo { + public const int Bar = 1; + + public int Id { get; set; } + + [Projectable] + public int IdWithBar() => Id + Foo.Bar; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task DefaultValuesGetRemoved() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +class Foo { + [Projectable] + public int Calculate(int i = 0) => i; +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ParamsModifiedGetsRemoved() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +class Foo { + [Projectable] + public int First(params int[] all) => all[0]; +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task MethodOverloads_WithDifferentParameterTypes() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + [Projectable] + public int Method(int x) => x; + + [Projectable] + public int Method(string s) => s.Length; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Equal(2, result.GeneratedTrees.Length); + + var generatedFiles = result.GeneratedTrees.Select(t => t.FilePath).ToList(); + Assert.Contains(generatedFiles, f => f.Contains("Method_P0_int.g.cs")); + Assert.Contains(generatedFiles, f => f.Contains("Method_P0_string.g.cs")); + + return Verifier.Verify(result.GeneratedTrees.Select(t => t.ToString())); + } + + [Fact] + public Task MethodOverloads_WithDifferentParameterCounts() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + [Projectable] + public int Method(int x) => x; + + [Projectable] + public int Method(int x, int y) => x + y; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Equal(2, result.GeneratedTrees.Length); + + var generatedFiles = result.GeneratedTrees.Select(t => t.FilePath).ToList(); + Assert.Contains(generatedFiles, f => f.Contains("Method_P0_int.g.cs")); + Assert.Contains(generatedFiles, f => f.Contains("Method_P0_int_P1_int.g.cs")); + + return Verifier.Verify(result.GeneratedTrees.Select(t => t.ToString())); + } + + [Fact] + public Task InheritedMembers() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using System.Collections.Generic; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public class Foo { + public int Id { get; set; } + } + + public class Bar : Foo { + [Projectable] + public int ProjectedId => Id; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BaseMemberExplicitReference() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Projectables.Repro; + +class Base +{ + public string Foo { get; set; } +} + +class Derived : Base +{ + [Projectable] + public string Bar => base.Foo; +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BaseMemberImplicitReference() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Projectables.Repro; + +class Base +{ + public string Foo { get; set; } +} + +class Derived : Base +{ + [Projectable] + public string Bar => Foo; +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BaseMethodExplicitReference() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Projectables.Repro; + +class Base +{ + public string Foo() => """"; +} + +class Derived : Base +{ + [Projectable] + public string Bar => base.Foo(); +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BaseMethorImplicitReference() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Projectables.Repro; + +class Base +{ + public string Foo() => """"; +} + +class Derived : Base +{ + [Projectable] + public string Bar => Foo(); +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task IsOperator() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using EntityFrameworkCore.Projectables; +namespace Foo { + class A { + [Projectable] + public bool IsB => this is B; + } + + class B : A { + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task Cast() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Projectables.Repro; + +public class SuperEntity : SomeEntity +{ + public string Superpower { get; set; } +} + +public class SomeEntity +{ + public int Id { get; set; } +} + +public static class SomeExtensions +{ + [Projectable] + public static string AsSomeResult(this SomeEntity e) => ((SuperEntity)e).Superpower; +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task EnumAccessor() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +public enum SomeFlag +{ + Foo +} + +public static class SomeExtensions +{ + [Projectable] + public static bool Test(this SomeFlag f) => f == SomeFlag.Foo; +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task StringInterpolationWithStaticCall_IsBeingRewritten() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using EntityFrameworkCore.Projectables; + +namespace Foo { + static class MyExtensions { + public static string ToDateString(this DateTime date) => date.ToString(""dd/MM/yyyy""); + } + + class C { + public DateTime? ValidationDate { get; set; } + + [Projectable] + public string Status => ValidationDate != null ? $""Validation date : ({ValidationDate.Value.ToDateString()})"" : """"; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task StringInterpolationWithParenthesis_NoParenthesisAdded() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using EntityFrameworkCore.Projectables; + +namespace Foo { + static class MyExtensions { + public static string ToDateString(this DateTime date) => date.ToString(""dd/MM/yyyy""); + } + + class C { + public DateTime? ValidationDate { get; set; } + + [Projectable] + public string Status => ValidationDate != null ? $""Validation date : ({(ValidationDate.Value.ToDateString())})"" : """"; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task TypesInBodyGetsFullyQualified() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using EntityFrameworkCore.Projectables; +namespace Foo { + class D { } + + class C { + public System.Collections.Generic.List Dees { get; set; } + + [Projectable] + public int Foo => Dees.OfType().Count(); + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task DeclarationTypeNamesAreGettingFullyQualified() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using System.Collections.Generic; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public static class EntityExtensions + { + public record Entity + { + public int Id { get; set; } + public string? FullName { get; set; } + + [Projectable] + public static Entity Something(Entity entity) + => entity; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task MixPrimaryConstructorAndProperties() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using System.Collections.Generic; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public static class EntityExtensions + { + public record Entity(int Id) + { + public int Id { get; set; } + public string? FullName { get; set; } + + [Projectable] + public static Entity Something(Entity entity) + => new Entity(entity.Id) { + FullName = entity.FullName + }; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task RequiredNamespace() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace One { + static class IntExtensions { + public static int AddOne(this int i) => i + 1; + } +} + +namespace One.Two { + class Bar { + [Projectable] + public int Method() => 1.AddOne(); + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BooleanSimpleTernary_WithRewriteSupport_IsBeingRewritten.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.BooleanSimpleTernary_WithRewriteSupport_IsBeingRewritten.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BooleanSimpleTernary_WithRewriteSupport_IsBeingRewritten.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.BooleanSimpleTernary_WithRewriteSupport_IsBeingRewritten.verified.txt index 8fb3344..e64abfa 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.BooleanSimpleTernary_WithRewriteSupport_IsBeingRewritten.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.BooleanSimpleTernary_WithRewriteSupport_IsBeingRewritten.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.GenericNullableReferenceTypesAreBeingEliminated.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.GenericNullableReferenceTypesAreBeingEliminated.verified.txt similarity index 97% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.GenericNullableReferenceTypesAreBeingEliminated.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.GenericNullableReferenceTypesAreBeingEliminated.verified.txt index 0993caa..490c579 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.GenericNullableReferenceTypesAreBeingEliminated.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.GenericNullableReferenceTypesAreBeingEliminated.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Collections.Generic; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullConditionalNullCoalesceTypeConversion.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullConditionalNullCoalesceTypeConversion.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullConditionalNullCoalesceTypeConversion.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullConditionalNullCoalesceTypeConversion.verified.txt index f366397..fe04612 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullConditionalNullCoalesceTypeConversion.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullConditionalNullCoalesceTypeConversion.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using EntityFrameworkCore.Projectables; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableElementAndMemberBinding_WithIgnoreSupport_IsBeingRewritten.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableElementAndMemberBinding_WithIgnoreSupport_IsBeingRewritten.verified.txt similarity index 96% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableElementAndMemberBinding_WithIgnoreSupport_IsBeingRewritten.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableElementAndMemberBinding_WithIgnoreSupport_IsBeingRewritten.verified.txt index 0153a0f..c51a3f1 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableElementAndMemberBinding_WithIgnoreSupport_IsBeingRewritten.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableElementAndMemberBinding_WithIgnoreSupport_IsBeingRewritten.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableElementAndMemberBinding_WithRewriteSupport_IsBeingRewritten.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableElementAndMemberBinding_WithRewriteSupport_IsBeingRewritten.verified.txt similarity index 97% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableElementAndMemberBinding_WithRewriteSupport_IsBeingRewritten.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableElementAndMemberBinding_WithRewriteSupport_IsBeingRewritten.verified.txt index 010f995..1f2af4d 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableElementAndMemberBinding_WithRewriteSupport_IsBeingRewritten.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableElementAndMemberBinding_WithRewriteSupport_IsBeingRewritten.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableElementBinding_WithIgnoreSupport_IsBeingRewritten.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableElementBinding_WithIgnoreSupport_IsBeingRewritten.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableElementBinding_WithIgnoreSupport_IsBeingRewritten.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableElementBinding_WithIgnoreSupport_IsBeingRewritten.verified.txt index aff9e8b..ceb60d4 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableElementBinding_WithIgnoreSupport_IsBeingRewritten.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableElementBinding_WithIgnoreSupport_IsBeingRewritten.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableElementBinding_WithRewriteSupport_IsBeingRewritten.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableElementBinding_WithRewriteSupport_IsBeingRewritten.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableElementBinding_WithRewriteSupport_IsBeingRewritten.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableElementBinding_WithRewriteSupport_IsBeingRewritten.verified.txt index c881b5d..55ac25a 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableElementBinding_WithRewriteSupport_IsBeingRewritten.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableElementBinding_WithRewriteSupport_IsBeingRewritten.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableMemberBinding_WithIgnoreSupport_IsBeingRewritten.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableMemberBinding_WithIgnoreSupport_IsBeingRewritten.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableMemberBinding_WithIgnoreSupport_IsBeingRewritten.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableMemberBinding_WithIgnoreSupport_IsBeingRewritten.verified.txt index 97ef48d..4fa8aa7 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableMemberBinding_WithIgnoreSupport_IsBeingRewritten.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableMemberBinding_WithIgnoreSupport_IsBeingRewritten.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableMemberBinding_WithRewriteSupport_IsBeingRewritten.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableMemberBinding_WithRewriteSupport_IsBeingRewritten.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableMemberBinding_WithRewriteSupport_IsBeingRewritten.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableMemberBinding_WithRewriteSupport_IsBeingRewritten.verified.txt index 4b30f5d..a93f089 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableMemberBinding_WithRewriteSupport_IsBeingRewritten.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableMemberBinding_WithRewriteSupport_IsBeingRewritten.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableParameters_WithRewriteSupport_IsBeingRewritten.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableParameters_WithRewriteSupport_IsBeingRewritten.verified.txt similarity index 97% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableParameters_WithRewriteSupport_IsBeingRewritten.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableParameters_WithRewriteSupport_IsBeingRewritten.verified.txt index fc9af02..734be49 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableParameters_WithRewriteSupport_IsBeingRewritten.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableParameters_WithRewriteSupport_IsBeingRewritten.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableReferenceTypeCastOperatorGetsEliminated.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableReferenceTypeCastOperatorGetsEliminated.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableReferenceTypeCastOperatorGetsEliminated.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableReferenceTypeCastOperatorGetsEliminated.verified.txt index 48f6a5f..88fa434 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableReferenceTypeCastOperatorGetsEliminated.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableReferenceTypeCastOperatorGetsEliminated.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Collections.Generic; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableReferenceTypesAreBeingEliminated.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableReferenceTypesAreBeingEliminated.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableReferenceTypesAreBeingEliminated.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableReferenceTypesAreBeingEliminated.verified.txt index f880d94..24ac2e2 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableReferenceTypesAreBeingEliminated.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableReferenceTypesAreBeingEliminated.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableSimpleElementBinding_WithIgnoreSupport_IsBeingRewritten.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableSimpleElementBinding_WithIgnoreSupport_IsBeingRewritten.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableSimpleElementBinding_WithIgnoreSupport_IsBeingRewritten.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableSimpleElementBinding_WithIgnoreSupport_IsBeingRewritten.verified.txt index fe0230a..f44e605 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableSimpleElementBinding_WithIgnoreSupport_IsBeingRewritten.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableSimpleElementBinding_WithIgnoreSupport_IsBeingRewritten.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableSimpleElementBinding_WithRewriteSupport_IsBeingRewritten.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableSimpleElementBinding_WithRewriteSupport_IsBeingRewritten.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableSimpleElementBinding_WithRewriteSupport_IsBeingRewritten.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableSimpleElementBinding_WithRewriteSupport_IsBeingRewritten.verified.txt index d34d367..a9ec933 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableSimpleElementBinding_WithRewriteSupport_IsBeingRewritten.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableSimpleElementBinding_WithRewriteSupport_IsBeingRewritten.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableValueCastOperatorsPersist.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableValueCastOperatorsPersist.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableValueCastOperatorsPersist.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableValueCastOperatorsPersist.verified.txt index 8cfc5e5..b464304 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NullableValueCastOperatorsPersist.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.NullableValueCastOperatorsPersist.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Collections.Generic; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.cs b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.cs new file mode 100644 index 0000000..1f533f8 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/NullableTests.cs @@ -0,0 +1,492 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using VerifyXunit; +using Xunit; +using Xunit.Abstractions; + +namespace EntityFrameworkCore.Projectables.Generator.Tests; + +[UsesVerify] +public class NullableTests : ProjectionExpressionGeneratorTestsBase +{ + public NullableTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + [Fact] + public Task NullableReferenceTypesAreBeingEliminated() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using EntityFrameworkCore.Projectables; + +#nullable enable + +namespace Foo { + static class C { + [Projectable] + public static object? NextFoo(this object? unusedArgument, int? nullablePrimitiveArgument) => null; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task GenericNullableReferenceTypesAreBeingEliminated() + { + var compilation = CreateCompilation(@" +using System; +using System.Collections.Generic; +using System.Linq; +using EntityFrameworkCore.Projectables; + +#nullable enable + +namespace Foo { + static class C { + [Projectable] + public static List NextFoo(this List input, List nullablePrimitiveArgument) => input; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task NullableReferenceTypeCastOperatorGetsEliminated() + { + var compilation = CreateCompilation(@" +using System; +using System.Collections.Generic; +using System.Linq; +using EntityFrameworkCore.Projectables; + +#nullable enable + +namespace Foo { + static class C { + [Projectable] + public static string? NullableReferenceType(object? input) => (string?)input; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task NullableValueCastOperatorsPersist() + { + var compilation = CreateCompilation(@" +using System; +using System.Collections.Generic; +using System.Linq; +using EntityFrameworkCore.Projectables; + +#nullable enable + +namespace Foo { + static class C { + [Projectable] + public static int? NullableValueType(object? input) => (int?)input; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public void NullableMemberBinding_WithoutSupport_IsBeingReported() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using EntityFrameworkCore.Projectables; + +namespace Foo { + static class C { + [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.None)] + public static int? GetLength(this string input) => input?.Length; + } +} +"); + var result = RunGenerator(compilation); + + var diagnostic = Assert.Single(result.Diagnostics); + Assert.Equal("EFP0002", diagnostic.Id); + } + + [Fact] + public void NullableMemberBinding_UndefinedSupport_IsBeingReported() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using EntityFrameworkCore.Projectables; + +namespace Foo { + static class C { + [Projectable] + public static int? GetLength(this string input) => input?.Length; + } +} +"); + var result = RunGenerator(compilation); + + var diagnostic = Assert.Single(result.Diagnostics); + Assert.Equal("EFP0002", diagnostic.Id); + } + + [Fact] + public void MultiLevelNullableMemberBinding_UndefinedSupport_IsBeingReported() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public record Address + { + public int Id { get; set; } + public string? Country { get; set; } + } + + public record Party + { + public int Id { get; set; } + + public Address? Address { get; set; } + } + + public record Entity + { + public int Id { get; set; } + + public Party? Left { get; set; } + public Party? Right { get; set; } + + [Projectable] + public bool IsSameCountry => Left?.Address?.Country == Right?.Address?.Country; + } +} +"); + var result = RunGenerator(compilation); + + Assert.All(result.Diagnostics, diagnostic => { + Assert.Equal("EFP0002", diagnostic.Id); + }); + } + + [Fact] + public Task NullableMemberBinding_WithIgnoreSupport_IsBeingRewritten() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using EntityFrameworkCore.Projectables; + +namespace Foo { + static class C { + [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Ignore)] + public static int? GetLength(this string input) => input?.Length; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task NullableMemberBinding_WithRewriteSupport_IsBeingRewritten() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using EntityFrameworkCore.Projectables; + +namespace Foo { + static class C { + [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Rewrite)] + public static int? GetLength(this string input) => input?.Length; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task NullableSimpleElementBinding_WithIgnoreSupport_IsBeingRewritten() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using EntityFrameworkCore.Projectables; + +namespace Foo { + static class C { + [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Ignore)] + public static char? GetFirst(this string input) => input?[0]; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task NullableSimpleElementBinding_WithRewriteSupport_IsBeingRewritten() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using EntityFrameworkCore.Projectables; + +namespace Foo { + static class C { + [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Rewrite)] + public static char? GetFirst(this string input) => input?[0]; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task BooleanSimpleTernary_WithRewriteSupport_IsBeingRewritten() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using EntityFrameworkCore.Projectables; + +namespace Foo { + static class C { + [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Rewrite)] + public static bool Test(this object? x) => x?.Equals(4) == false; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task NullableElementBinding_WithIgnoreSupport_IsBeingRewritten() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using EntityFrameworkCore.Projectables; + +namespace Foo { + static class C { + [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Ignore)] + public static string? GetFirst(this string input) => input?[0].ToString(); + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task NullableElementBinding_WithRewriteSupport_IsBeingRewritten() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using EntityFrameworkCore.Projectables; + +namespace Foo { + static class C { + [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Rewrite)] + public static string? GetFirst(this string input) => input?[0].ToString(); + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task NullableElementAndMemberBinding_WithIgnoreSupport_IsBeingRewritten() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using System.Collections.Generic; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public static class EntityExtensions + { + public record Entity + { + public int Id { get; set; } + public List? RelatedEntities { get; set; } + } + + [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Ignore)] + public static Entity GetFirstRelatedIgnoreNulls(this Entity entity) + => entity?.RelatedEntities?[0]; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task NullableElementAndMemberBinding_WithRewriteSupport_IsBeingRewritten() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using System.Collections.Generic; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public static class EntityExtensions + { + public record Entity + { + public int Id { get; set; } + public List? RelatedEntities { get; set; } + } + + [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Rewrite)] + public static Entity GetFirstRelatedIgnoreNulls(this Entity entity) + => entity?.RelatedEntities?[0]; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task NullableParameters_WithRewriteSupport_IsBeingRewritten() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using System.Collections.Generic; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public static class EntityExtensions + { + public record Entity + { + public int Id { get; set; } + public string? FullName { get; set; } + } + + [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Rewrite)] + public static string GetFirstName(this Entity entity) + => entity.FullName?.Substring(entity.FullName?.IndexOf(' ') ?? 0); + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task NullConditionalNullCoalesceTypeConversion() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +class Foo { + public int? FancyNumber { get; set; } + + [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Rewrite)] + public static int SomeNumber(Foo fancyClass) => fancyClass?.FancyNumber ?? 3; +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberMethod.DotNet10_0.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberMethod.DotNet10_0.verified.txt deleted file mode 100644 index e0d8932..0000000 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberMethod.DotNet10_0.verified.txt +++ /dev/null @@ -1,17 +0,0 @@ -// -#nullable disable -using System; -using EntityFrameworkCore.Projectables; -using Foo; - -namespace EntityFrameworkCore.Projectables.Generated -{ - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - static class Foo_EntityExtensions_TripleId_P0_Foo_Entity - { - static global::System.Linq.Expressions.Expression> Expression() - { - return (global::Foo.Entity @this) => @this.Id * 3; - } - } -} diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberMethodWithParameters.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberMethodWithParameters.verified.txt deleted file mode 100644 index 837945b..0000000 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberMethodWithParameters.verified.txt +++ /dev/null @@ -1,17 +0,0 @@ -// -#nullable disable -using System; -using EntityFrameworkCore.Projectables; -using Foo; - -namespace EntityFrameworkCore.Projectables.Generated -{ - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - static class Foo_EntityExtensions_Multiply_P0_Foo_Entity_P1_int - { - static global::System.Linq.Expressions.Expression> Expression() - { - return (global::Foo.Entity @this, int factor) => @this.Id * factor; - } - } -} diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberOnInterface.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberOnInterface.verified.txt deleted file mode 100644 index a16c95c..0000000 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberOnInterface.verified.txt +++ /dev/null @@ -1,17 +0,0 @@ -// -#nullable disable -using System; -using EntityFrameworkCore.Projectables; -using Foo; - -namespace EntityFrameworkCore.Projectables.Generated -{ - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - static class Foo_IEntityExtensions_Label - { - static global::System.Linq.Expressions.Expression> Expression() - { - return (global::Foo.IEntity @this) => @this.Id + ": " + @this.Name; - } - } -} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberOnPrimitive.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberOnPrimitive.verified.txt deleted file mode 100644 index f6a60da..0000000 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberOnPrimitive.verified.txt +++ /dev/null @@ -1,16 +0,0 @@ -// -#nullable disable -using System; -using EntityFrameworkCore.Projectables; - -namespace EntityFrameworkCore.Projectables.Generated -{ - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - static class _IntExtensions_Squared - { - static global::System.Linq.Expressions.Expression> Expression() - { - return (int @this) => @this * @this; - } - } -} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberProperty.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberProperty.verified.txt deleted file mode 100644 index 0d29557..0000000 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberProperty.verified.txt +++ /dev/null @@ -1,17 +0,0 @@ -// -#nullable disable -using System; -using EntityFrameworkCore.Projectables; -using Foo; - -namespace EntityFrameworkCore.Projectables.Generated -{ - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - static class Foo_EntityExtensions_DoubleId - { - static global::System.Linq.Expressions.Expression> Expression() - { - return (global::Foo.Entity @this) => @this.Id * 2; - } - } -} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberWithBlockBody.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberWithBlockBody.verified.txt deleted file mode 100644 index 70c9c10..0000000 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberWithBlockBody.verified.txt +++ /dev/null @@ -1,17 +0,0 @@ -// -#nullable disable -using System; -using EntityFrameworkCore.Projectables; -using Foo; - -namespace EntityFrameworkCore.Projectables.Generated -{ - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - static class Foo_EntityExtensions_GetStatus_P0_Foo_Entity - { - static global::System.Linq.Expressions.Expression> Expression() - { - return (global::Foo.Entity @this) => @this.IsActive && @this.Value > 0 ? "Active" : "Inactive"; - } - } -} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberWithIsPatternExpression.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberWithIsPatternExpression.verified.txt deleted file mode 100644 index 758dab3..0000000 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberWithIsPatternExpression.verified.txt +++ /dev/null @@ -1,17 +0,0 @@ -// -#nullable disable -using System; -using EntityFrameworkCore.Projectables; -using Foo; - -namespace EntityFrameworkCore.Projectables.Generated -{ - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - static class Foo_EntityExtensions_IsHighValue - { - static global::System.Linq.Expressions.Expression> Expression() - { - return (global::Foo.Entity @this) => @this.Value > 100; - } - } -} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberWithMemberAccess.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberWithMemberAccess.verified.txt deleted file mode 100644 index 5707b4d..0000000 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberWithMemberAccess.verified.txt +++ /dev/null @@ -1,17 +0,0 @@ -// -#nullable disable -using System; -using EntityFrameworkCore.Projectables; -using Foo; - -namespace EntityFrameworkCore.Projectables.Generated -{ - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - static class Foo_EntityExtensions_IdAndName - { - static global::System.Linq.Expressions.Expression> Expression() - { - return (global::Foo.Entity @this) => @this.Id + ": " + @this.Name; - } - } -} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberWithSwitchExpression.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberWithSwitchExpression.verified.txt deleted file mode 100644 index 2bbeb71..0000000 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExtensionMemberWithSwitchExpression.verified.txt +++ /dev/null @@ -1,17 +0,0 @@ -// -#nullable disable -using System; -using EntityFrameworkCore.Projectables; -using Foo; - -namespace EntityFrameworkCore.Projectables.Generated -{ - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - static class Foo_EntityExtensions_GetGrade_P0_Foo_Entity - { - static global::System.Linq.Expressions.Expression> Expression() - { - return (global::Foo.Entity @this) => @this.Score >= 90 ? "A" : @this.Score >= 80 ? "B" : @this.Score >= 70 ? "C" : "F"; - } - } -} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_Overloads.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_Overloads.verified.txt deleted file mode 100644 index 5e9c8af..0000000 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_Overloads.verified.txt +++ /dev/null @@ -1,65 +0,0 @@ -[ -// -#nullable disable -using EntityFrameworkCore.Projectables; -using Foo; - -namespace EntityFrameworkCore.Projectables.Generated -{ - /// - /// Generated from: - /// - /// [Projectable] - /// public PersonDto(string firstName, string lastName) - /// { - /// FirstName = firstName; - /// LastName = lastName; - /// } - /// - /// - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - static class Foo_PersonDto__ctor_P0_string_P1_string - { - static global::System.Linq.Expressions.Expression> Expression() - { - return (string firstName, string lastName) => new global::Foo.PersonDto() - { - FirstName = firstName, - LastName = lastName - }; - } - } -} - -// -#nullable disable -using EntityFrameworkCore.Projectables; -using Foo; - -namespace EntityFrameworkCore.Projectables.Generated -{ - /// - /// Generated from: - /// - /// [Projectable] - /// public PersonDto(string fullName) - /// { - /// FirstName = fullName; - /// LastName = string.Empty; - /// } - /// - /// - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - static class Foo_PersonDto__ctor_P0_string - { - static global::System.Linq.Expressions.Expression> Expression() - { - return (string fullName) => new global::Foo.PersonDto() - { - FirstName = fullName, - LastName = string.Empty - }; - } - } -} -] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ReferencingBasePropertyInDerivedBody.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ReferencingBasePropertyInDerivedBody.verified.txt deleted file mode 100644 index 6fe422b..0000000 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ReferencingBasePropertyInDerivedBody.verified.txt +++ /dev/null @@ -1,36 +0,0 @@ -// -#nullable disable -using EntityFrameworkCore.Projectables; -using Foo; - -namespace EntityFrameworkCore.Projectables.Generated -{ - /// - /// Generated from: - /// - /// [Projectable] - /// public Child(string code) : base(code) - /// { - /// Label = "[" + Code + "]"; - /// } - /// - /// - /// public Base(string code) - /// { - /// Code = code; - /// } - /// - /// - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - static class Foo_Child__ctor_P0_string - { - static global::System.Linq.Expressions.Expression> Expression() - { - return (string code) => new global::Foo.Child() - { - Code = code, - Label = "[" + (code) + "]" - }; - } - } -} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ReferencingPreviouslyAssignedInBaseCtor.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ReferencingPreviouslyAssignedInBaseCtor.verified.txt deleted file mode 100644 index 61fa3b3..0000000 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ReferencingPreviouslyAssignedInBaseCtor.verified.txt +++ /dev/null @@ -1,38 +0,0 @@ -// -#nullable disable -using EntityFrameworkCore.Projectables; -using Foo; - -namespace EntityFrameworkCore.Projectables.Generated -{ - /// - /// Generated from: - /// - /// [Projectable] - /// public Child(int a, int b) : base(a, b) - /// { - /// Sum = X + Y; - /// } - /// - /// - /// public Base(int x, int y) - /// { - /// X = x; - /// Y = x + y; // Y depends on X's assigned value (x) - /// } - /// - /// - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - static class Foo_Child__ctor_P0_int_P1_int - { - static global::System.Linq.Expressions.Expression> Expression() - { - return (int a, int b) => new global::Foo.Child() - { - X = a, - Y = a + b, - Sum = (a) + (a + b) - }; - } - } -} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ReferencingPreviouslyAssignedProperty.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ReferencingPreviouslyAssignedProperty.verified.txt deleted file mode 100644 index c3af8ba..0000000 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ReferencingPreviouslyAssignedProperty.verified.txt +++ /dev/null @@ -1,33 +0,0 @@ -// -#nullable disable -using EntityFrameworkCore.Projectables; -using Foo; - -namespace EntityFrameworkCore.Projectables.Generated -{ - /// - /// Generated from: - /// - /// [Projectable] - /// public PersonDto(string firstName, string lastName) - /// { - /// FirstName = firstName; - /// LastName = lastName; - /// FullName = FirstName + " " + LastName; - /// } - /// - /// - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - static class Foo_PersonDto__ctor_P0_string_P1_string - { - static global::System.Linq.Expressions.Expression> Expression() - { - return (string firstName, string lastName) => new global::Foo.PersonDto() - { - FirstName = firstName, - LastName = lastName, - FullName = (firstName) + " " + (lastName) - }; - } - } -} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ReferencingStaticConstMember.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ReferencingStaticConstMember.verified.txt deleted file mode 100644 index bb1416a..0000000 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ReferencingStaticConstMember.verified.txt +++ /dev/null @@ -1,29 +0,0 @@ -// -#nullable disable -using EntityFrameworkCore.Projectables; -using Foo; - -namespace EntityFrameworkCore.Projectables.Generated -{ - /// - /// Generated from: - /// - /// [Projectable] - /// public PersonDto(string first, string last) - /// { - /// FullName = first + Separator + last; - /// } - /// - /// - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - static class Foo_PersonDto__ctor_P0_string_P1_string - { - static global::System.Linq.Expressions.Expression> Expression() - { - return (string first, string last) => new global::Foo.PersonDto() - { - FullName = first + global::Foo.PersonDto.Separator + last - }; - } - } -} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_ChainedThisAndBase.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_ChainedThisAndBase.verified.txt deleted file mode 100644 index 28552c7..0000000 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_ChainedThisAndBase.verified.txt +++ /dev/null @@ -1,42 +0,0 @@ -// -#nullable disable -using EntityFrameworkCore.Projectables; -using Foo; - -namespace EntityFrameworkCore.Projectables.Generated -{ - /// - /// Generated from: - /// - /// [Projectable] - /// public Child(int id, string name, string suffix) : this(id, name) - /// { - /// Name = Name + suffix; - /// } - /// - /// - /// public Child(int id, string name) : base(id) - /// { - /// Name = name; - /// } - /// - /// - /// public Base(int id) - /// { - /// Id = id; - /// } - /// - /// - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - static class Foo_Child__ctor_P0_int_P1_string_P2_string - { - static global::System.Linq.Expressions.Expression> Expression() - { - return (int id, string name, string suffix) => new global::Foo.Child() - { - Id = id, - Name = (name) + suffix - }; - } - } -} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_RefPreviouslyAssignedProperty.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_RefPreviouslyAssignedProperty.verified.txt deleted file mode 100644 index b2fc637..0000000 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_RefPreviouslyAssignedProperty.verified.txt +++ /dev/null @@ -1,38 +0,0 @@ -// -#nullable disable -using EntityFrameworkCore.Projectables; -using Foo; - -namespace EntityFrameworkCore.Projectables.Generated -{ - /// - /// Generated from: - /// - /// [Projectable] - /// public PersonDto(string firstName) : this(firstName, "Doe") - /// { - /// } - /// - /// - /// public PersonDto(string firstName, string lastName) - /// { - /// FirstName = firstName; - /// LastName = lastName; - /// FullName = FirstName + " " + LastName; - /// } - /// - /// - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - static class Foo_PersonDto__ctor_P0_string - { - static global::System.Linq.Expressions.Expression> Expression() - { - return (string firstName) => new global::Foo.PersonDto() - { - FirstName = firstName, - LastName = "Doe", - FullName = (firstName) + " " + ("Doe") - }; - } - } -} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_SimpleOverload.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_SimpleOverload.verified.txt deleted file mode 100644 index 3a246ec..0000000 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_SimpleOverload.verified.txt +++ /dev/null @@ -1,36 +0,0 @@ -// -#nullable disable -using EntityFrameworkCore.Projectables; -using Foo; - -namespace EntityFrameworkCore.Projectables.Generated -{ - /// - /// Generated from: - /// - /// [Projectable] - /// public PersonDto(string fullName) : this(fullName.Split(' ')[0], fullName.Split(' ')[1]) - /// { - /// } - /// - /// - /// public PersonDto(string firstName, string lastName) - /// { - /// FirstName = firstName; - /// LastName = lastName; - /// } - /// - /// - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - static class Foo_PersonDto__ctor_P0_string - { - static global::System.Linq.Expressions.Expression> Expression() - { - return (string fullName) => new global::Foo.PersonDto() - { - FirstName = fullName.Split(' ')[0], - LastName = fullName.Split(' ')[1] - }; - } - } -} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_WithBodyAfter.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_WithBodyAfter.verified.txt deleted file mode 100644 index ec11879..0000000 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_WithBodyAfter.verified.txt +++ /dev/null @@ -1,38 +0,0 @@ -// -#nullable disable -using EntityFrameworkCore.Projectables; -using Foo; - -namespace EntityFrameworkCore.Projectables.Generated -{ - /// - /// Generated from: - /// - /// [Projectable] - /// public PersonDto(string fn, string ln, bool upper) : this(fn, ln) - /// { - /// FullName = upper ? (FirstName + " " + LastName).ToUpper() : FirstName + " " + LastName; - /// } - /// - /// - /// public PersonDto(string firstName, string lastName) - /// { - /// FirstName = firstName; - /// LastName = lastName; - /// } - /// - /// - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - static class Foo_PersonDto__ctor_P0_string_P1_string_P2_bool - { - static global::System.Linq.Expressions.Expression> Expression() - { - return (string fn, string ln, bool upper) => new global::Foo.PersonDto() - { - FirstName = fn, - LastName = ln, - FullName = upper ? ((fn) + " " + (ln)).ToUpper() : (fn) + " " + (ln) - }; - } - } -} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_WithIfElseInDelegated.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_WithIfElseInDelegated.verified.txt deleted file mode 100644 index 8051ed6..0000000 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableConstructor_ThisInitializer_WithIfElseInDelegated.verified.txt +++ /dev/null @@ -1,44 +0,0 @@ -// -#nullable disable -using EntityFrameworkCore.Projectables; -using Foo; - -namespace EntityFrameworkCore.Projectables.Generated -{ - /// - /// Generated from: - /// - /// [Projectable] - /// public PersonDto(int score, string prefix) : this(score) - /// { - /// Label = prefix + Label; - /// } - /// - /// - /// public PersonDto(int score) - /// { - /// Score = score; - /// if (score >= 90) - /// { - /// Label = "A"; - /// } - /// else - /// { - /// Label = "B"; - /// } - /// } - /// - /// - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - static class Foo_PersonDto__ctor_P0_int_P1_string - { - static global::System.Linq.Expressions.Expression> Expression() - { - return (int score, string prefix) => new global::Foo.PersonDto() - { - Score = score, - Label = prefix + (score >= 90 ? "A" : "B") - }; - } - } -} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.cs b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.cs deleted file mode 100644 index e6a2af4..0000000 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.cs +++ /dev/null @@ -1,5418 +0,0 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using VerifyXunit; -using Xunit; -using Xunit.Abstractions; - -namespace EntityFrameworkCore.Projectables.Generator.Tests -{ - [UsesVerify] - public class ProjectionExpressionGeneratorTests - { - readonly ITestOutputHelper _testOutputHelper; - - public ProjectionExpressionGeneratorTests(ITestOutputHelper testOutputHelper) - { - _testOutputHelper = testOutputHelper; - } - - [Fact] - public void EmtpyCode_Noop() - { - var compilation = CreateCompilation(@" -class C { } -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Empty(result.GeneratedTrees); - } - - [Fact] - public Task SimpleProjectableMethod() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - [Projectable] - public int Foo() => 1; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task SimpleProjectableProperty() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - [Projectable] - public int Foo => 1; - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task MinimalProjectableComputedProperty() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - - [Projectable] - public int Foo => Bar; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task SimpleProjectableComputedProperty() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - - [Projectable] - public int Foo => Bar + 1; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task SimpleProjectableComputedInNestedClassProperty() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - public class C { - public class D { - public int Bar { get; set; } - - [Projectable] - public int Foo => Bar + 1; - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableComputedPropertyUsingThis() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - - [Projectable] - public int Foo => this.Bar; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableComputedPropertyMethod() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar() => 1; - - [Projectable] - public int Foo => Bar(); - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectablePropertyWithExplicitExpressionGetter() - { - // Tests explicit getter with expression body: { get => expression; } - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - [Projectable] - public int Foo { get => 1; } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectablePropertyWithExplicitBlockGetter() - { - // Tests explicit getter with block body: { get { return expression; } } - // Requires AllowBlockBody = true - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - [Projectable(AllowBlockBody = true)] - public int Foo { get { return 1; } } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableComputedPropertyWithExplicitExpressionGetter() - { - // Tests explicit getter with expression body accessing other properties - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - - [Projectable] - public int Foo { get => Bar + 1; } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableComputedPropertyWithExplicitBlockGetter() - { - // Tests explicit getter with block body accessing other properties - // Requires AllowBlockBody = true - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - - [Projectable(AllowBlockBody = true)] - public int Foo { get { return Bar + 1; } } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectablePropertyWithExplicitBlockGetterUsingThis() - { - // Tests explicit getter with block body using 'this' qualifier - // Requires AllowBlockBody = true - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - - [Projectable(AllowBlockBody = true)] - public int Foo { get { return this.Bar; } } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectablePropertyWithExplicitBlockGetterAndMethodCall() - { - // Tests explicit getter with block body calling other methods - // Requires AllowBlockBody = true - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar() => 1; - - [Projectable(AllowBlockBody = true)] - public int Foo { get { return Bar(); } } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public void ProjectablePropertyWithExplicitBlockGetter_WithoutAllowBlockBody_EmitsWarning() - { - // Tests that block-bodied property getter without AllowBlockBody = true emits a warning - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - [Projectable] - public int Foo { get { return 1; } } - } -} -"); - - var result = RunGenerator(compilation); - - // Should have a warning about experimental feature - var diagnostic = Assert.Single(result.Diagnostics); - Assert.Equal("EFP0001", diagnostic.Id); - Assert.Equal(DiagnosticSeverity.Warning, diagnostic.Severity); - } - - - [Fact] - public Task MoreComplexProjectableComputedProperty() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - - [Projectable] - public int Foo => Bar + this.Bar + Bar; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ArgumentlessProjectableComputedMethod() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - [Projectable] - public int Foo() => 0; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableComputedMethodWithSingleArgument() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - [Projectable] - public int Foo(int i) => i; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableComputedMethodWithMultipleArguments() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - [Projectable] - public int Foo(int a, string b, object d) => a; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectablePropertyToNavigationalProperty() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using EntityFrameworkCore.Projectables; -namespace Foo { - class D { } - - class C { - public System.Collections.Generic.List Dees { get; set; } - - [Projectable] - public D Foo => Dees.First(); - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task TypesInBodyGetsFullyQualified() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using EntityFrameworkCore.Projectables; -namespace Foo { - class D { } - - class C { - public System.Collections.Generic.List Dees { get; set; } - - [Projectable] - public int Foo => Dees.OfType().Count(); - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task IsOperator() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using EntityFrameworkCore.Projectables; -namespace Foo { - class A { - [Projectable] - public bool IsB => this is B; - } - - class B : A { - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableExtensionMethod() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using EntityFrameworkCore.Projectables; -namespace Foo { - class D { } - - static class C { - [Projectable] - public static int Foo(this D d) => 1; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableExtensionMethod2() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using EntityFrameworkCore.Projectables; -namespace Foo { - static class C { - [Projectable] - public static int Foo(this int i) => i; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - - [Fact] - public Task ProjectableExtensionMethod3() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using EntityFrameworkCore.Projectables; -namespace Foo { - static class C { - [Projectable] - public static int Foo1(this int i) => i; - - [Projectable] - public static int Foo2(this int i) => i.Foo1(); - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Equal(2, result.GeneratedTrees.Length); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableExtensionMethod4() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using EntityFrameworkCore.Projectables; -namespace Foo { - static class C { - [Projectable] - public static object Foo1(this object i) => i.Foo1(); - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public void BlockBodiedMethod_NoLongerRaisesDiagnostics() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - [Projectable(AllowBlockBody = true)] - public int Foo() - { - return 1; - } - } -} -"); - - var result = RunGenerator(compilation); - - // Block-bodied methods are now supported, so no diagnostics should be raised - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - } - - [Fact] - public Task NullableReferenceTypesAreBeingEliminated() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using EntityFrameworkCore.Projectables; - -#nullable enable - -namespace Foo { - static class C { - [Projectable] - public static object? NextFoo(this object? unusedArgument, int? nullablePrimitiveArgument) => null; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - - [Fact] - public Task GenericNullableReferenceTypesAreBeingEliminated() - { - var compilation = CreateCompilation(@" -using System; -using System.Collections.Generic; -using System.Linq; -using EntityFrameworkCore.Projectables; - -#nullable enable - -namespace Foo { - static class C { - [Projectable] - public static List NextFoo(this List input, List nullablePrimitiveArgument) => input; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task NullableReferenceTypeCastOperatorGetsEliminated() - { - var compilation = CreateCompilation(@" -using System; -using System.Collections.Generic; -using System.Linq; -using EntityFrameworkCore.Projectables; - -#nullable enable - -namespace Foo { - static class C { - [Projectable] - public static string? NullableReferenceType(object? input) => (string?)input; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task NullableValueCastOperatorsPersist() - { - var compilation = CreateCompilation(@" -using System; -using System.Collections.Generic; -using System.Linq; -using EntityFrameworkCore.Projectables; - -#nullable enable - -namespace Foo { - static class C { - [Projectable] - public static int? NullableValueType(object? input) => (int?)input; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - - [Fact] - public void NullableMemberBinding_WithoutSupport_IsBeingReported() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using EntityFrameworkCore.Projectables; - -namespace Foo { - static class C { - [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.None)] - public static int? GetLength(this string input) => input?.Length; - } -} -"); - var result = RunGenerator(compilation); - - var diagnostic = Assert.Single(result.Diagnostics); - Assert.Equal("EFP0002", diagnostic.Id); - } - - [Fact] - public void NullableMemberBinding_UndefinedSupport_IsBeingReported() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using EntityFrameworkCore.Projectables; - -namespace Foo { - static class C { - [Projectable] - public static int? GetLength(this string input) => input?.Length; - } -} -"); - var result = RunGenerator(compilation); - - var diagnostic = Assert.Single(result.Diagnostics); - Assert.Equal("EFP0002", diagnostic.Id); - } - - - [Fact] - public void MultiLevelNullableMemberBinding_UndefinedSupport_IsBeingReported() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public record Address - { - public int Id { get; set; } - public string? Country { get; set; } - } - - public record Party - { - public int Id { get; set; } - - public Address? Address { get; set; } - } - - public record Entity - { - public int Id { get; set; } - - public Party? Left { get; set; } - public Party? Right { get; set; } - - [Projectable] - public bool IsSameCountry => Left?.Address?.Country == Right?.Address?.Country; - } -} -"); - var result = RunGenerator(compilation); - - Assert.All(result.Diagnostics, diagnostic => { - Assert.Equal("EFP0002", diagnostic.Id); - }); - } - - [Fact] - public Task NullableMemberBinding_WithIgnoreSupport_IsBeingRewritten() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using EntityFrameworkCore.Projectables; - -namespace Foo { - static class C { - [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Ignore)] - public static int? GetLength(this string input) => input?.Length; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task NullableMemberBinding_WithRewriteSupport_IsBeingRewritten() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using EntityFrameworkCore.Projectables; - -namespace Foo { - static class C { - [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Rewrite)] - public static int? GetLength(this string input) => input?.Length; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task NullableSimpleElementBinding_WithIgnoreSupport_IsBeingRewritten() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using EntityFrameworkCore.Projectables; - -namespace Foo { - static class C { - [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Ignore)] - public static char? GetFirst(this string input) => input?[0]; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task StringInterpolationWithStaticCall_IsBeingRewritten() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using EntityFrameworkCore.Projectables; - -namespace Foo { - static class MyExtensions { - public static string ToDateString(this DateTime date) => date.ToString(""dd/MM/yyyy""); - } - - class C { - public DateTime? ValidationDate { get; set; } - - [Projectable] - public string Status => ValidationDate != null ? $""Validation date : ({ValidationDate.Value.ToDateString()})"" : """"; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task StringInterpolationWithParenthesis_NoParenthesisAdded() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using EntityFrameworkCore.Projectables; - -namespace Foo { - static class MyExtensions { - public static string ToDateString(this DateTime date) => date.ToString(""dd/MM/yyyy""); - } - - class C { - public DateTime? ValidationDate { get; set; } - - [Projectable] - public string Status => ValidationDate != null ? $""Validation date : ({(ValidationDate.Value.ToDateString())})"" : """"; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task NullableSimpleElementBinding_WithRewriteSupport_IsBeingRewritten() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using EntityFrameworkCore.Projectables; - -namespace Foo { - static class C { - [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Rewrite)] - public static char? GetFirst(this string input) => input?[0]; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BooleanSimpleTernary_WithRewriteSupport_IsBeingRewritten() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using EntityFrameworkCore.Projectables; - -namespace Foo { - static class C { - [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Rewrite)] - public static bool Test(this object? x) => x?.Equals(4) == false; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - - - [Fact] - public Task NullableElementBinding_WithIgnoreSupport_IsBeingRewritten() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using EntityFrameworkCore.Projectables; - -namespace Foo { - static class C { - [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Ignore)] - public static string? GetFirst(this string input) => input?[0].ToString(); - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task NullableElementBinding_WithRewriteSupport_IsBeingRewritten() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using EntityFrameworkCore.Projectables; - -namespace Foo { - static class C { - [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Rewrite)] - public static string? GetFirst(this string input) => input?[0].ToString(); - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task NullableElementAndMemberBinding_WithIgnoreSupport_IsBeingRewritten() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using System.Collections.Generic; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public static class EntityExtensions - { - public record Entity - { - public int Id { get; set; } - public List? RelatedEntities { get; set; } - } - - [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Ignore)] - public static Entity GetFirstRelatedIgnoreNulls(this Entity entity) - => entity?.RelatedEntities?[0]; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task NullableElementAndMemberBinding_WithRewriteSupport_IsBeingRewritten() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using System.Collections.Generic; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public static class EntityExtensions - { - public record Entity - { - public int Id { get; set; } - public List? RelatedEntities { get; set; } - } - - [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Rewrite)] - public static Entity GetFirstRelatedIgnoreNulls(this Entity entity) - => entity?.RelatedEntities?[0]; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task NullableParameters_WithRewriteSupport_IsBeingRewritten() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using System.Collections.Generic; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public static class EntityExtensions - { - public record Entity - { - public int Id { get; set; } - public string? FullName { get; set; } - } - - [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Rewrite)] - public static string GetFirstName(this Entity entity) - => entity.FullName?.Substring(entity.FullName?.IndexOf(' ') ?? 0); - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task GenericMethods_AreRewritten() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using System.Collections.Generic; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public static class EntityExtensions - { - public record Entity - { - public int Id { get; set; } - public string? FullName { get; set; } - } - - [Projectable] - public static string EnforceString(T value) where T : unmanaged - => value.ToString(); - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task GenericClassesWithContraints_AreRewritten() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using System.Collections.Generic; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public class TypedObject where TEnum : struct, System.Enum - { - public TEnum SomeProp { get; set; } - } - - public abstract class Entitywhere T : TypedObject where TEnum : struct, System.Enum - { - public int Id { get; set; } - public string FirstName { get; set; } - public string LastName { get; set; } - public T SomeSubobject { get; set; } - - [Projectable] - public string FullName => $""{FirstName} {LastName} {SomeSubobject.SomeProp}""; - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task GenericClassesWithTypeContraints_AreRewritten() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using System.Collections.Generic; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public abstract class Entity where T : notnull - { - public int Id { get; set; } - public string FirstName { get; set; } - public string LastName { get; set; } - public T SomeSubobject { get; set; } - - [Projectable] - public string FullName => $""{FirstName} {LastName} {SomeSubobject}""; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - // Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task DeclarationTypeNamesAreGettingFullyQualified() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using System.Collections.Generic; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public static class EntityExtensions - { - public record Entity - { - public int Id { get; set; } - public string? FullName { get; set; } - - [Projectable] - public static Entity Something(Entity entity) - => entity; - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task MixPrimaryConstructorAndProperties() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using System.Collections.Generic; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public static class EntityExtensions - { - public record Entity(int Id) - { - public int Id { get; set; } - public string? FullName { get; set; } - - [Projectable] - public static Entity Something(Entity entity) - => new Entity(entity.Id) { - FullName = entity.FullName - }; - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task InheritedMembers() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using System.Collections.Generic; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public class Foo { - public int Id { get; set; } - } - - public class Bar : Foo { - [Projectable] - public int ProjectedId => Id; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task StaticMembers() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using System.Collections.Generic; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public class Foo { - public static int Bar { get; set; } - - public int Id { get; set; } - - [Projectable] - public int IdWithBar() => Id + Bar; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task StaticMembers2() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using System.Collections.Generic; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public static class Constants { - public static readonly int Bar = 1; - } - - public class Foo { - public int Id { get; set; } - - [Projectable] - public int IdWithBar() => Id + Constants.Bar; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - - [Fact] - public Task StaticMethodWithNoParameters() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using System.Collections.Generic; -using EntityFrameworkCore.Projectables; - -public static class Foo { - [Projectable] - public static int Zero() => 0; -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task StaticMethodWithParameters() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using System.Collections.Generic; -using EntityFrameworkCore.Projectables; - -public static class Foo { - [Projectable] - public static int Zero(int x) => 0; -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ConstMember() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using System.Collections.Generic; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public class Foo { - public const int Bar = 1; - - public int Id { get; set; } - - [Projectable] - public int IdWithBar() => Id + Bar; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ConstMember2() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using System.Collections.Generic; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public static class Constants { - public const int Bar = 1; - } - - public class Foo { - public int Id { get; set; } - - [Projectable] - public int IdWithBar() => Id + Constants.Bar; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ConstMember3() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using System.Collections.Generic; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public class Foo { - public const int Bar = 1; - - public int Id { get; set; } - - [Projectable] - public int IdWithBar() => Id + Foo.Bar; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task RelationalProperty() - { - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using System.Collections.Generic; -using EntityFrameworkCore.Projectables; - -namespace Foos { - public class Foo { - public int Id { get; set; } - } - - public class Bar { - public Foo Foo { get; set; } - - [Projectable] - public int FooId => Foo.Id; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task EnumAccessor() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -public enum SomeFlag -{ - Foo -} - -public static class SomeExtensions -{ - [Projectable] - public static bool Test(this SomeFlag f) => f == SomeFlag.Foo; -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task Cast() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Projectables.Repro; - -public class SuperEntity : SomeEntity -{ - public string Superpower { get; set; } -} - -public class SomeEntity -{ - public int Id { get; set; } -} - -public static class SomeExtensions -{ - [Projectable] - public static string AsSomeResult(this SomeEntity e) => ((SuperEntity)e).Superpower; -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task NavigationProperties() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; -using System.Collections.Generic; - -namespace Projectables.Repro; - -public class SomeEntity -{ - public int Id { get; set; } - - public SomeEntity Parent { get; set; } - - public ICollection Children { get; set; } - - [Projectable] - public ICollection RootChildren => - Parent != null ? Parent.RootChildren : Children; -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task FooOrBar() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; -using System.Collections.Generic; - -namespace Projectables.Repro; - -public class SomeEntity -{ - public int Id { get; set; } - - public string Foo { get; set; } - - public string Bar { get; set; } - - [Projectable] - public string FooOrBar => - Foo != null ? Foo : Bar; -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BaseMemberExplicitReference() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Projectables.Repro; - -class Base -{ - public string Foo { get; set; } -} - -class Derived : Base -{ - [Projectable] - public string Bar => base.Foo; -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BaseMemberImplicitReference() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Projectables.Repro; - -class Base -{ - public string Foo { get; set; } -} - -class Derived : Base -{ - [Projectable] - public string Bar => Foo; -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BaseMethodExplicitReference() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Projectables.Repro; - -class Base -{ - public string Foo() => """"; -} - -class Derived : Base -{ - [Projectable] - public string Bar => base.Foo(); -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BaseMethorImplicitReference() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Projectables.Repro; - -class Base -{ - public string Foo() => """"; -} - -class Derived : Base -{ - [Projectable] - public string Bar => Foo(); -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task DefaultValuesGetRemoved() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -class Foo { - [Projectable] - public int Calculate(int i = 0) => i; -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ParamsModifiedGetsRemoved() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -class Foo { - [Projectable] - public int First(params int[] all) => all[0]; -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task RequiredNamespace() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace One { - static class IntExtensions { - public static int AddOne(this int i) => i + 1; - } -} - -namespace One.Two { - class Bar { - [Projectable] - public int Method() => 1.AddOne(); - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task NullConditionalNullCoalesceTypeConversion() - { - // issue: https://github.com/koenbeuk/EntityFrameworkCore.Projectables/issues/48 - - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -class Foo { - public int? FancyNumber { get; set; } - - [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Rewrite)] - public static int SomeNumber(Foo fancyClass) => fancyClass?.FancyNumber ?? 3; -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task SwitchExpressionWithConstantPattern() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -class Foo { - public int? FancyNumber { get; set; } - - [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Rewrite)] - public int SomeNumber(int input) => input switch { - 1 => 2, - 3 => 4, - 4 when FancyNumber == 12 => 48, - _ => 1000, - }; - } -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task SwitchExpressionWithTypePattern() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -public abstract class Item -{ - public int Id { get; set; } - public string Name { get; set; } -} - -public class GroupItem : Item -{ - public string Description { get; set; } -} - -public class DocumentItem : Item -{ - public int Priority { get; set; } -} - -public abstract record ItemData(int Id, string Name); -public record GroupData(int Id, string Name, string Description) : ItemData(Id, Name); -public record DocumentData(int Id, string Name, int Priority) : ItemData(Id, Name); - -public static class ItemMapper -{ - [Projectable] - public static ItemData ToData(this Item item) => - item switch - { - GroupItem groupItem => new GroupData(groupItem.Id, groupItem.Name, groupItem.Description), - DocumentItem documentItem => new DocumentData(documentItem.Id, documentItem.Name, documentItem.Priority), - _ => null! - }; -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task SwitchExpression_WithRelationalPattern() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class Entity { - public int Score { get; set; } - - [Projectable] - public string GetGrade() => Score switch - { - >= 90 => ""A"", - >= 80 => ""B"", - >= 70 => ""C"", - _ => ""F"", - }; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task SwitchExpression_WithRelationalPattern_OnExtensionMethod() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class Order { - public decimal Amount { get; set; } - } - - static class OrderExtensions { - [Projectable] - public static string GetTier(this Order order) => order.Amount switch - { - >= 1000 => ""Platinum"", - >= 500 => ""Gold"", - >= 100 => ""Silver"", - _ => ""Bronze"", - }; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ExpressionBodied_IsPattern_WithAndPattern() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class Entity { - public int Value { get; set; } - - [Projectable] - public bool IsInRange => Value is >= 1 and <= 100; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ExpressionBodied_IsPattern_WithOrPattern() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class Entity { - public int Value { get; set; } - - [Projectable] - public bool IsOutOfRange => Value is 0 or > 100; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ExpressionBodied_IsPattern_WithPropertyPattern() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class Entity { - public bool IsActive { get; set; } - public int Value { get; set; } - } - - static class Extensions { - [Projectable] - public static bool IsActiveAndPositive(this Entity entity) => - entity is { IsActive: true, Value: > 0 }; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ExpressionBodied_IsPattern_WithNotNullPattern() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class Entity { - public string? Name { get; set; } - - [Projectable] - public bool HasName => Name is not null; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BlockBodiedMethod_WithAndPattern() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; - -namespace Foo { - class Entity { - public int Value { get; set; } - } - - static class Extensions { - [Projectable(AllowBlockBody = true)] - public static bool IsInRange(this Entity entity) - { - if (entity.Value is >= 1 and <= 100) - { - return true; - } - return false; - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BlockBodiedMethod_WithOrPattern() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; - -namespace Foo { - class Entity { - public string Status { get; set; } - } - - static class Extensions { - [Projectable(AllowBlockBody = true)] - public static bool IsTerminal(this Entity entity) - { - if (entity.Status is ""Cancelled"" or ""Completed"") - { - return true; - } - return false; - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task GenericTypes() - { - // issue: https://github.com/koenbeuk/EntityFrameworkCore.Projectables/issues/48 - - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -class EntiyBase { - [Projectable] - public static TId GetId() => default; -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task GenericTypesWithConstraints() - { - // issue: https://github.com/koenbeuk/EntityFrameworkCore.Projectables/issues/48 - - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; - -class EntityBase where TId : ICloneable, new() { - [Projectable] - public static TId GetId() => default; -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task DictionaryIndexInitializer_IsBeingRewritten() - { - // lang=csharp - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using System.Collections.Generic; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public static class EntityExtensions - { - public record Entity - { - public int Id { get; set; } - public string? FullName { get; set; } - } - - [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Rewrite)] - public static Dictionary ToDictionary(this Entity entity) - => new Dictionary - { - [""FullName""] = entity.FullName ?? ""N/A"", - [""Id""] = entity.Id.ToString(), - }; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task DictionaryObjectInitializer_PreservesCollectionInitializerSyntax() - { - // lang=csharp - var compilation = CreateCompilation(@" -using System; -using System.Linq; -using System.Collections.Generic; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public static class EntityExtensions - { - public record Entity - { - public int Id { get; set; } - public string? FullName { get; set; } - } - - [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Rewrite)] - public static Dictionary ToDictionary(this Entity entity) - => new Dictionary - { - { ""FullName"", entity.FullName ?? ""N/A"" } - }; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BlockBodiedMethod_SimpleReturn() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - [Projectable(AllowBlockBody = true)] - public int Foo() - { - return 42; - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BlockBodiedMethod_WithPropertyAccess() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - - [Projectable(AllowBlockBody = true)] - public int Foo() - { - return Bar + 10; - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BlockBodiedMethod_WithIfElse() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - - [Projectable(AllowBlockBody = true)] - public int Foo() - { - if (Bar > 10) - { - return 1; - } - else - { - return 0; - } - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BlockBodiedMethod_WithNestedIfElse() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - - [Projectable(AllowBlockBody = true)] - public string Foo() - { - if (Bar > 10) - { - return ""High""; - } - else if (Bar > 5) - { - return ""Medium""; - } - else - { - return ""Low""; - } - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BlockBodiedMethod_WithLocalVariable() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - - [Projectable(AllowBlockBody = true)] - public int Foo() - { - var temp = Bar * 2; - return temp + 5; - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BlockBodiedMethod_WithTransitiveLocalVariables() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - - [Projectable(AllowBlockBody = true)] - public int Foo() - { - var a = Bar * 2; - var b = a + 5; - return b + 10; - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BlockBodiedMethod_LocalInIfCondition() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - - [Projectable(AllowBlockBody = true)] - public int Foo() - { - var threshold = Bar * 2; - if (threshold > 10) - { - return 1; - } - else - { - return 0; - } - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BlockBodiedMethod_LocalInSwitchExpression() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - - [Projectable(AllowBlockBody = true)] - public string Foo() - { - var value = Bar * 2; - switch (value) - { - case 2: - return ""Two""; - case 4: - return ""Four""; - default: - return ""Other""; - } - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BlockBodiedMethod_LocalsInNestedBlock_ProducesDiagnostic() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - - [Projectable(AllowBlockBody = true)] - public int Foo() - { - if (Bar > 10) - { - var temp = Bar * 2; - return temp; - } - return 0; - } - } -} -"); - - var result = RunGenerator(compilation); - - // Should have a diagnostic about locals in nested blocks - Assert.NotEmpty(result.Diagnostics); - Assert.Contains(result.Diagnostics, d => d.Id == "EFP0003"); - - return Verifier.Verify(result.Diagnostics.Select(d => d.ToString())); - } - - [Fact] - public Task BlockBodiedMethod_WithMultipleParameters() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - [Projectable(AllowBlockBody = true)] - public int Add(int a, int b) - { - return a + b; - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BlockBodiedMethod_WithIfElseAndCondition() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - public bool IsActive { get; set; } - - [Projectable(AllowBlockBody = true)] - public int Foo() - { - if (IsActive && Bar > 0) - { - return Bar * 2; - } - else - { - return 0; - } - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - - [Fact] - public Task BlockBodiedMethod_IfWithoutElse_UsesDefault() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - - [Projectable(AllowBlockBody = true)] - public int Foo() - { - if (Bar > 10) - { - return 1; - } - return 0; - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BlockBodiedMethod_IfWithoutElse_ImplicitReturn() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - - [Projectable(AllowBlockBody = true)] - public int? Foo() - { - if (Bar > 10) - { - return 1; - } - - return null; - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BlockBodiedMethod_SwitchStatement_Simple() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - - [Projectable(AllowBlockBody = true)] - public string Foo() - { - switch (Bar) - { - case 1: - return ""One""; - case 2: - return ""Two""; - default: - return ""Other""; - } - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BlockBodiedMethod_SwitchStatement_WithMultipleCases() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - - [Projectable(AllowBlockBody = true)] - public string Foo() - { - switch (Bar) - { - case 1: - case 2: - return ""Low""; - case 3: - case 4: - case 5: - return ""Medium""; - default: - return ""High""; - } - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BlockBodiedMethod_SwitchStatement_WithoutDefault() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - - [Projectable(AllowBlockBody = true)] - public string? Foo() - { - switch (Bar) - { - case 1: - return ""One""; - case 2: - return ""Two""; - } - - return null; - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BlockBodiedMethod_PropertyAssignment_ReportsError() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - - [Projectable(AllowBlockBody = true)] - public int Foo() - { - Bar = 10; - return Bar; - } - } -} -"); - - var result = RunGenerator(compilation); - - // Should have a diagnostic about side effects - Assert.NotEmpty(result.Diagnostics); - Assert.Contains(result.Diagnostics, d => d.Id == "EFP0004"); - - return Verifier.Verify(result.Diagnostics.Select(d => d.ToString())); - } - - [Fact] - public Task BlockBodiedMethod_CompoundAssignment_ReportsError() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - - [Projectable(AllowBlockBody = true)] - public int Foo() - { - Bar += 10; - return Bar; - } - } -} -"); - - var result = RunGenerator(compilation); - - // Should have a diagnostic about side effects - Assert.NotEmpty(result.Diagnostics); - Assert.Contains(result.Diagnostics, d => d.Id == "EFP0004"); - - return Verifier.Verify(result.Diagnostics.Select(d => d.ToString())); - } - - [Fact] - public Task BlockBodiedMethod_IncrementOperator_ReportsError() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - - [Projectable(AllowBlockBody = true)] - public int Foo() - { - var x = 5; - x++; - return x; - } - } -} -"); - - var result = RunGenerator(compilation); - - // Should have a diagnostic about side effects - Assert.NotEmpty(result.Diagnostics); - Assert.Contains(result.Diagnostics, d => d.Id == "EFP0004"); - - return Verifier.Verify(result.Diagnostics.Select(d => d.ToString())); - } - - [Fact] - public Task BlockBodiedMethod_NonProjectableMethodCall_ReportsWarning() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - public int Bar { get; set; } - - [Projectable(AllowBlockBody = true)] - public int Foo() - { - Console.WriteLine(""test""); - return Bar; - } - } -} -"); - - var result = RunGenerator(compilation); - - // Should have a diagnostic about potential side effects - Assert.NotEmpty(result.Diagnostics); - Assert.Contains(result.Diagnostics, d => d.Id == "EFP0005"); - - return Verifier.Verify(result.Diagnostics.Select(d => d.ToString())); - } - - [Fact] - public Task MethodOverloads_WithDifferentParameterTypes() - { - // lang=csharp - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - [Projectable] - public int Method(int x) => x; - - [Projectable] - public int Method(string s) => s.Length; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Equal(2, result.GeneratedTrees.Length); - - // Verify both overloads are generated with distinct names - var generatedFiles = result.GeneratedTrees.Select(t => t.FilePath).ToList(); - Assert.Contains(generatedFiles, f => f.Contains("Method_P0_int.g.cs")); - Assert.Contains(generatedFiles, f => f.Contains("Method_P0_string.g.cs")); - - return Verifier.Verify(result.GeneratedTrees.Select(t => t.ToString())); - } - - [Fact] - public Task MethodOverloads_WithDifferentParameterCounts() - { - // lang=csharp - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class C { - [Projectable] - public int Method(int x) => x; - - [Projectable] - public int Method(int x, int y) => x + y; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Equal(2, result.GeneratedTrees.Length); - - // Verify both overloads are generated with distinct names - var generatedFiles = result.GeneratedTrees.Select(t => t.FilePath).ToList(); - Assert.Contains(generatedFiles, f => f.Contains("Method_P0_int.g.cs")); - Assert.Contains(generatedFiles, f => f.Contains("Method_P0_int_P1_int.g.cs")); - - return Verifier.Verify(result.GeneratedTrees.Select(t => t.ToString())); - } - -#if NET10_0_OR_GREATER - [Fact] - public Task ExtensionMemberProperty() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; - -namespace Foo { - class Entity { - public int Id { get; set; } - } - - static class EntityExtensions { - extension(Entity e) { - [Projectable] - public int DoubleId => e.Id * 2; - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ExtensionMemberMethod() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; - -namespace Foo { - class Entity { - public int Id { get; set; } - } - - static class EntityExtensions { - extension(Entity e) { - [Projectable] - public int TripleId() => e.Id * 3; - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ExtensionMemberMethodWithParameters() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; - -namespace Foo { - class Entity { - public int Id { get; set; } - } - - static class EntityExtensions { - extension(Entity e) { - [Projectable] - public int Multiply(int factor) => e.Id * factor; - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ExtensionMemberOnPrimitive() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; - -static class IntExtensions { - extension(int i) { - [Projectable] - public int Squared => i * i; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ExtensionMemberWithMemberAccess() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; - -namespace Foo { - class Entity { - public int Id { get; set; } - public string Name { get; set; } - } - - static class EntityExtensions { - extension(Entity e) { - [Projectable] - public string IdAndName => e.Id + "": "" + e.Name; - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ExtensionMemberWithBlockBody() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; - -namespace Foo { - class Entity { - public int Value { get; set; } - public bool IsActive { get; set; } - } - - static class EntityExtensions { - extension(Entity e) { - [Projectable(AllowBlockBody = true)] - public string GetStatus() - { - if (e.IsActive && e.Value > 0) - { - return ""Active""; - } - return ""Inactive""; - } - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ExtensionMemberWithSwitchExpression() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; - -namespace Foo { - class Entity { - public int Score { get; set; } - } - - static class EntityExtensions { - extension(Entity e) { - [Projectable] - public string GetGrade() => e.Score switch - { - >= 90 => ""A"", - >= 80 => ""B"", - >= 70 => ""C"", - _ => ""F"", - }; - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ExtensionMemberOnInterface() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; - -namespace Foo { - interface IEntity { - int Id { get; } - string Name { get; } - } - - static class IEntityExtensions { - extension(IEntity e) { - [Projectable] - public string Label => e.Id + "": "" + e.Name; - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ExtensionMemberWithIsPatternExpression() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; - -namespace Foo { - class Entity { - public int Value { get; set; } - } - - static class EntityExtensions { - extension(Entity e) { - [Projectable] - public bool IsHighValue => e.Value is > 100; - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } -#endif - - [Fact] - public Task ExpandEnumMethodsWithDisplayAttribute() - { - var compilation = CreateCompilation(@" -using System; -using System.ComponentModel.DataAnnotations; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public enum CustomEnum - { - [Display(Name = ""Value 1"")] - Value1, - - [Display(Name = ""Value 2"")] - Value2, - } - - public static class EnumExtensions - { - public static string GetDisplayName(this CustomEnum value) - { - return value.ToString(); - } - } - - public record Entity - { - public int Id { get; set; } - public CustomEnum MyValue { get; set; } - - [Projectable(ExpandEnumMethods = true)] - public string MyEnumName => MyValue.GetDisplayName(); - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ExpandEnumMethodsWithNullableEnum() - { - var compilation = CreateCompilation(@" -using System; -using System.ComponentModel.DataAnnotations; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public enum CustomEnum - { - [Display(Name = ""First Value"")] - First, - - [Display(Name = ""Second Value"")] - Second, - } - - public static class EnumExtensions - { - public static string GetDisplayName(this CustomEnum value) - { - return value.ToString(); - } - } - - public record Entity - { - public int Id { get; set; } - public CustomEnum? MyValue { get; set; } - - [Projectable(ExpandEnumMethods = true)] - public string MyEnumName => MyValue.HasValue ? MyValue.Value.GetDisplayName() : null; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ExpandEnumMethodsWithDescriptionAttribute() - { - var compilation = CreateCompilation(@" -using System; -using System.ComponentModel; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public enum Status - { - [Description(""The item is pending"")] - Pending, - - [Description(""The item is approved"")] - Approved, - - [Description(""The item is rejected"")] - Rejected, - } - - public static class EnumExtensions - { - public static string GetDescription(this Status value) - { - return value.ToString(); - } - } - - public record Entity - { - public int Id { get; set; } - public Status Status { get; set; } - - [Projectable(ExpandEnumMethods = true)] - public string StatusDescription => Status.GetDescription(); - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ExpandEnumMethodsOnNavigationProperty() - { - var compilation = CreateCompilation(@" -using System; -using System.ComponentModel.DataAnnotations; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public enum OrderStatus - { - [Display(Name = ""Pending Review"")] - Pending, - - [Display(Name = ""Approved"")] - Approved, - } - - public static class EnumExtensions - { - public static string GetDisplayName(this OrderStatus value) - { - return value.ToString(); - } - } - - public record Order - { - public int Id { get; set; } - public OrderStatus Status { get; set; } - } - - public record OrderItem - { - public int Id { get; set; } - public Order Order { get; set; } - - [Projectable(ExpandEnumMethods = true)] - public string OrderStatusName => Order.Status.GetDisplayName(); - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ExpandEnumMethodsReturningBoolean() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public enum Status - { - Pending, - Approved, - Rejected, - } - - public static class EnumExtensions - { - public static bool IsApproved(this Status value) - { - return value == Status.Approved; - } - } - - public record Entity - { - public int Id { get; set; } - public Status Status { get; set; } - - [Projectable(ExpandEnumMethods = true)] - public bool IsStatusApproved => Status.IsApproved(); - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ExpandEnumMethodsReturningInteger() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public enum Priority - { - Low, - Medium, - High, - } - - public static class EnumExtensions - { - public static int GetSortOrder(this Priority value) - { - return (int)value; - } - } - - public record Entity - { - public int Id { get; set; } - public Priority Priority { get; set; } - - [Projectable(ExpandEnumMethods = true)] - public int PrioritySortOrder => Priority.GetSortOrder(); - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ExpandEnumMethodsWithParameter() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public enum Status - { - Pending, - Approved, - Rejected, - } - - public static class EnumExtensions - { - public static string GetDisplayNameWithPrefix(this Status value, string prefix) - { - return prefix + value.ToString(); - } - } - - public record Entity - { - public int Id { get; set; } - public Status Status { get; set; } - - [Projectable(ExpandEnumMethods = true)] - public string StatusWithPrefix => Status.GetDisplayNameWithPrefix(""Status: ""); - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ExpandEnumMethodsWithMultipleParameters() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public enum Status - { - Pending, - Approved, - Rejected, - } - - public static class EnumExtensions - { - public static string Format(this Status value, string prefix, string suffix) - { - return prefix + value.ToString() + suffix; - } - } - - public record Entity - { - public int Id { get; set; } - public Status Status { get; set; } - - [Projectable(ExpandEnumMethods = true)] - public string FormattedStatus => Status.Format(""["", ""]""); - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_BodyAssignments() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class PointDto { - public int X { get; set; } - public int Y { get; set; } - - public PointDto() { } - - [Projectable] - public PointDto(int x, int y) { - X = x; - Y = y; - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_WithBaseInitializer() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class Base { - public int Id { get; set; } - public Base(int id) { Id = id; } - - protected Base() { } - } - - class Child : Base { - public string Name { get; set; } - - public Child() { } - - [Projectable] - public Child(int id, string name) : base(id) { - Name = name; - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_Overloads() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class PersonDto { - public string FirstName { get; set; } - public string LastName { get; set; } - - public PersonDto() { } - - [Projectable] - public PersonDto(string firstName, string lastName) { - FirstName = firstName; - LastName = lastName; - } - - [Projectable] - public PersonDto(string fullName) { - FirstName = fullName; - LastName = string.Empty; - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Equal(2, result.GeneratedTrees.Length); - - return Verifier.Verify(result.GeneratedTrees.OrderBy(t => t.FilePath).Select(t => t.ToString())); - } - - [Fact] - public Task ProjectableConstructor_WithClassArgument() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class SourceEntity { - public int Id { get; set; } - public string Name { get; set; } - } - - class PersonDto { - public int Id { get; set; } - public string Name { get; set; } - - public PersonDto() { } - - [Projectable] - public PersonDto(SourceEntity source) { - Id = source.Id; - Name = source.Name; - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_WithMultipleClassArguments() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class NamePart { - public string Value { get; set; } - } - - class PersonDto { - public string FirstName { get; set; } - public string LastName { get; set; } - - public PersonDto() { } - - [Projectable] - public PersonDto(NamePart first, NamePart last) { - FirstName = first.Value; - LastName = last.Value; - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_WithIfElseLogic() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class PersonDto { - public string Label { get; set; } - public int Score { get; set; } - - public PersonDto() { } - - [Projectable] - public PersonDto(int score) { - Score = score; - if (score >= 90) { - Label = ""A""; - } else { - Label = ""B""; - } - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_WithLocalVariable() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class PersonDto { - public string FullName { get; set; } - - public PersonDto() { } - - [Projectable] - public PersonDto(string first, string last) { - var full = first + "" "" + last; - FullName = full; - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_WithBaseInitializerExpression() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class Base { - public string Code { get; set; } - public Base(string code) { Code = code; } - - protected Base() { } - } - - class Child : Base { - public string Name { get; set; } - - public Child() { } - - [Projectable] - public Child(string name, string rawCode) : base(rawCode.ToUpper()) { - Name = name; - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_WithBaseInitializerAndIfElse() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class Base { - public int Id { get; set; } - public Base(int id) { - if (id < 0) { - Id = 0; - } else { - Id = id; - } - } - - protected Base() { } - } - - class Child : Base { - public string Name { get; set; } - - public Child() { } - - [Projectable] - public Child(int id, string name) : base(id) { - Name = name; - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_WithIfNoElse() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class PersonDto { - public string Label { get; set; } - - public PersonDto() { } - - [Projectable] - public PersonDto(int score) { - Label = ""none""; - if (score >= 90) { - Label = ""A""; - } - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_ReferencingPreviouslyAssignedProperty() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class PersonDto { - public string FirstName { get; set; } - public string LastName { get; set; } - public string FullName { get; set; } - - public PersonDto() { } - - [Projectable] - public PersonDto(string firstName, string lastName) { - FirstName = firstName; - LastName = lastName; - FullName = FirstName + "" "" + LastName; - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_ReferencingBasePropertyInDerivedBody() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class Base { - public string Code { get; set; } - public Base(string code) { Code = code; } - - protected Base() { } - } - - class Child : Base { - public string Label { get; set; } - - public Child() { } - - [Projectable] - public Child(string code) : base(code) { - Label = ""["" + Code + ""]""; - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_ReferencingStaticConstMember() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class PersonDto { - internal const string Separator = "" - ""; - public string FullName { get; set; } - - public PersonDto() { } - - [Projectable] - public PersonDto(string first, string last) { - FullName = first + Separator + last; - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_ReferencingPreviouslyAssignedInBaseCtor() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class Base { - public int X { get; set; } - public int Y { get; set; } - public Base(int x, int y) { - X = x; - Y = x + y; // Y depends on X's assigned value (x) - } - - protected Base() { } - } - - class Child : Base { - public int Sum { get; set; } - - public Child() { } - - [Projectable] - public Child(int a, int b) : base(a, b) { - Sum = X + Y; - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_ThisInitializer_SimpleOverload() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class PersonDto { - public string FirstName { get; set; } - public string LastName { get; set; } - - public PersonDto() { } - - public PersonDto(string firstName, string lastName) { - FirstName = firstName; - LastName = lastName; - } - - [Projectable] - public PersonDto(string fullName) : this(fullName.Split(' ')[0], fullName.Split(' ')[1]) { - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_ThisInitializer_WithBodyAfter() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class PersonDto { - public string FirstName { get; set; } - public string LastName { get; set; } - public string FullName { get; set; } - - public PersonDto() { } - - public PersonDto(string firstName, string lastName) { - FirstName = firstName; - LastName = lastName; - } - - [Projectable] - public PersonDto(string fn, string ln, bool upper) : this(fn, ln) { - FullName = upper ? (FirstName + "" "" + LastName).ToUpper() : FirstName + "" "" + LastName; - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_ThisInitializer_WithIfElseInDelegated() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class PersonDto { - public string Label { get; set; } - public int Score { get; set; } - - public PersonDto() { } - - public PersonDto(int score) { - Score = score; - if (score >= 90) { - Label = ""A""; - } else { - Label = ""B""; - } - } - - [Projectable] - public PersonDto(int score, string prefix) : this(score) { - Label = prefix + Label; - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_ThisInitializer_ChainedThisAndBase() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class Base { - public int Id { get; set; } - public Base(int id) { Id = id; } - } - - class Child : Base { - public string Name { get; set; } - - public Child() : base(0) { } - - public Child(int id, string name) : base(id) { - Name = name; - } - - [Projectable] - public Child(int id, string name, string suffix) : this(id, name) { - Name = Name + suffix; - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_ThisInitializer_RefPreviouslyAssignedProperty() - { - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class PersonDto { - public string FirstName { get; set; } - public string LastName { get; set; } - public string FullName { get; set; } - - public PersonDto() { } - - public PersonDto(string firstName, string lastName) { - FirstName = firstName; - LastName = lastName; - FullName = FirstName + "" "" + LastName; - } - - [Projectable] - public PersonDto(string firstName) : this(firstName, ""Doe"") { - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public void ProjectableConstructor_WithoutParameterlessConstructor_EmitsDiagnostic() - { - // A class that only exposes a parameterized constructor (no parameterless one). - // The generator must emit EFP0008 and produce no code because the object-initializer - // pattern requires a parameterless constructor. - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class PersonDto { - public string Name { get; set; } - - // No parameterless constructor – only the one marked [Projectable]. - [Projectable] - public PersonDto(string name) { - Name = name; - } - } -} -"); - var result = RunGenerator(compilation); - - var diagnostic = Assert.Single(result.Diagnostics); - Assert.Equal("EFP0008", diagnostic.Id); - Assert.Equal(DiagnosticSeverity.Error, diagnostic.Severity); - Assert.Empty(result.GeneratedTrees); - } - - [Fact] - public Task ProjectableConstructor_WithExplicitParameterlessConstructor_Succeeds() - { - // A class that explicitly defines a parameterless constructor alongside the - // [Projectable] one – the generator should succeed and produce code. - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class PersonDto { - public string Name { get; set; } - - public PersonDto() { } - - [Projectable] - public PersonDto(string name) { - Name = name; - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - // ----------------------------------------------------------------------- - // Additional constructor tests – if/else, early return, nested, etc. - // ----------------------------------------------------------------------- - - [Fact] - public Task ProjectableConstructor_WithElseIfChain() - { - // if / else-if / else – three branches - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class GradeDto { - public string Grade { get; set; } - - public GradeDto() { } - - [Projectable] - public GradeDto(int score) { - if (score >= 90) { - Grade = ""A""; - } else if (score >= 75) { - Grade = ""B""; - } else if (score >= 60) { - Grade = ""C""; - } else { - Grade = ""F""; - } - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_WithNestedIfElse() - { - // if inside else – nested branching - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class StatusDto { - public string Status { get; set; } - - public StatusDto() { } - - [Projectable] - public StatusDto(bool isActive, bool isPremium) { - if (isActive) { - if (isPremium) { - Status = ""Active Premium""; - } else { - Status = ""Active Free""; - } - } else { - Status = ""Inactive""; - } - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public void ProjectableConstructor_WithEarlyReturn_GuardClause_EmitsDiagnostic() - { - // Return statements inside a [Projectable] constructor body are not supported. - // The generator must emit EFP0003 and skip code generation for this member. - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class ItemDto { - public string Name { get; set; } - public string Category { get; set; } - - public ItemDto() { } - - [Projectable] - public ItemDto(string name, string category) { - Name = name; - if (string.IsNullOrEmpty(category)) { - Category = ""Unknown""; - return; - } - Category = category; - } - } -} -"); - var result = RunGenerator(compilation); - - var diagnostic = Assert.Single(result.Diagnostics); - Assert.Equal("EFP0003", diagnostic.Id); - Assert.Equal(DiagnosticSeverity.Warning, diagnostic.Severity); - } - - [Fact] - public void ProjectableConstructor_WithMultipleEarlyReturns_EmitsDiagnostic() - { - // Multiple return statements inside a [Projectable] constructor body are not supported. - // The generator must emit EFP0003 on the first unsupported return encountered. - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class PriorityDto { - public string Level { get; set; } - - public PriorityDto() { } - - [Projectable] - public PriorityDto(int value) { - if (value < 0) { - Level = ""Invalid""; - return; - } - if (value == 0) { - Level = ""None""; - return; - } - if (value <= 5) { - Level = ""Low""; - return; - } - Level = ""High""; - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.NotEmpty(result.Diagnostics); - Assert.All(result.Diagnostics, d => Assert.Equal("EFP0003", d.Id)); - Assert.All(result.Diagnostics, d => Assert.Equal(DiagnosticSeverity.Warning, d.Severity)); - } - - [Fact] - public Task ProjectableConstructor_WithSequentialIfs() - { - // Multiple independent (non-else) if blocks that each may set a different property - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class FlagDto { - public string Tag { get; set; } - public bool IsVerified { get; set; } - public bool IsAdmin { get; set; } - - public FlagDto() { } - - [Projectable] - public FlagDto(string role, bool verified) { - Tag = role; - if (verified) { - IsVerified = true; - } - if (role == ""admin"") { - IsAdmin = true; - } - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_WithTernaryAssignment() - { - // Ternary (conditional) expression used directly in property assignment - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class LabelDto { - public string Label { get; set; } - public string Display { get; set; } - - public LabelDto() { } - - [Projectable] - public LabelDto(string name, bool uppercase) { - Label = name; - Display = uppercase ? name.ToUpper() : name.ToLower(); - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_WithNullCoalescing() - { - // Null-coalescing operator (??) in property assignment - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class ProductDto { - public string Name { get; set; } - public string Description { get; set; } - - public ProductDto() { } - - [Projectable] - public ProductDto(string name, string description) { - Name = name ?? ""Unnamed""; - Description = description ?? string.Empty; - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_WithSwitchExpression() - { - // Switch expression in property assignment - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class SeasonDto { - public string Name { get; set; } - public string Description { get; set; } - - public SeasonDto() { } - - [Projectable] - public SeasonDto(int month) { - Name = month switch { - 12 or 1 or 2 => ""Winter"", - 3 or 4 or 5 => ""Spring"", - 6 or 7 or 8 => ""Summer"", - _ => ""Autumn"" - }; - Description = ""Month: "" + month; - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_WithMultipleLocalVariables() - { - // Several local variables used to build up property values - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class AddressDto { - public string Street { get; set; } - public string City { get; set; } - public string Full { get; set; } - - public AddressDto() { } - - [Projectable] - public AddressDto(string street, string city, string country) { - var trimmedStreet = street.Trim(); - var trimmedCity = city.Trim(); - Street = trimmedStreet; - City = trimmedCity; - Full = trimmedStreet + "", "" + trimmedCity + "", "" + country; - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_WithNullableParameter() - { - // Nullable value-type parameter with null-coalescing default - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class MeasurementDto { - public double Value { get; set; } - public string Unit { get; set; } - - public MeasurementDto() { } - - [Projectable] - public MeasurementDto(double? value, string unit) { - Value = value ?? 0.0; - Unit = unit ?? ""m""; - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_WithLocalVariableUsedInCondition() - { - // Local variable computed from params, then used inside an if - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class RangeDto { - public int Min { get; set; } - public int Max { get; set; } - public bool IsValid { get; set; } - - public RangeDto() { } - - [Projectable] - public RangeDto(int a, int b) { - var lo = a < b ? a : b; - var hi = a < b ? b : a; - Min = lo; - Max = hi; - if (hi - lo > 0) { - IsValid = true; - } else { - IsValid = false; - } - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_WithBaseInitializer_AndIfElse_InDerivedBody() - { - // Derived constructor calls base AND has its own if/else logic - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class Animal { - public string Species { get; set; } - public Animal(string species) { Species = species; } - protected Animal() { } - } - - class Pet : Animal { - public string Name { get; set; } - public string Nickname { get; set; } - - public Pet() { } - - [Projectable] - public Pet(string species, string name, bool useShortName) : base(species) { - Name = name; - if (useShortName) { - Nickname = name.Length > 3 ? name.Substring(0, 3) : name; - } else { - Nickname = name; - } - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public void ProjectableConstructor_WithBaseInitializer_AndEarlyReturn_EmitsDiagnostic() - { - // A derived constructor that delegates to base() but uses an early return in its - // own body. Return statements are not supported → EFP0003 warning expected. - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class Vehicle { - public string Type { get; set; } - public Vehicle(string type) { Type = type; } - protected Vehicle() { } - } - - class Car : Vehicle { - public string Model { get; set; } - public int Year { get; set; } - - public Car() { } - - [Projectable] - public Car(string model, int year) : base(""Car"") { - Model = model; - if (year <= 0) { - Year = 2000; - return; - } - Year = year; - } - } -} -"); - var result = RunGenerator(compilation); - - var diagnostic = Assert.Single(result.Diagnostics); - Assert.Equal("EFP0003", diagnostic.Id); - Assert.Equal(DiagnosticSeverity.Warning, diagnostic.Severity); - } - - [Fact] - public Task ProjectableConstructor_WithDeepNestedIf() - { - // Three levels of nesting - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class AccessDto { - public string Access { get; set; } - - public AccessDto() { } - - [Projectable] - public AccessDto(bool isLoggedIn, bool isVerified, bool isAdmin) { - if (isLoggedIn) { - if (isVerified) { - if (isAdmin) { - Access = ""Full""; - } else { - Access = ""Verified""; - } - } else { - Access = ""Unverified""; - } - } else { - Access = ""Guest""; - } - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_WithIfInsideLocalScope_AndElse() - { - // if/else where both branches assign multiple properties - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class OrderDto { - public string Status { get; set; } - public string Note { get; set; } - public bool NeedsReview { get; set; } - - public OrderDto() { } - - [Projectable] - public OrderDto(int amount, bool flagged) { - if (flagged) { - Status = ""Flagged""; - Note = ""Requires manual review""; - NeedsReview = true; - } else { - Status = amount > 1000 ? ""Large"" : ""Normal""; - Note = string.Empty; - NeedsReview = false; - } - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_WithThisInitializer_AndElseIfInBody() - { - // this() delegation followed by else-if logic in own body - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class EventDto { - public string Title { get; set; } - public string Tag { get; set; } - public string Priority { get; set; } - - public EventDto() { } - - public EventDto(string title, string tag) { - Title = title; - Tag = tag; - } - - [Projectable] - public EventDto(string title, string tag, int urgency) : this(title, tag) { - if (urgency >= 10) { - Priority = ""Critical""; - } else if (urgency >= 5) { - Priority = ""High""; - } else { - Priority = ""Normal""; - } - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ProjectableConstructor_WithSwitchExpression_AndExtraProperty() - { - // Switch expression for one property, regular assignment for another - var compilation = CreateCompilation(@" -using EntityFrameworkCore.Projectables; - -namespace Foo { - class ShapeDto { - public string ShapeType { get; set; } - public int Sides { get; set; } - public string Description { get; set; } - - public ShapeDto() { } - - [Projectable] - public ShapeDto(int sides) { - Sides = sides; - ShapeType = sides switch { - 3 => ""Triangle"", - 4 => ""Rectangle"", - 5 => ""Pentagon"", - _ => ""Polygon"" - }; - Description = ShapeType + "" with "" + sides + "" sides""; - } - } -} -"); - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ExplicitInterfaceMember() - { - var compilation = CreateCompilation( - """ - using System; - using EntityFrameworkCore.Projectables; - - public interface IBase - { - int ComputedProperty { get; } - } - - public class Concrete : IBase - { - public int Id { get; } - - [Projectable] - int IBase.ComputedProperty => Id + 1; - } - """); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task DefaultInterfaceMember() - { - var compilation = CreateCompilation( - """ - using System; - using EntityFrameworkCore.Projectables; - - public interface IBase - { - int Id { get; } - int ComputedProperty { get; } - int ComputedMethod(); - } - - public interface IDefaultBase : IBase - { - [Projectable] - int Default => ComputedProperty * 2; - } - """); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task DefaultExplicitInterfaceMember() - { - var compilation = CreateCompilation( - """ - using System; - using EntityFrameworkCore.Projectables; - - public interface IBase - { - int Id { get; } - int ComputedProperty { get; } - int ComputedMethod(); - } - - public interface IDefaultBase - { - int Default { get; } - } - - public interface IDefaultBaseImplementation : IDefaultBase, IBase - { - [Projectable] - int IDefaultBase.Default => ComputedProperty * 2; - } - """); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task ExplicitInterfaceImplementation() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; - -namespace Foo { - public interface IStringId - { - string Id { get; } - } - - public class Item : IStringId - { - public int Id { get; set; } - - // Explicit interface implementation without [Projectable] - string IStringId.Id => Id.ToString(); - - [Projectable] - public string FormattedId => ((IStringId)this).Id; - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public void BlockBodiedMethod_WithoutAllowFlag_EmitsWarning() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; - -namespace Foo { - class C { - public int Value { get; set; } - - [Projectable] - public int GetDouble() - { - return Value * 2; - } - } -} -"); - var result = RunGenerator(compilation); - - // Should have a warning about experimental feature - var diagnostic = Assert.Single(result.Diagnostics); - Assert.Equal("EFP0001", diagnostic.Id); - Assert.Equal(DiagnosticSeverity.Warning, diagnostic.Severity); - } - - [Fact] - public void BlockBodiedMethod_WithAllowFlag_NoWarning() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; - -namespace Foo { - class C { - public int Value { get; set; } - - [Projectable(AllowBlockBody = true)] - public int GetDouble() - { - return Value * 2; - } - } -} -"); - var result = RunGenerator(compilation); - - // Should have no warnings - Assert.Empty(result.Diagnostics); - } - - [Fact] - public Task BlockBodiedMethod_WithPatternMatching() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class Entity { - public bool IsActive { get; set; } - public int Value { get; set; } - } - - static class Extensions { - [Projectable(AllowBlockBody = true)] - public static string GetComplexCategory(this Entity entity) - { - if (entity is { IsActive: true, Value: > 100 }) - { - return ""Active High""; - } - return ""Other""; - } - } -} -"); - - var result = RunGenerator(compilation); - - // The generator should not crash and should handle pattern matching - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BlockBodiedMethod_WithRelationalPattern() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class Entity { - public int Value { get; set; } - } - - static class Extensions { - [Projectable(AllowBlockBody = true)] - public static string GetCategory(this Entity entity) - { - if (entity.Value is > 100) - { - return ""High""; - } - return ""Low""; - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BlockBodiedMethod_WithConstantPattern() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class Entity { - public string Status { get; set; } - } - - static class Extensions { - [Projectable(AllowBlockBody = true)] - public static bool IsNull(this Entity entity) - { - if (entity is null) - { - return true; - } - return false; - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - [Fact] - public Task BlockBodiedMethod_WithNotPattern() - { - var compilation = CreateCompilation(@" -using System; -using EntityFrameworkCore.Projectables; -namespace Foo { - class Entity { - public string Name { get; set; } - } - - static class Extensions { - [Projectable(AllowBlockBody = true)] - public static bool IsNotNull(this Entity entity) - { - if (entity is not null) - { - return true; - } - return false; - } - } -} -"); - - var result = RunGenerator(compilation); - - Assert.Empty(result.Diagnostics); - Assert.Single(result.GeneratedTrees); - - return Verifier.Verify(result.GeneratedTrees[0].ToString()); - } - - #region Helpers - - Compilation CreateCompilation([StringSyntax("csharp")] string source) - { - var references = Basic.Reference.Assemblies. -#if NET10_0 - Net100 -#elif NET9_0 - Net90 -#elif NET8_0 - Net80 -#endif - .References.All.ToList(); - - references.Add(MetadataReference.CreateFromFile(typeof(ProjectableAttribute).Assembly.Location)); - - var compilation = CSharpCompilation.Create("compilation", - new[] { CSharpSyntaxTree.ParseText(source) }, - references, - new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); - -#if DEBUG - var compilationDiagnostics = compilation.GetDiagnostics(); - - if (!compilationDiagnostics.IsEmpty) - { - _testOutputHelper.WriteLine($"Original compilation diagnostics produced:"); - - foreach (var diagnostic in compilationDiagnostics) - { - _testOutputHelper.WriteLine($" > " + diagnostic.ToString()); - } - - if (compilationDiagnostics.Any(x => x.Severity == DiagnosticSeverity.Error)) - { - Debug.Fail("Compilation diagnostics produced"); - } - } -#endif - - return compilation; - } - - private GeneratorDriverRunResult RunGenerator(Compilation compilation) - { - _testOutputHelper.WriteLine("Running generator and updating compilation..."); - - var subject = new ProjectionExpressionGenerator(); - var driver = CSharpGeneratorDriver - .Create(subject) - .RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out _); - - var result = driver.GetRunResult(); - - if (result.Diagnostics.IsEmpty) - { - _testOutputHelper.WriteLine("Run did not produce diagnostics"); - } - else - { - _testOutputHelper.WriteLine("Diagnostics produced:"); - - foreach (var diagnostic in result.Diagnostics) - { - _testOutputHelper.WriteLine(" > " + diagnostic); - } - } - - foreach (var newSyntaxTree in result.GeneratedTrees) - { - _testOutputHelper.WriteLine($"Produced syntax tree with path produced: {newSyntaxTree.FilePath}"); - _testOutputHelper.WriteLine(newSyntaxTree.GetText().ToString()); - } - - // Verify that the generated code compiles without errors - var hasGeneratorErrors = result.Diagnostics.Any(d => d.Severity == DiagnosticSeverity.Error); - if (!hasGeneratorErrors && result.GeneratedTrees.Length > 0) - { - _testOutputHelper.WriteLine("Checking that generated code compiles..."); - - var compilationErrors = outputCompilation - .GetDiagnostics() - .Where(d => d.Severity == DiagnosticSeverity.Error) - .ToList(); - - if (compilationErrors.Count > 0) - { - _testOutputHelper.WriteLine("Generated code produced compilation errors:"); - foreach (var error in compilationErrors) - { - _testOutputHelper.WriteLine(" > " + error); - } - } - - Assert.Empty(compilationErrors); - } - - return result; - } - - #endregion - } -} diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTestsBase.cs b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTestsBase.cs new file mode 100644 index 0000000..9a791e2 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTestsBase.cs @@ -0,0 +1,117 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Xunit; +using Xunit.Abstractions; + +namespace EntityFrameworkCore.Projectables.Generator.Tests; + +public abstract class ProjectionExpressionGeneratorTestsBase +{ + protected readonly ITestOutputHelper _testOutputHelper; + + protected ProjectionExpressionGeneratorTestsBase(ITestOutputHelper testOutputHelper) + { + _testOutputHelper = testOutputHelper; + } + + protected Compilation CreateCompilation([StringSyntax("csharp")] string source) + { + var references = Basic.Reference.Assemblies. +#if NET10_0 + Net100 +#elif NET9_0 + Net90 +#elif NET8_0 + Net80 +#endif + .References.All.ToList(); + + references.Add(MetadataReference.CreateFromFile(typeof(ProjectableAttribute).Assembly.Location)); + + var compilation = CSharpCompilation.Create("compilation", + new[] { CSharpSyntaxTree.ParseText(source) }, + references, + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + +#if DEBUG + var compilationDiagnostics = compilation.GetDiagnostics(); + + if (!compilationDiagnostics.IsEmpty) + { + _testOutputHelper.WriteLine($"Original compilation diagnostics produced:"); + + foreach (var diagnostic in compilationDiagnostics) + { + _testOutputHelper.WriteLine($" > " + diagnostic.ToString()); + } + + if (compilationDiagnostics.Any(x => x.Severity == DiagnosticSeverity.Error)) + { + Debug.Fail("Compilation diagnostics produced"); + } + } +#endif + + return compilation; + } + + protected GeneratorDriverRunResult RunGenerator(Compilation compilation) + { + _testOutputHelper.WriteLine("Running generator and updating compilation..."); + + var subject = new ProjectionExpressionGenerator(); + var driver = CSharpGeneratorDriver + .Create(subject) + .RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out _); + + var result = driver.GetRunResult(); + + if (result.Diagnostics.IsEmpty) + { + _testOutputHelper.WriteLine("Run did not produce diagnostics"); + } + else + { + _testOutputHelper.WriteLine("Diagnostics produced:"); + + foreach (var diagnostic in result.Diagnostics) + { + _testOutputHelper.WriteLine(" > " + diagnostic); + } + } + + foreach (var newSyntaxTree in result.GeneratedTrees) + { + _testOutputHelper.WriteLine($"Produced syntax tree with path produced: {newSyntaxTree.FilePath}"); + _testOutputHelper.WriteLine(newSyntaxTree.GetText().ToString()); + } + + // Verify that the generated code compiles without errors + var hasGeneratorErrors = result.Diagnostics.Any(d => d.Severity == DiagnosticSeverity.Error); + if (!hasGeneratorErrors && result.GeneratedTrees.Length > 0) + { + _testOutputHelper.WriteLine("Checking that generated code compiles..."); + + var compilationErrors = outputCompilation + .GetDiagnostics() + .Where(d => d.Severity == DiagnosticSeverity.Error) + .ToList(); + + if (compilationErrors.Count > 0) + { + _testOutputHelper.WriteLine("Generated code produced compilation errors:"); + foreach (var error in compilationErrors) + { + _testOutputHelper.WriteLine(" > " + error); + } + } + + Assert.Empty(compilationErrors); + } + + return result; + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.FooOrBar.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.FooOrBar.verified.txt similarity index 96% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.FooOrBar.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.FooOrBar.verified.txt index 393afea..4cb996f 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.FooOrBar.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.FooOrBar.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using EntityFrameworkCore.Projectables; using System.Collections.Generic; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectablePropertyWithExplicitBlockGetterUsingThis.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.MinimalProjectableComputedProperty.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectablePropertyWithExplicitBlockGetterUsingThis.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.MinimalProjectableComputedProperty.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.MoreComplexProjectableComputedProperty.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.MoreComplexProjectableComputedProperty.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.MoreComplexProjectableComputedProperty.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.MoreComplexProjectableComputedProperty.verified.txt index 59b563c..dbbff3e 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.MoreComplexProjectableComputedProperty.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.MoreComplexProjectableComputedProperty.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using EntityFrameworkCore.Projectables; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NavigationProperties.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.NavigationProperties.verified.txt similarity index 96% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NavigationProperties.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.NavigationProperties.verified.txt index 034257c..043e27f 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.NavigationProperties.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.NavigationProperties.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using EntityFrameworkCore.Projectables; using System.Collections.Generic; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectablePropertyWithExplicitBlockGetterAndMethodCall.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.ProjectableComputedPropertyMethod.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectablePropertyWithExplicitBlockGetterAndMethodCall.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.ProjectableComputedPropertyMethod.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.MinimalProjectableComputedProperty.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.ProjectableComputedPropertyUsingThis.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.MinimalProjectableComputedProperty.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.ProjectableComputedPropertyUsingThis.verified.txt index dccc517..3ad21d6 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.MinimalProjectableComputedProperty.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.ProjectableComputedPropertyUsingThis.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using EntityFrameworkCore.Projectables; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableComputedPropertyWithExplicitBlockGetter.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.ProjectableComputedPropertyWithExplicitBlockGetter.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableComputedPropertyWithExplicitBlockGetter.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.ProjectableComputedPropertyWithExplicitBlockGetter.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableComputedPropertyWithExplicitExpressionGetter.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.ProjectableComputedPropertyWithExplicitExpressionGetter.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableComputedPropertyWithExplicitExpressionGetter.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.ProjectableComputedPropertyWithExplicitExpressionGetter.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectablePropertyToNavigationalProperty.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.ProjectablePropertyToNavigationalProperty.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectablePropertyToNavigationalProperty.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.ProjectablePropertyToNavigationalProperty.verified.txt index bbf47b8..6bbf82f 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectablePropertyToNavigationalProperty.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.ProjectablePropertyToNavigationalProperty.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectablePropertyWithExplicitExpressionGetter.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.ProjectablePropertyWithExplicitBlockGetter.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectablePropertyWithExplicitExpressionGetter.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.ProjectablePropertyWithExplicitBlockGetter.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableComputedPropertyMethod.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.ProjectablePropertyWithExplicitBlockGetterAndMethodCall.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableComputedPropertyMethod.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.ProjectablePropertyWithExplicitBlockGetterAndMethodCall.verified.txt index 4583693..fb4be05 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableComputedPropertyMethod.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.ProjectablePropertyWithExplicitBlockGetterAndMethodCall.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using EntityFrameworkCore.Projectables; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableComputedPropertyUsingThis.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.ProjectablePropertyWithExplicitBlockGetterUsingThis.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableComputedPropertyUsingThis.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.ProjectablePropertyWithExplicitBlockGetterUsingThis.verified.txt index dccc517..3ad21d6 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ProjectableComputedPropertyUsingThis.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.ProjectablePropertyWithExplicitBlockGetterUsingThis.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using EntityFrameworkCore.Projectables; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SimpleProjectableMethod.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.ProjectablePropertyWithExplicitExpressionGetter.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SimpleProjectableMethod.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.ProjectablePropertyWithExplicitExpressionGetter.verified.txt index ba0730c..c9f2bbb 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SimpleProjectableMethod.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.ProjectablePropertyWithExplicitExpressionGetter.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using EntityFrameworkCore.Projectables; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.RelationalProperty.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.RelationalProperty.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.RelationalProperty.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.RelationalProperty.verified.txt index 7e75c49..23d8106 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.RelationalProperty.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.RelationalProperty.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using System.Linq; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SimpleProjectableComputedInNestedClassProperty.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.SimpleProjectableComputedInNestedClassProperty.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SimpleProjectableComputedInNestedClassProperty.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.SimpleProjectableComputedInNestedClassProperty.verified.txt index a493b87..758ff1a 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SimpleProjectableComputedInNestedClassProperty.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.SimpleProjectableComputedInNestedClassProperty.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using EntityFrameworkCore.Projectables; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SimpleProjectableComputedProperty.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.SimpleProjectableComputedProperty.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SimpleProjectableComputedProperty.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.SimpleProjectableComputedProperty.verified.txt index 47b3e7c..1614e52 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SimpleProjectableComputedProperty.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.SimpleProjectableComputedProperty.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using EntityFrameworkCore.Projectables; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SimpleProjectableProperty.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.SimpleProjectableProperty.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SimpleProjectableProperty.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.SimpleProjectableProperty.verified.txt index ba0730c..c9f2bbb 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SimpleProjectableProperty.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.SimpleProjectableProperty.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using System; using EntityFrameworkCore.Projectables; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.cs b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.cs new file mode 100644 index 0000000..9ca49e3 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/PropertyTests.cs @@ -0,0 +1,474 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using VerifyXunit; +using Xunit; +using Xunit.Abstractions; + +namespace EntityFrameworkCore.Projectables.Generator.Tests; + +[UsesVerify] +public class PropertyTests : ProjectionExpressionGeneratorTestsBase +{ + public PropertyTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + [Fact] + public void EmtpyCode_Noop() + { + var compilation = CreateCompilation(@" +class C { } +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Empty(result.GeneratedTrees); + } + + [Fact] + public Task SimpleProjectableProperty() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + [Projectable] + public int Foo => 1; + } +} +"); + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task MinimalProjectableComputedProperty() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable] + public int Foo => Bar; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task SimpleProjectableComputedProperty() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable] + public int Foo => Bar + 1; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task SimpleProjectableComputedInNestedClassProperty() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + public class C { + public class D { + public int Bar { get; set; } + + [Projectable] + public int Foo => Bar + 1; + } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableComputedPropertyUsingThis() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable] + public int Foo => this.Bar; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableComputedPropertyMethod() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar() => 1; + + [Projectable] + public int Foo => Bar(); + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectablePropertyWithExplicitExpressionGetter() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + [Projectable] + public int Foo { get => 1; } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectablePropertyWithExplicitBlockGetter() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + [Projectable(AllowBlockBody = true)] + public int Foo { get { return 1; } } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableComputedPropertyWithExplicitExpressionGetter() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable] + public int Foo { get => Bar + 1; } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectableComputedPropertyWithExplicitBlockGetter() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable(AllowBlockBody = true)] + public int Foo { get { return Bar + 1; } } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectablePropertyWithExplicitBlockGetterUsingThis() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable(AllowBlockBody = true)] + public int Foo { get { return this.Bar; } } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectablePropertyWithExplicitBlockGetterAndMethodCall() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar() => 1; + + [Projectable(AllowBlockBody = true)] + public int Foo { get { return Bar(); } } + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public void ProjectablePropertyWithExplicitBlockGetter_WithoutAllowBlockBody_EmitsWarning() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + [Projectable] + public int Foo { get { return 1; } } + } +} +"); + + var result = RunGenerator(compilation); + + var diagnostic = Assert.Single(result.Diagnostics); + Assert.Equal("EFP0001", diagnostic.Id); + Assert.Equal(DiagnosticSeverity.Warning, diagnostic.Severity); + } + + [Fact] + public Task MoreComplexProjectableComputedProperty() + { + var compilation = CreateCompilation(@" +using System; +using EntityFrameworkCore.Projectables; +namespace Foo { + class C { + public int Bar { get; set; } + + [Projectable] + public int Foo => Bar + this.Bar + Bar; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ProjectablePropertyToNavigationalProperty() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using EntityFrameworkCore.Projectables; +namespace Foo { + class D { } + + class C { + public System.Collections.Generic.List Dees { get; set; } + + [Projectable] + public D Foo => Dees.First(); + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task NavigationProperties() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; +using System.Collections.Generic; + +namespace Projectables.Repro; + +public class SomeEntity +{ + public int Id { get; set; } + + public SomeEntity Parent { get; set; } + + public ICollection Children { get; set; } + + [Projectable] + public ICollection RootChildren => + Parent != null ? Parent.RootChildren : Children; +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task FooOrBar() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; +using System.Collections.Generic; + +namespace Projectables.Repro; + +public class SomeEntity +{ + public int Id { get; set; } + + public string Foo { get; set; } + + public string Bar { get; set; } + + [Projectable] + public string FooOrBar => + Foo != null ? Foo : Bar; +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task RelationalProperty() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using System.Collections.Generic; +using EntityFrameworkCore.Projectables; + +namespace Foos { + public class Foo { + public int Id { get; set; } + } + + public class Bar { + public Foo Foo { get; set; } + + [Projectable] + public int FooId => Foo.Id; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.DictionaryIndexInitializer_IsBeingRewritten.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.DictionaryIndexInitializer_IsBeingRewritten.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.DictionaryIndexInitializer_IsBeingRewritten.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.DictionaryIndexInitializer_IsBeingRewritten.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.DictionaryObjectInitializer_PreservesCollectionInitializerSyntax.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.DictionaryObjectInitializer_PreservesCollectionInitializerSyntax.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.DictionaryObjectInitializer_PreservesCollectionInitializerSyntax.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.DictionaryObjectInitializer_PreservesCollectionInitializerSyntax.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExpressionBodied_IsPattern_WithAndPattern.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.ExpressionBodied_IsPattern_WithAndPattern.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExpressionBodied_IsPattern_WithAndPattern.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.ExpressionBodied_IsPattern_WithAndPattern.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExpressionBodied_IsPattern_WithNotNullPattern.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.ExpressionBodied_IsPattern_WithNotNullPattern.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExpressionBodied_IsPattern_WithNotNullPattern.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.ExpressionBodied_IsPattern_WithNotNullPattern.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExpressionBodied_IsPattern_WithOrPattern.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.ExpressionBodied_IsPattern_WithOrPattern.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExpressionBodied_IsPattern_WithOrPattern.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.ExpressionBodied_IsPattern_WithOrPattern.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExpressionBodied_IsPattern_WithPropertyPattern.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.ExpressionBodied_IsPattern_WithPropertyPattern.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.ExpressionBodied_IsPattern_WithPropertyPattern.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.ExpressionBodied_IsPattern_WithPropertyPattern.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SwitchExpressionWithConstantPattern.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.SwitchExpressionWithConstantPattern.verified.txt similarity index 95% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SwitchExpressionWithConstantPattern.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.SwitchExpressionWithConstantPattern.verified.txt index e906cc7..fd7848e 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SwitchExpressionWithConstantPattern.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.SwitchExpressionWithConstantPattern.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using EntityFrameworkCore.Projectables; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SwitchExpressionWithTypePattern.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.SwitchExpressionWithTypePattern.verified.txt similarity index 96% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SwitchExpressionWithTypePattern.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.SwitchExpressionWithTypePattern.verified.txt index e611e59..4ed355a 100644 --- a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SwitchExpressionWithTypePattern.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.SwitchExpressionWithTypePattern.verified.txt @@ -1,4 +1,4 @@ -// +// #nullable disable using EntityFrameworkCore.Projectables; diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SwitchExpression_WithRelationalPattern.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.SwitchExpression_WithRelationalPattern.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SwitchExpression_WithRelationalPattern.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.SwitchExpression_WithRelationalPattern.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SwitchExpression_WithRelationalPattern_OnExtensionMethod.verified.txt b/tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.SwitchExpression_WithRelationalPattern_OnExtensionMethod.verified.txt similarity index 100% rename from tests/EntityFrameworkCore.Projectables.Generator.Tests/ProjectionExpressionGeneratorTests.SwitchExpression_WithRelationalPattern_OnExtensionMethod.verified.txt rename to tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.SwitchExpression_WithRelationalPattern_OnExtensionMethod.verified.txt diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.cs b/tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.cs new file mode 100644 index 0000000..3e809a8 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/SwitchPatternTests.cs @@ -0,0 +1,320 @@ +using System.Threading.Tasks; +using VerifyXunit; +using Xunit; +using Xunit.Abstractions; + +namespace EntityFrameworkCore.Projectables.Generator.Tests; + +[UsesVerify] +public class SwitchPatternTests : ProjectionExpressionGeneratorTestsBase +{ + public SwitchPatternTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + + [Fact] + public Task SwitchExpressionWithConstantPattern() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +class Foo { + public int? FancyNumber { get; set; } + + [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Rewrite)] + public int SomeNumber(int input) => input switch { + 1 => 2, + 3 => 4, + 4 when FancyNumber == 12 => 48, + _ => 1000, + }; + } +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task SwitchExpressionWithTypePattern() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +public abstract class Item +{ + public int Id { get; set; } + public string Name { get; set; } +} + +public class GroupItem : Item +{ + public string Description { get; set; } +} + +public class DocumentItem : Item +{ + public int Priority { get; set; } +} + +public abstract record ItemData(int Id, string Name); +public record GroupData(int Id, string Name, string Description) : ItemData(Id, Name); +public record DocumentData(int Id, string Name, int Priority) : ItemData(Id, Name); + +public static class ItemMapper +{ + [Projectable] + public static ItemData ToData(this Item item) => + item switch + { + GroupItem groupItem => new GroupData(groupItem.Id, groupItem.Name, groupItem.Description), + DocumentItem documentItem => new DocumentData(documentItem.Id, documentItem.Name, documentItem.Priority), + _ => null! + }; +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task SwitchExpression_WithRelationalPattern() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class Entity { + public int Score { get; set; } + + [Projectable] + public string GetGrade() => Score switch + { + >= 90 => ""A"", + >= 80 => ""B"", + >= 70 => ""C"", + _ => ""F"", + }; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task SwitchExpression_WithRelationalPattern_OnExtensionMethod() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class Order { + public decimal Amount { get; set; } + } + + static class OrderExtensions { + [Projectable] + public static string GetTier(this Order order) => order.Amount switch + { + >= 1000 => ""Platinum"", + >= 500 => ""Gold"", + >= 100 => ""Silver"", + _ => ""Bronze"", + }; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ExpressionBodied_IsPattern_WithAndPattern() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class Entity { + public int Value { get; set; } + + [Projectable] + public bool IsInRange => Value is >= 1 and <= 100; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ExpressionBodied_IsPattern_WithOrPattern() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class Entity { + public int Value { get; set; } + + [Projectable] + public bool IsOutOfRange => Value is 0 or > 100; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ExpressionBodied_IsPattern_WithPropertyPattern() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class Entity { + public bool IsActive { get; set; } + public int Value { get; set; } + } + + static class Extensions { + [Projectable] + public static bool IsActiveAndPositive(this Entity entity) => + entity is { IsActive: true, Value: > 0 }; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task ExpressionBodied_IsPattern_WithNotNullPattern() + { + var compilation = CreateCompilation(@" +using EntityFrameworkCore.Projectables; + +namespace Foo { + class Entity { + public string? Name { get; set; } + + [Projectable] + public bool HasName => Name is not null; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task DictionaryIndexInitializer_IsBeingRewritten() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using System.Collections.Generic; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public static class EntityExtensions + { + public record Entity + { + public int Id { get; set; } + public string? FullName { get; set; } + } + + [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Rewrite)] + public static Dictionary ToDictionary(this Entity entity) + => new Dictionary + { + [""FullName""] = entity.FullName ?? ""N/A"", + [""Id""] = entity.Id.ToString(), + }; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } + + [Fact] + public Task DictionaryObjectInitializer_PreservesCollectionInitializerSyntax() + { + var compilation = CreateCompilation(@" +using System; +using System.Linq; +using System.Collections.Generic; +using EntityFrameworkCore.Projectables; + +namespace Foo { + public static class EntityExtensions + { + public record Entity + { + public int Id { get; set; } + public string? FullName { get; set; } + } + + [Projectable(NullConditionalRewriteSupport = NullConditionalRewriteSupport.Rewrite)] + public static Dictionary ToDictionary(this Entity entity) + => new Dictionary + { + { ""FullName"", entity.FullName ?? ""N/A"" } + }; + } +} +"); + + var result = RunGenerator(compilation); + + Assert.Empty(result.Diagnostics); + Assert.Single(result.GeneratedTrees); + + return Verifier.Verify(result.GeneratedTrees[0].ToString()); + } +} \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Generator.Tests/VerifyInit.cs b/tests/EntityFrameworkCore.Projectables.Generator.Tests/VerifyInit.cs new file mode 100644 index 0000000..1d02679 --- /dev/null +++ b/tests/EntityFrameworkCore.Projectables.Generator.Tests/VerifyInit.cs @@ -0,0 +1,13 @@ +using System.Runtime.CompilerServices; + +namespace EntityFrameworkCore.Projectables.Generator.Tests; + +public static class VerifyInit +{ + [ModuleInitializer] + public static void Initialize() + { + // Uncomment the following line to enable auto-approval of snapshots. Make sure to review changes before enabling this. + // VerifierSettings.AutoVerify(); + } +} \ No newline at end of file