11
11
using Microsoft . CodeAnalysis . CSharp ;
12
12
using CommunityToolkit . Mvvm . ComponentModel ;
13
13
using Microsoft . VisualStudio . TestTools . UnitTesting ;
14
+ using System . Reflection . Emit ;
14
15
15
16
namespace CommunityToolkit . Mvvm . SourceGenerators . UnitTests ;
16
17
@@ -247,6 +248,9 @@ public partial class SampleViewModel
247
248
VerifyGeneratedDiagnostics < INotifyPropertyChangedGenerator > (
248
249
CSharpSyntaxTree . ParseText ( source , CSharpParseOptions . Default . WithLanguageVersion ( LanguageVersion . CSharp7_3 ) ) ,
249
250
"MVVMTK0008" ) ;
251
+
252
+ // Ensure that it succeeds with the minimum supported language version
253
+ VerifySuccessfulGeneration ( source ) ;
250
254
}
251
255
252
256
[ TestMethod ]
@@ -266,6 +270,9 @@ public partial class SampleViewModel
266
270
VerifyGeneratedDiagnostics < ObservableObjectGenerator > (
267
271
CSharpSyntaxTree . ParseText ( source , CSharpParseOptions . Default . WithLanguageVersion ( LanguageVersion . CSharp7_3 ) ) ,
268
272
"MVVMTK0008" ) ;
273
+
274
+ // Ensure that it succeeds with the minimum supported language version
275
+ VerifySuccessfulGeneration ( source ) ;
269
276
}
270
277
271
278
[ TestMethod ]
@@ -287,12 +294,16 @@ public partial class SampleViewModel
287
294
VerifyGeneratedDiagnostics < ObservablePropertyGenerator > (
288
295
CSharpSyntaxTree . ParseText ( source , CSharpParseOptions . Default . WithLanguageVersion ( LanguageVersion . CSharp7_3 ) ) ,
289
296
"MVVMTK0008" ) ;
297
+
298
+ // Ensure that it succeeds with the minimum supported language version
299
+ VerifySuccessfulGeneration ( source ) ;
290
300
}
291
301
292
302
[ TestMethod ]
293
303
public void UnsupportedCSharpLanguageVersion_FromObservableValidatorValidateAllPropertiesGenerator ( )
294
304
{
295
305
string source = @"
306
+ using System.ComponentModel.DataAnnotations;
296
307
using CommunityToolkit.Mvvm.ComponentModel;
297
308
298
309
namespace MyApp
@@ -304,9 +315,12 @@ public partial class SampleViewModel : ObservableValidator
304
315
}
305
316
}" ;
306
317
307
- // This is explicitly allowed in C# < 8.0, as it doesn't use any new features
308
318
VerifyGeneratedDiagnostics < ObservableValidatorValidateAllPropertiesGenerator > (
309
- CSharpSyntaxTree . ParseText ( source , CSharpParseOptions . Default . WithLanguageVersion ( LanguageVersion . CSharp7_3 ) ) ) ;
319
+ CSharpSyntaxTree . ParseText ( source , CSharpParseOptions . Default . WithLanguageVersion ( LanguageVersion . CSharp7_3 ) ) ,
320
+ "MVVMTK0008" ) ;
321
+
322
+ // Ensure that it succeeds with the minimum supported language version
323
+ VerifySuccessfulGeneration ( source ) ;
310
324
}
311
325
312
326
[ TestMethod ]
@@ -329,6 +343,9 @@ private void GreetUser(object value)
329
343
VerifyGeneratedDiagnostics < RelayCommandGenerator > (
330
344
CSharpSyntaxTree . ParseText ( source , CSharpParseOptions . Default . WithLanguageVersion ( LanguageVersion . CSharp7_3 ) ) ,
331
345
"MVVMTK0008" ) ;
346
+
347
+ // Ensure that it succeeds with the minimum supported language version
348
+ VerifySuccessfulGeneration ( source ) ;
332
349
}
333
350
334
351
[ TestMethod ]
@@ -351,9 +368,12 @@ public void Receive(MyMessage message)
351
368
}
352
369
}" ;
353
370
354
- // This is explicitly allowed in C# < 8.0, as it doesn't use any new features
355
371
VerifyGeneratedDiagnostics < IMessengerRegisterAllGenerator > (
356
- CSharpSyntaxTree . ParseText ( source , CSharpParseOptions . Default . WithLanguageVersion ( LanguageVersion . CSharp7_3 ) ) ) ;
372
+ CSharpSyntaxTree . ParseText ( source , CSharpParseOptions . Default . WithLanguageVersion ( LanguageVersion . CSharp7_3 ) ) ,
373
+ "MVVMTK0008" ) ;
374
+
375
+ // Ensure that it succeeds with the minimum supported language version
376
+ VerifySuccessfulGeneration ( source ) ;
357
377
}
358
378
359
379
[ TestMethod ]
@@ -1410,6 +1430,29 @@ private void GreetUser(User user)
1410
1430
VerifyGeneratedDiagnostics < RelayCommandGenerator > ( source , "MVVMTK0031" ) ;
1411
1431
}
1412
1432
1433
+ [ TestMethod ]
1434
+ public void ValidObservablePropertyGeneratorScenarios ( )
1435
+ {
1436
+ string source = @"
1437
+ using CommunityToolkit.Mvvm.ComponentModel;
1438
+
1439
+ namespace MyApp
1440
+ {
1441
+ [ObservableObject]
1442
+ public partial class SampleViewModel
1443
+ {
1444
+ [ObservableProperty]
1445
+ string name;
1446
+
1447
+ [ObservableProperty]
1448
+ [NotifyPropertyChangedFor(nameof(Name))]
1449
+ int number;
1450
+ }
1451
+ }" ;
1452
+
1453
+ VerifySuccessfulGeneration ( source ) ;
1454
+ }
1455
+
1413
1456
/// <summary>
1414
1457
/// Verifies the output of a source generator.
1415
1458
/// </summary>
@@ -1419,17 +1462,50 @@ private void GreetUser(User user)
1419
1462
private static void VerifyGeneratedDiagnostics < TGenerator > ( string source , params string [ ] diagnosticsIds )
1420
1463
where TGenerator : class , IIncrementalGenerator , new ( )
1421
1464
{
1422
- VerifyGeneratedDiagnostics < TGenerator > ( CSharpSyntaxTree . ParseText ( source ) , diagnosticsIds ) ;
1465
+ IIncrementalGenerator generator = new TGenerator ( ) ;
1466
+ VerifyGeneratedDiagnostics ( CSharpSyntaxTree . ParseText ( source , CSharpParseOptions . Default . WithLanguageVersion ( LanguageVersion . CSharp8 ) ) , new [ ] { generator } , diagnosticsIds ) ;
1467
+ }
1468
+
1469
+ /// <summary>
1470
+ /// Verifies the output of all source generators for input source (including subsequent compilation).
1471
+ /// </summary>
1472
+ /// <param name="source"></param>
1473
+ private static void VerifySuccessfulGeneration ( string source )
1474
+ {
1475
+ IIncrementalGenerator [ ] generators =
1476
+ {
1477
+ new IMessengerRegisterAllGenerator ( ) ,
1478
+ new NullabilityAttributesGenerator ( ) ,
1479
+ new ObservableObjectGenerator ( ) ,
1480
+ new INotifyPropertyChangedGenerator ( ) ,
1481
+ new ObservablePropertyGenerator ( ) ,
1482
+ new ObservableRecipientGenerator ( ) ,
1483
+ new ObservableValidatorValidateAllPropertiesGenerator ( ) ,
1484
+ new RelayCommandGenerator ( )
1485
+ } ;
1486
+ VerifyGeneratedDiagnostics ( CSharpSyntaxTree . ParseText ( source , CSharpParseOptions . Default . WithLanguageVersion ( LanguageVersion . CSharp8 ) ) , generators , new string [ ] { } ) ;
1423
1487
}
1424
1488
1425
1489
/// <summary>
1426
1490
/// Verifies the output of a source generator.
1427
1491
/// </summary>
1428
1492
/// <typeparam name="TGenerator">The generator type to use.</typeparam>
1429
- /// <param name="syntaxTree">The input source tree to process.</param>
1493
+ /// <param name="syntaxTree">The input source to process.</param>
1430
1494
/// <param name="diagnosticsIds">The diagnostic ids to expect for the input source code.</param>
1431
1495
private static void VerifyGeneratedDiagnostics < TGenerator > ( SyntaxTree syntaxTree , params string [ ] diagnosticsIds )
1432
1496
where TGenerator : class , IIncrementalGenerator , new ( )
1497
+ {
1498
+ IIncrementalGenerator generator = new TGenerator ( ) ;
1499
+ VerifyGeneratedDiagnostics ( syntaxTree , new [ ] { generator } , diagnosticsIds ) ;
1500
+ }
1501
+
1502
+ /// <summary>
1503
+ /// Verifies the output of a source generator.
1504
+ /// </summary>
1505
+ /// <typeparam name="TGenerator">The generator type to use.</typeparam>
1506
+ /// <param name="syntaxTree">The input source tree to process.</param>
1507
+ /// <param name="diagnosticsIds">The diagnostic ids to expect for the input source code.</param>
1508
+ private static void VerifyGeneratedDiagnostics ( SyntaxTree syntaxTree , IIncrementalGenerator [ ] generators , string [ ] generatorDiagnosticsIds )
1433
1509
{
1434
1510
Type observableObjectType = typeof ( ObservableObject ) ;
1435
1511
Type validationAttributeType = typeof ( ValidationAttribute ) ;
@@ -1446,15 +1522,22 @@ from assembly in AppDomain.CurrentDomain.GetAssemblies()
1446
1522
references ,
1447
1523
new CSharpCompilationOptions ( OutputKind . DynamicallyLinkedLibrary ) ) ;
1448
1524
1449
- IIncrementalGenerator generator = new TGenerator ( ) ;
1450
-
1451
- GeneratorDriver driver = CSharpGeneratorDriver . Create ( generator ) . WithUpdatedParseOptions ( ( CSharpParseOptions ) syntaxTree . Options ) ;
1525
+ GeneratorDriver driver = CSharpGeneratorDriver . Create ( generators ) . WithUpdatedParseOptions ( ( CSharpParseOptions ) syntaxTree . Options ) ;
1452
1526
1453
1527
_ = driver . RunGeneratorsAndUpdateCompilation ( compilation , out Compilation outputCompilation , out ImmutableArray < Diagnostic > diagnostics ) ;
1454
1528
1455
1529
HashSet < string > resultingIds = diagnostics . Select ( diagnostic => diagnostic . Id ) . ToHashSet ( ) ;
1456
1530
1457
- CollectionAssert . AreEquivalent ( diagnosticsIds , resultingIds . ToArray ( ) ) ;
1531
+ CollectionAssert . AreEquivalent ( generatorDiagnosticsIds , resultingIds . ToArray ( ) , $ "resultingIds: { string . Join ( ", " , resultingIds ) } ") ;
1532
+
1533
+ // If the compilation was supposed to succeed, ensure that no further errors were generated
1534
+ if ( resultingIds . Count == 0 )
1535
+ {
1536
+ // Compute diagnostics for the final compiled output (just include errors)
1537
+ List < Diagnostic > outputCompilationDiagnostics = outputCompilation . GetDiagnostics ( ) . Where ( diagnostic => diagnostic . Severity == DiagnosticSeverity . Error ) . ToList ( ) ;
1538
+
1539
+ Assert . IsTrue ( outputCompilationDiagnostics . Count == 0 , $ "resultingIds:{ Environment . NewLine } { string . Join ( Environment . NewLine , outputCompilationDiagnostics ) } ") ;
1540
+ }
1458
1541
1459
1542
GC . KeepAlive ( observableObjectType ) ;
1460
1543
GC . KeepAlive ( validationAttributeType ) ;
0 commit comments