11
11
using Microsoft . CodeAnalysis . CSharp ;
12
12
using CommunityToolkit . Mvvm . ComponentModel ;
13
13
using Microsoft . VisualStudio . TestTools . UnitTesting ;
14
+ using System . Threading . Tasks ;
15
+ using CommunityToolkit . Mvvm . SourceGenerators . UnitTests . Helpers ;
16
+ using System . Text . RegularExpressions ;
14
17
15
18
namespace CommunityToolkit . Mvvm . SourceGenerators . UnitTests ;
16
19
@@ -231,73 +234,85 @@ public partial class SampleViewModel
231
234
}
232
235
233
236
[ TestMethod ]
234
- public void UnsupportedCSharpLanguageVersion_FromINotifyPropertyChangedGenerator ( )
237
+ public async Task UnsupportedCSharpLanguageVersion_FromINotifyPropertyChangedGenerator ( )
235
238
{
236
239
string source = @"
237
240
using CommunityToolkit.Mvvm.ComponentModel;
238
241
239
242
namespace MyApp
240
243
{
241
244
[INotifyPropertyChanged]
242
- public partial class SampleViewModel
245
+ public partial class {|MVVMTK0008: SampleViewModel|}
243
246
{
244
247
}
245
248
}" ;
246
249
247
- VerifyGeneratedDiagnostics < INotifyPropertyChangedGenerator > (
248
- CSharpSyntaxTree . ParseText ( source , CSharpParseOptions . Default . WithLanguageVersion ( LanguageVersion . CSharp7_3 ) ) ,
249
- "MVVMTK0008" ) ;
250
-
251
- VerifySuccessfulGeneration ( source ) ;
250
+ await VerifyUnsupportedCSharpVersionAndSuccessfulGeneration ( source ) ;
252
251
}
253
252
254
253
[ TestMethod ]
255
- public void UnsupportedCSharpLanguageVersion_FromObservableObjectGenerator ( )
254
+ public async Task UnsupportedCSharpLanguageVersion_FromObservableObjectGenerator ( )
256
255
{
257
256
string source = @"
258
257
using CommunityToolkit.Mvvm.ComponentModel;
259
258
260
259
namespace MyApp
261
260
{
262
261
[ObservableObject]
263
- public partial class SampleViewModel
262
+ public partial class {|MVVMTK0008: SampleViewModel|}
264
263
{
265
264
}
266
265
}" ;
267
266
268
- VerifyGeneratedDiagnostics < ObservableObjectGenerator > (
269
- CSharpSyntaxTree . ParseText ( source , CSharpParseOptions . Default . WithLanguageVersion ( LanguageVersion . CSharp7_3 ) ) ,
270
- "MVVMTK0008" ) ;
271
-
272
- VerifySuccessfulGeneration ( source ) ;
267
+ await VerifyUnsupportedCSharpVersionAndSuccessfulGeneration ( source ) ;
273
268
}
274
269
275
270
[ TestMethod ]
276
- public void UnsupportedCSharpLanguageVersion_FromObservablePropertyGenerator ( )
271
+ public async Task UnsupportedCSharpLanguageVersion_FromObservablePropertyGenerator ( )
277
272
{
278
273
string source = @"
279
274
using CommunityToolkit.Mvvm.ComponentModel;
280
275
281
276
namespace MyApp
282
277
{
283
278
[INotifyPropertyChanged]
284
- public partial class SampleViewModel
279
+ public partial class {|MVVMTK0008: SampleViewModel|}
285
280
{
286
281
[ObservableProperty]
287
- private string name;
282
+ private string {|MVVMTK0008: name|} ;
288
283
}
289
284
}" ;
290
285
291
- VerifyGeneratedDiagnostics < ObservablePropertyGenerator > (
292
- CSharpSyntaxTree . ParseText ( source , CSharpParseOptions . Default . WithLanguageVersion ( LanguageVersion . CSharp7_3 ) ) ,
293
- "MVVMTK0008" ) ;
286
+ await VerifyUnsupportedCSharpVersionAndSuccessfulGeneration ( source ) ;
287
+ }
294
288
295
- VerifySuccessfulGeneration ( source ) ;
289
+ [ TestMethod ]
290
+ public async Task UnsupportedCSharpLanguageVersion_FromObservablePropertyGenerator_MultipleAttributes ( )
291
+ {
292
+ string source = @"
293
+ using CommunityToolkit.Mvvm.ComponentModel;
294
+
295
+ namespace MyApp
296
+ {
297
+ [ObservableObject]
298
+ public partial class {|MVVMTK0008:SampleViewModel|}
299
+ {
300
+ [ObservableProperty]
301
+ string {|MVVMTK0008:name|};
302
+
303
+ [ObservableProperty]
304
+ [NotifyPropertyChangedFor(nameof(Bar))]
305
+ int {|MVVMTK0008:number|};
306
+
307
+ string Bar { get; set; }
308
+ }
309
+ }" ;
310
+
311
+ await VerifyUnsupportedCSharpVersionAndSuccessfulGeneration ( source ) ;
296
312
}
297
313
298
314
[ TestMethod ]
299
- [ Ignore ( "The generator should just not trigger at all in this scenario, update this after migrating diagnostics" ) ]
300
- public void UnsupportedCSharpLanguageVersion_FromObservableValidatorValidateAllPropertiesGenerator ( )
315
+ public async Task UnsupportedCSharpLanguageVersion_FromObservableValidatorValidateAllPropertiesGenerator ( )
301
316
{
302
317
string source = @"
303
318
using System.ComponentModel.DataAnnotations;
@@ -312,15 +327,11 @@ public partial class SampleViewModel : ObservableValidator
312
327
}
313
328
}" ;
314
329
315
- // Compilation should be fine on C# 7.3 as well (the generator just doesn't trigger)
316
- VerifyGeneratedDiagnostics < ObservableValidatorValidateAllPropertiesGenerator > (
317
- CSharpSyntaxTree . ParseText ( source , CSharpParseOptions . Default . WithLanguageVersion ( LanguageVersion . CSharp7_3 ) ) ) ;
318
-
319
- VerifySuccessfulGeneration ( source ) ;
330
+ await VerifyUnsupportedCSharpVersionAndSuccessfulGeneration ( source ) ;
320
331
}
321
332
322
333
[ TestMethod ]
323
- public void UnsupportedCSharpLanguageVersion_FromRelayCommandGenerator ( )
334
+ public async Task UnsupportedCSharpLanguageVersion_FromRelayCommandGenerator ( )
324
335
{
325
336
string source = @"
326
337
using CommunityToolkit.Mvvm.Input;
@@ -330,21 +341,17 @@ namespace MyApp
330
341
public partial class SampleViewModel
331
342
{
332
343
[RelayCommand]
333
- private void GreetUser(object value)
344
+ private void {|MVVMTK0008: GreetUser|} (object value)
334
345
{
335
346
}
336
347
}
337
348
}" ;
338
349
339
- VerifyGeneratedDiagnostics < RelayCommandGenerator > (
340
- CSharpSyntaxTree . ParseText ( source , CSharpParseOptions . Default . WithLanguageVersion ( LanguageVersion . CSharp7_3 ) ) ,
341
- "MVVMTK0008" ) ;
342
-
343
- VerifySuccessfulGeneration ( source ) ;
350
+ await VerifyUnsupportedCSharpVersionAndSuccessfulGeneration ( source ) ;
344
351
}
345
352
346
353
[ TestMethod ]
347
- public void UnsupportedCSharpLanguageVersion_FromIMessengerRegisterAllGenerator ( )
354
+ public async Task UnsupportedCSharpLanguageVersion_FromIMessengerRegisterAllGenerator ( )
348
355
{
349
356
string source = @"
350
357
using CommunityToolkit.Mvvm.Messaging;
@@ -363,12 +370,7 @@ public void Receive(MyMessage message)
363
370
}
364
371
}" ;
365
372
366
- // This should run fine on C# 8.0 too, as it doesn't use any newer features. Additionally, when not supported this
367
- // generator should just not run, not cause issues. The MVVM Toolkit has a reflection-based fallback path for this.
368
- VerifyGeneratedDiagnostics < IMessengerRegisterAllGenerator > (
369
- CSharpSyntaxTree . ParseText ( source , CSharpParseOptions . Default . WithLanguageVersion ( LanguageVersion . CSharp8 ) ) ) ;
370
-
371
- VerifySuccessfulGeneration ( source ) ;
373
+ await VerifyUnsupportedCSharpVersionAndSuccessfulGeneration ( source ) ;
372
374
}
373
375
374
376
[ TestMethod ]
@@ -1425,35 +1427,14 @@ private void GreetUser(User user)
1425
1427
VerifyGeneratedDiagnostics < RelayCommandGenerator > ( source , "MVVMTK0031" ) ;
1426
1428
}
1427
1429
1428
- [ TestMethod ]
1429
- public void ValidObservablePropertyGeneratorScenarios ( )
1430
- {
1431
- string source = @"
1432
- using CommunityToolkit.Mvvm.ComponentModel;
1433
-
1434
- namespace MyApp
1435
- {
1436
- [ObservableObject]
1437
- public partial class SampleViewModel
1438
- {
1439
- [ObservableProperty]
1440
- string name;
1441
-
1442
- [ObservableProperty]
1443
- [NotifyPropertyChangedFor(nameof(Name))]
1444
- int number;
1445
- }
1446
- }" ;
1447
-
1448
- VerifySuccessfulGeneration ( source ) ;
1449
- }
1450
-
1451
1430
/// <summary>
1452
- /// Verifies that all available source generators can run successfully with the input source (including subsequent compilation).
1431
+ /// Verifies the diagnostic error for unsupported C# version, and that all available source generators can run successfully with the input source (including subsequent compilation).
1453
1432
/// </summary>
1454
- /// <param name="source ">The input source to process.</param>
1455
- private static void VerifySuccessfulGeneration ( string source )
1433
+ /// <param name="markdownSource ">The input source to process with diagnostic annotations .</param>
1434
+ private static async Task VerifyUnsupportedCSharpVersionAndSuccessfulGeneration ( string markdownSource )
1456
1435
{
1436
+ await CSharpAnalyzerWithLanguageVersionTest < UnsupportedCSharpLanguageVersionAnalyzer > . VerifyAnalyzerAsync ( markdownSource , LanguageVersion . CSharp7_3 ) ;
1437
+
1457
1438
IIncrementalGenerator [ ] generators =
1458
1439
{
1459
1440
new IMessengerRegisterAllGenerator ( ) ,
@@ -1466,7 +1447,10 @@ private static void VerifySuccessfulGeneration(string source)
1466
1447
new RelayCommandGenerator ( )
1467
1448
} ;
1468
1449
1469
- VerifyGeneratedDiagnostics ( CSharpSyntaxTree . ParseText ( source , CSharpParseOptions . Default . WithLanguageVersion ( LanguageVersion . CSharp8 ) ) , generators , Array . Empty < string > ( ) ) ;
1450
+ // Transform diagnostic annotations back to normal C# (eg. "{|MVVMTK0008:Foo()|}" ---> "Foo()")
1451
+ string source = Regex . Replace ( markdownSource , @"{\|((?:,?\w+)+):(.+)\|}" , m => m . Groups [ 2 ] . Value ) ;
1452
+
1453
+ VerifyGeneratedDiagnostics ( CSharpSyntaxTree . ParseText ( source , CSharpParseOptions . Default . WithLanguageVersion ( LanguageVersion . CSharp7_3 ) ) , generators , Array . Empty < string > ( ) ) ;
1470
1454
}
1471
1455
1472
1456
/// <summary>
@@ -1505,15 +1489,18 @@ private static void VerifyGeneratedDiagnostics<TGenerator>(SyntaxTree syntaxTree
1505
1489
/// <param name="generatorDiagnosticsIds">The diagnostic ids to expect for the input source code.</param>
1506
1490
private static void VerifyGeneratedDiagnostics ( SyntaxTree syntaxTree , IIncrementalGenerator [ ] generators , string [ ] generatorDiagnosticsIds )
1507
1491
{
1492
+ // Ensure CommunityToolkit.Mvvm and System.ComponentModel.DataAnnotations are loaded
1508
1493
Type observableObjectType = typeof ( ObservableObject ) ;
1509
1494
Type validationAttributeType = typeof ( ValidationAttribute ) ;
1510
1495
1496
+ // Get all assembly references for the loaded assemblies (easy way to pull in all necessary dependencies)
1511
1497
IEnumerable < MetadataReference > references =
1512
1498
from assembly in AppDomain . CurrentDomain . GetAssemblies ( )
1513
1499
where ! assembly . IsDynamic
1514
1500
let reference = MetadataReference . CreateFromFile ( assembly . Location )
1515
1501
select reference ;
1516
1502
1503
+ // Create a syntax tree with the input source
1517
1504
CSharpCompilation compilation = CSharpCompilation . Create (
1518
1505
"original" ,
1519
1506
new SyntaxTree [ ] { syntaxTree } ,
@@ -1522,19 +1509,20 @@ from assembly in AppDomain.CurrentDomain.GetAssemblies()
1522
1509
1523
1510
GeneratorDriver driver = CSharpGeneratorDriver . Create ( generators ) . WithUpdatedParseOptions ( ( CSharpParseOptions ) syntaxTree . Options ) ;
1524
1511
1512
+ // Run all source generators on the input source code
1525
1513
_ = driver . RunGeneratorsAndUpdateCompilation ( compilation , out Compilation outputCompilation , out ImmutableArray < Diagnostic > diagnostics ) ;
1526
1514
1527
- HashSet < string > resultingIds = diagnostics . Select ( diagnostic => diagnostic . Id ) . ToHashSet ( ) ;
1515
+ string [ ] resultingIds = diagnostics . Select ( diagnostic => diagnostic . Id ) . ToArray ( ) ;
1528
1516
1529
- CollectionAssert . AreEquivalent ( generatorDiagnosticsIds , resultingIds . ToArray ( ) , $ "resultingIds: { string . Join ( ", " , resultingIds ) } ") ;
1517
+ CollectionAssert . AreEquivalent ( generatorDiagnosticsIds , resultingIds , $ "resultingIds: { string . Join ( ", " , resultingIds ) } ") ;
1530
1518
1531
1519
// If the compilation was supposed to succeed, ensure that no further errors were generated
1532
- if ( resultingIds . Count == 0 )
1520
+ if ( resultingIds . Length == 0 )
1533
1521
{
1534
1522
// Compute diagnostics for the final compiled output (just include errors)
1535
1523
List < Diagnostic > outputCompilationDiagnostics = outputCompilation . GetDiagnostics ( ) . Where ( diagnostic => diagnostic . Severity == DiagnosticSeverity . Error ) . ToList ( ) ;
1536
1524
1537
- Assert . IsTrue ( outputCompilationDiagnostics . Count == 0 , $ "resultingIds:{ Environment . NewLine } { string . Join ( Environment . NewLine , outputCompilationDiagnostics ) } ") ;
1525
+ Assert . IsTrue ( outputCompilationDiagnostics . Count == 0 , $ "resultingIds: { string . Join ( ", " , outputCompilationDiagnostics ) } ") ;
1538
1526
}
1539
1527
1540
1528
GC . KeepAlive ( observableObjectType ) ;
0 commit comments