Skip to content

Commit 845503d

Browse files
committed
Add codegen test for new partial property hooks
1 parent 7f4c880 commit 845503d

File tree

3 files changed

+149
-5
lines changed

3 files changed

+149
-5
lines changed

tests/CommunityToolkit.Mvvm.SourceGenerators.UnitTests/CommunityToolkit.Mvvm.SourceGenerators.UnitTests.projitems

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
</PropertyGroup>
1111
<ItemGroup>
1212
<Compile Include="$(MSBuildThisFileDirectory)Helpers\CSharpAnalyzerWithLanguageVersionTest{TAnalyzer}.cs" />
13+
<Compile Include="$(MSBuildThisFileDirectory)Test_SourceGeneratorsCodegen.cs" />
1314
<Compile Include="$(MSBuildThisFileDirectory)Test_SourceGeneratorsDiagnostics.cs" />
1415
</ItemGroup>
1516
</Project>
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Collections.Immutable;
8+
using System.ComponentModel.DataAnnotations;
9+
using System.IO;
10+
using System.Linq;
11+
using CommunityToolkit.Mvvm.ComponentModel;
12+
using Microsoft.CodeAnalysis;
13+
using Microsoft.CodeAnalysis.CSharp;
14+
using Microsoft.VisualStudio.TestTools.UnitTesting;
15+
16+
namespace CommunityToolkit.Mvvm.SourceGenerators.UnitTests;
17+
18+
[TestClass]
19+
public class Test_SourceGeneratorsCodegen
20+
{
21+
[TestMethod]
22+
public void ObservablePropertyWithPartialMethodWithPreviousValuesNotUsed_DoesNotGenerateFieldReadAndMarksOldValueAsNullable()
23+
{
24+
string source = """
25+
using System.ComponentModel;
26+
using CommunityToolkit.Mvvm.ComponentModel;
27+
28+
#nullable enable
29+
30+
namespace MyApp;
31+
32+
partial class MyViewModel : ObservableObject
33+
{
34+
[ObservableProperty]
35+
private string name = null!;
36+
}
37+
""";
38+
39+
string result = """
40+
// <auto-generated/>
41+
#pragma warning disable
42+
#nullable enable
43+
namespace MyApp
44+
{
45+
partial class MyViewModel
46+
{
47+
/// <inheritdoc cref="name"/>
48+
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.1.0.0")]
49+
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
50+
public string Name
51+
{
52+
get => name;
53+
set
54+
{
55+
if (!global::System.Collections.Generic.EqualityComparer<string>.Default.Equals(name, value))
56+
{
57+
OnNameChanging(value);
58+
OnNameChanging(default, value);
59+
OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Name);
60+
name = value;
61+
OnNameChanged(value);
62+
OnNameChanged(default, value);
63+
OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Name);
64+
}
65+
}
66+
}
67+
68+
/// <summary>Executes the logic for when <see cref="Name"/> is changing.</summary>
69+
/// <param name="value">The new property value being set.</param>
70+
/// <remarks>This method is invoked right before the value of <see cref="Name"/> is changed.</remarks>
71+
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.1.0.0")]
72+
partial void OnNameChanging(string value);
73+
/// <summary>Executes the logic for when <see cref="Name"/> is changing.</summary>
74+
/// <param name="oldValue">The previous property value that is being replaced.</param>
75+
/// <param name="newValue">The new property value being set.</param>
76+
/// <remarks>This method is invoked right before the value of <see cref="Name"/> is changed.</remarks>
77+
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.1.0.0")]
78+
partial void OnNameChanging(string? oldValue, string newValue);
79+
/// <summary>Executes the logic for when <see cref="Name"/> just changed.</summary>
80+
/// <param name="value">The new property value that was set.</param>
81+
/// <remarks>This method is invoked right after the value of <see cref="Name"/> is changed.</remarks>
82+
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.1.0.0")]
83+
partial void OnNameChanged(string value);
84+
/// <summary>Executes the logic for when <see cref="Name"/> just changed.</summary>
85+
/// <param name="oldValue">The previous property value that was replaced.</param>
86+
/// <param name="newValue">The new property value that was set.</param>
87+
/// <remarks>This method is invoked right after the value of <see cref="Name"/> is changed.</remarks>
88+
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.1.0.0")]
89+
partial void OnNameChanged(string? oldValue, string newValue);
90+
}
91+
}
92+
""";
93+
94+
VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, ("MyApp.MyViewModel.g.cs", result));
95+
}
96+
97+
/// <summary>
98+
/// Generates the requested sources
99+
/// </summary>
100+
/// <param name="source">The input source to process.</param>
101+
/// <param name="generators">The generators to apply to the input syntax tree.</param>
102+
/// <param name="results">The source files to compare.</param>
103+
private static void VerifyGenerateSources(string source, IIncrementalGenerator[] generators, params (string Filename, string Text)[] results)
104+
{
105+
// Ensure CommunityToolkit.Mvvm and System.ComponentModel.DataAnnotations are loaded
106+
Type observableObjectType = typeof(ObservableObject);
107+
Type validationAttributeType = typeof(ValidationAttribute);
108+
109+
// Get all assembly references for the loaded assemblies (easy way to pull in all necessary dependencies)
110+
IEnumerable<MetadataReference> references =
111+
from assembly in AppDomain.CurrentDomain.GetAssemblies()
112+
where !assembly.IsDynamic
113+
let reference = MetadataReference.CreateFromFile(assembly.Location)
114+
select reference;
115+
116+
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(source, CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp11));
117+
118+
// Create a syntax tree with the input source
119+
CSharpCompilation compilation = CSharpCompilation.Create(
120+
"original",
121+
new SyntaxTree[] { syntaxTree },
122+
references,
123+
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
124+
125+
GeneratorDriver driver = CSharpGeneratorDriver.Create(generators).WithUpdatedParseOptions((CSharpParseOptions)syntaxTree.Options);
126+
127+
// Run all source generators on the input source code
128+
_ = driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation outputCompilation, out ImmutableArray<Diagnostic> diagnostics);
129+
130+
// Ensure that no diagnostics were generated
131+
CollectionAssert.AreEquivalent(Array.Empty<Diagnostic>(), diagnostics);
132+
133+
foreach ((string filename, string text) in results)
134+
{
135+
SyntaxTree generatedTree = outputCompilation.SyntaxTrees.Single(tree => Path.GetFileName(tree.FilePath) == filename);
136+
137+
Assert.AreEqual(text, generatedTree.ToString());
138+
}
139+
140+
GC.KeepAlive(observableObjectType);
141+
GC.KeepAlive(validationAttributeType);
142+
}
143+
}

tests/CommunityToolkit.Mvvm.SourceGenerators.UnitTests/Test_SourceGeneratorsDiagnostics.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
using System.Collections.Immutable;
88
using System.ComponentModel.DataAnnotations;
99
using System.Linq;
10-
using Microsoft.CodeAnalysis;
11-
using Microsoft.CodeAnalysis.CSharp;
12-
using CommunityToolkit.Mvvm.ComponentModel;
13-
using Microsoft.VisualStudio.TestTools.UnitTesting;
10+
using System.Text.RegularExpressions;
1411
using System.Threading.Tasks;
12+
using CommunityToolkit.Mvvm.ComponentModel;
1513
using CommunityToolkit.Mvvm.SourceGenerators.UnitTests.Helpers;
16-
using System.Text.RegularExpressions;
14+
using Microsoft.CodeAnalysis;
15+
using Microsoft.CodeAnalysis.CSharp;
1716
using Microsoft.CodeAnalysis.Diagnostics;
17+
using Microsoft.VisualStudio.TestTools.UnitTesting;
1818

1919
namespace CommunityToolkit.Mvvm.SourceGenerators.UnitTests;
2020

0 commit comments

Comments
 (0)