public async Task AddingFileWithNewLibraryImport_DoesNotRegenerateOriginalMethod() { string source = CodeSnippets.BasicParametersAndModifiers <int>(); Compilation comp1 = await TestUtils.CreateCompilation(source); Microsoft.Interop.LibraryImportGenerator generator = new(); GeneratorDriver driver = TestUtils.CreateDriver(comp1, null, new[] { generator }, EnableIncrementalTrackingDriverOptions); driver = driver.RunGenerators(comp1); Compilation comp2 = comp1.AddSyntaxTrees(CSharpSyntaxTree.ParseText(CodeSnippets.BasicParametersAndModifiers <bool>(), new CSharpParseOptions(LanguageVersion.Preview))); GeneratorDriver driver2 = driver.RunGenerators(comp2); GeneratorRunResult runResult = driver2.GetRunResult().Results[0]; Assert.Collection(runResult.TrackedSteps[StepNames.CalculateStubInformation], step => { Assert.Collection(step.Outputs, output => Assert.Equal(IncrementalStepRunReason.Unchanged, output.Reason)); }, step => { Assert.Collection(step.Outputs, output => Assert.Equal(IncrementalStepRunReason.New, output.Reason)); }); }
public async Task ReplacingFileWithNewLibraryImport_DoesNotRegenerateStubsInOtherFiles() { Compilation comp1 = await TestUtils.CreateCompilation(new string[] { CodeSnippets.BasicParametersAndModifiers <int>(), CodeSnippets.MarshalAsParametersAndModifiers <bool>(UnmanagedType.I1) }); Microsoft.Interop.LibraryImportGenerator generator = new(); GeneratorDriver driver = TestUtils.CreateDriver(comp1, null, new[] { generator }, EnableIncrementalTrackingDriverOptions); driver = driver.RunGenerators(comp1); Compilation comp2 = comp1.ReplaceSyntaxTree(comp1.SyntaxTrees.First(), CSharpSyntaxTree.ParseText(CodeSnippets.BasicParametersAndModifiers <ulong>(), new CSharpParseOptions(LanguageVersion.Preview))); GeneratorDriver driver2 = driver.RunGenerators(comp2); GeneratorRunResult runResult = driver2.GetRunResult().Results[0]; Assert.Collection(runResult.TrackedSteps[StepNames.CalculateStubInformation], step => { Assert.Collection(step.Outputs, output => Assert.Equal(IncrementalStepRunReason.Modified, output.Reason)); }, step => { Assert.Collection(step.Outputs, output => Assert.Equal(IncrementalStepRunReason.Unchanged, output.Reason)); }); }
public async Task AppendingUnrelatedSource_DoesNotRegenerateSource() { string source = $"namespace NS{{{CodeSnippets.BasicParametersAndModifiers<int>()}}}"; SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(source, new CSharpParseOptions(LanguageVersion.Preview)); Compilation comp1 = await TestUtils.CreateCompilation(new[] { syntaxTree }); Microsoft.Interop.LibraryImportGenerator generator = new(); GeneratorDriver driver = TestUtils.CreateDriver(comp1, null, new[] { generator }, EnableIncrementalTrackingDriverOptions); driver = driver.RunGenerators(comp1); SyntaxTree newTree = syntaxTree.WithRootAndOptions(syntaxTree.GetCompilationUnitRoot().AddMembers(SyntaxFactory.ParseMemberDeclaration("struct Foo {}") !), syntaxTree.Options); Compilation comp2 = comp1.ReplaceSyntaxTree(comp1.SyntaxTrees.First(), newTree); GeneratorDriver driver2 = driver.RunGenerators(comp2); GeneratorRunResult runResult = driver2.GetRunResult().Results[0]; Assert.Collection(runResult.TrackedSteps[StepNames.CalculateStubInformation], step => { // The input contains symbols and Compilation objects, so it will always be different. // However, we validate that the calculated stub information is identical. Assert.Collection(step.Outputs, output => Assert.Equal(IncrementalStepRunReason.Unchanged, output.Reason)); }); }
public void AddJsonMergePatch_AddsExtensionMethod() { // Create the 'input' compilation that the generator will act on Compilation inputCompilation = CreateCompilation(@" namespace TestCode1 { public class Dto { public int Property { get; set; } } public class Program { public void SomeMethod(LaDeak.JsonMergePatch.Abstractions.Patch<Dto> data) { } } } "); var commonGenerator = new JsonMergePatchSourceGenerator(); var sut = new AspNetJsonMergePatchSourceGenerator(); GeneratorDriver driver = CSharpGeneratorDriver.Create(commonGenerator, sut); driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); Assert.True(diagnostics.IsEmpty); GeneratorDriverRunResult runResult = driver.GetRunResult(); GeneratorRunResult testedGenerator = runResult.Results[1]; Assert.Single(testedGenerator.GeneratedSources); Assert.Empty(testedGenerator.Diagnostics); }
/// <summary> /// Initializes a new instance of the <see cref="AttributeTargetGeneratorTestResult"/> struct. /// </summary> /// <param name="generatorDriver">A <see cref="CSharpGeneratorDriver"/> that was used to perform the test.</param> /// <param name="inputCompilation">A <see cref="CSharpCompilation"/> that represent an input for the tested <see cref="ISourceGenerator"/>.</param> /// <param name="outputCompilation">A <see cref="CSharpCompilation"/> that was created by the tested <see cref="ISourceGenerator"/>.</param> public AttributeTargetGeneratorTestResult(GeneratorDriver generatorDriver, CSharpCompilation inputCompilation, CSharpCompilation outputCompilation) { InputCompilation = inputCompilation; OutputCompilation = outputCompilation; _runResult = generatorDriver.GetRunResult().Results[0]; if (_runResult.Exception is null && _runResult.GeneratedSources.Length > 1) { Attribute = _runResult.GeneratedSources[0]; Source = _runResult.GeneratedSources[1]; IsGenerated = Attribute.SyntaxTree is CSharpSyntaxTree && Source.SyntaxTree is CSharpSyntaxTree; }
public void Verify_generator_works() { // Create the 'input' compilation that the generator will act on Compilation inputCompilation = CreateCompilation(@" [assembly: NServiceBusEndpointName(""test"")] namespace MyCode { public class Program { public static void Main(string[] args) { } } } "); // directly create an instance of the generator // (Note: in the compiler this is loaded from an assembly, and created via reflection at runtime) var generator = new CodeGenLibrary.FunctionEndpointTriggerGenerator(); // Create the driver that will control the generation, passing in our generator GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // Run the generation pass // (Note: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls) driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); // We can now assert things about the resulting compilation: Debug.Assert(diagnostics.IsEmpty); // there were no diagnostics created by the generators Debug.Assert(outputCompilation.SyntaxTrees.Count() == 3); // we have 3 syntax trees, the original 'user' provided one, attribute, and a trigger class //Debug.Assert(outputCompilation.GetDiagnostics().IsEmpty); // verify the compilation with the added source has no diagnostics // Or we can look at the results directly: GeneratorDriverRunResult runResult = driver.GetRunResult(); // The runResult contains the combined results of all generators passed to the driver Debug.Assert(runResult.GeneratedTrees.Length == 2); Debug.Assert(runResult.Diagnostics.IsEmpty); // Or you can access the individual results on a by-generator basis GeneratorRunResult generatorResult = runResult.Results[0]; Debug.Assert(generatorResult.Generator == generator); Debug.Assert(generatorResult.Diagnostics.IsEmpty); Debug.Assert(generatorResult.GeneratedSources.Length == 2); Debug.Assert(generatorResult.Exception is null); }
/// <summary> /// Initializes a new instance of the <see cref="SingletonGeneratorTestResult"/> struct. /// </summary> /// <param name="generatorDriver">A <see cref="CSharpGeneratorDriver"/> that was used to perform the test.</param> /// <param name="inputCompilation">A <see cref="CSharpCompilation"/> that represent an input for the tested <see cref="ISourceGenerator"/>.</param> /// <param name="outputCompilation">A <see cref="CSharpCompilation"/> that was created by the tested <see cref="ISourceGenerator"/>.</param> /// <param name="sourceIndex">Index of the target <see cref="CSharpSyntaxTree"/> in the generator's output.</param> public SingletonGeneratorTestResult(CSharpGeneratorDriver generatorDriver, CSharpCompilation inputCompilation, CSharpCompilation outputCompilation, int sourceIndex) { InputCompilation = inputCompilation; OutputCompilation = outputCompilation; _runResult = generatorDriver.GetRunResult().Results[0]; bool isGenerated = _runResult.Exception is null && _runResult.GeneratedSources.Length > sourceIndex; if (isGenerated) { _sourceResult = _runResult.GeneratedSources[sourceIndex]; _tree = _sourceResult.SyntaxTree as CSharpSyntaxTree; isGenerated = _tree is not null; } else { _sourceResult = default; _tree = null; } IsGenerated = isGenerated; }
public async Task ChangingMarshallingStrategy_RegeneratesStub() { string stubSource = CodeSnippets.BasicParametersAndModifiers("CustomType"); string customTypeImpl1 = "struct CustomType { System.IntPtr handle; }"; string customTypeImpl2 = "class CustomType : Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid { public CustomType():base(true){} protected override bool ReleaseHandle(){return true;} }"; Compilation comp1 = await TestUtils.CreateCompilation(stubSource); SyntaxTree customTypeImpl1Tree = CSharpSyntaxTree.ParseText(customTypeImpl1, new CSharpParseOptions(LanguageVersion.Preview)); comp1 = comp1.AddSyntaxTrees(customTypeImpl1Tree); Microsoft.Interop.LibraryImportGenerator generator = new(); GeneratorDriver driver = TestUtils.CreateDriver(comp1, null, new[] { generator }, EnableIncrementalTrackingDriverOptions); driver = driver.RunGenerators(comp1); Compilation comp2 = comp1.ReplaceSyntaxTree(customTypeImpl1Tree, CSharpSyntaxTree.ParseText(customTypeImpl2, new CSharpParseOptions(LanguageVersion.Preview))); GeneratorDriver driver2 = driver.RunGenerators(comp2); GeneratorRunResult runResult = driver2.GetRunResult().Results[0]; Assert.Collection(runResult.TrackedSteps[StepNames.CalculateStubInformation], step => { Assert.Collection(step.Outputs, output => Assert.Equal(IncrementalStepRunReason.Modified, output.Reason)); }); Assert.Collection(runResult.TrackedSteps[StepNames.GenerateSingleStub], step => { Assert.Collection(step.Outputs, output => Assert.Equal(IncrementalStepRunReason.Modified, output.Reason)); }); }
public async Task ChangingMarshallingAttributes_SameStrategy_DoesNotRegenerate() { string source = CodeSnippets.BasicParametersAndModifiers <int>(); SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(source, new CSharpParseOptions(LanguageVersion.Preview)); Compilation comp1 = await TestUtils.CreateCompilation(new[] { syntaxTree }); Microsoft.Interop.LibraryImportGenerator generator = new(); GeneratorDriver driver = TestUtils.CreateDriver(comp1, null, new[] { generator }, EnableIncrementalTrackingDriverOptions); driver = driver.RunGenerators(comp1); SyntaxTree newTree = syntaxTree.WithRootAndOptions( SyntaxFactory.ParseCompilationUnit( CodeSnippets.MarshalAsParametersAndModifiers <int>(System.Runtime.InteropServices.UnmanagedType.I4)), syntaxTree.Options); Compilation comp2 = comp1.ReplaceSyntaxTree(comp1.SyntaxTrees.First(), newTree); GeneratorDriver driver2 = driver.RunGenerators(comp2); GeneratorRunResult runResult = driver2.GetRunResult().Results[0]; Assert.Collection(runResult.TrackedSteps[StepNames.CalculateStubInformation], step => { Assert.Collection(step.Outputs, output => Assert.Equal(IncrementalStepRunReason.Modified, output.Reason)); }); Assert.Collection(runResult.TrackedSteps[StepNames.GenerateSingleStub], step => { Assert.Collection(step.Outputs, output => Assert.Equal(IncrementalStepRunReason.Unchanged, output.Reason)); }); }
public void SimpleGeneratorTest() { // Input for our generator. Compilation inputCompilation = CreateCompilation(@" namespace WalletWasabi.Fluent.ViewModels { public class TestViewModel2 { [AutoNotify(PropertyName = ""TestName"")] private bool _prop1; [AutoNotify(SetterModifier = AccessModifier.None)] private bool _prop2 = false; [AutoNotify(SetterModifier = AccessModifier.Public)] private bool _prop3; [AutoNotify(SetterModifier = AccessModifier.Protected)] private bool _prop4; [AutoNotify(SetterModifier = AccessModifier.Private)] private bool _prop5; [AutoNotify(SetterModifier = AccessModifier.Internal)] private bool _prop6; } } "); AutoNotifyGenerator generator = new(); GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // Run the generation pass driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); Assert.True(diagnostics.IsEmpty); Assert.Equal(4, outputCompilation.SyntaxTrees.Count()); GeneratorDriverRunResult runResult = driver.GetRunResult(); Assert.Equal(3, runResult.GeneratedTrees.Length); Assert.True(runResult.Diagnostics.IsEmpty); GeneratorRunResult generatorResult = runResult.Results[0]; Assert.True(generatorResult.Exception is null); Assert.Equal(generatorResult.Generator, generator); Assert.True(generatorResult.Diagnostics.IsEmpty); Assert.Equal(3, generatorResult.GeneratedSources.Length); string expectedGeneratedSourceCode = @" // <auto-generated /> #nullable enable using ReactiveUI; namespace WalletWasabi.Fluent.ViewModels { public partial class TestViewModel2 : ReactiveUI.ReactiveObject { public bool TestName { get => _prop1; set => this.RaiseAndSetIfChanged(ref _prop1, value); } public bool Prop2 { get => _prop2; } public bool Prop3 { get => _prop3; set => this.RaiseAndSetIfChanged(ref _prop3, value); } public bool Prop4 { get => _prop4; protected set => this.RaiseAndSetIfChanged(ref _prop4, value); } public bool Prop5 { get => _prop5; private set => this.RaiseAndSetIfChanged(ref _prop5, value); } public bool Prop6 { get => _prop6; internal set => this.RaiseAndSetIfChanged(ref _prop6, value); } } }".Trim(); Assert.Equal(expectedGeneratedSourceCode, generatorResult.GeneratedSources[2].SourceText.ToString()); }
public void GenerationFormat() { var source = @"using DevExpress.Mvvm.CodeGenerators; namespace Test { [GenerateViewModel(ImplementINotifyPropertyChanging = true, ImplementIDataErrorInfo = true, ImplementISupportServices = true)] partial class Example { [GenerateProperty] [System.ComponentModel.DataAnnotations.Range(0, 1)] int property; [GenerateCommand] public void Method(int arg) { } } public class Program { public static void Main(string[] args) { } } } "; Compilation inputCompilation = CSharpCompilation.Create("MyCompilation", new[] { CSharpSyntaxTree.ParseText(source) }, new[] { MetadataReference.CreateFromFile(typeof(DelegateCommand).Assembly.Location), MetadataReference.CreateFromFile(typeof(System.ComponentModel.DataAnnotations.RangeAttribute).Assembly.Location), MetadataReference.CreateFromFile(typeof(System.Windows.Input.ICommand).Assembly.Location), MetadataReference.CreateFromFile(typeof(object).Assembly.Location), }, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); ViewModelGenerator generator = new ViewModelGenerator(); GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); GeneratorDriverRunResult runResult = driver.GetRunResult(); GeneratorRunResult generatorResult = runResult.Results[0]; var generatedCode = generatorResult.GeneratedSources[1].SourceText.ToString(); var tabs = 0; foreach (var str in generatedCode.Split(new[] { Environment.NewLine }, StringSplitOptions.None)) { if (string.IsNullOrEmpty(str)) { continue; } if (str.Contains("}") && !str.Contains("{")) { if (str.EndsWith("}")) { tabs--; } else { Assert.Fail(); } } var expectedLeadingWhitespaceCount = tabs * 4; var leadingWhitespaceCount = str.Length - str.TrimStart().Length; Assert.AreEqual(expectedLeadingWhitespaceCount, leadingWhitespaceCount); if (str.EndsWith("{")) { tabs++; } } }
/// <summary> /// Initializes a new instance of the <see cref="MultiOutputGeneratorTestResult"/> struct. /// </summary> /// <param name="generatorDriver">A <see cref="CSharpGeneratorDriver"/> that was used to perform the test.</param> /// <param name="inputCompilation">A <see cref="CSharpCompilation"/> that represent an input for the tested <see cref="ISourceGenerator"/>.</param> /// <param name="outputCompilation">A <see cref="CSharpCompilation"/> that was created by the tested <see cref="ISourceGenerator"/>.</param> public MultiOutputGeneratorTestResult(GeneratorDriver generatorDriver, CSharpCompilation inputCompilation, CSharpCompilation outputCompilation) { InputCompilation = inputCompilation; OutputCompilation = outputCompilation; _runResult = generatorDriver.GetRunResult().Results[0]; }
public void Test_InterfaceExtensionsGenerator() { // Create the 'input' compilation that the generator will act on Compilation inputCompilation = CreateCompilation(@" using System; namespace MyCode { [UltimateOrb.CodeAnalysis.SourceGenerators.GeneratExtensions] interface IInterfaceA<T> { bool Property1 { get; } internal bool Property2 { set; } public bool Property3 { get; protected set; } static int Method4() { return 123; } public long Method5() { return 123; } void Method6(ref long arg1, in uint? arg2 , in string? arg3, Guid arg4) { return; } protected void Method7(ref ulong arg1, in uint? arg2, in string? arg3, Guid arg4); void Method8(ref nint arg1, in UIntPtr? arg2, in string? arg3, Guid arg4); } } "); // directly create an instance of the generator // (Note: in the compiler this is loaded from an assembly, and created via reflection at runtime) var generator = new InterfaceExtensionsGenerator(); // Create the driver that will control the generation, passing in our generator GeneratorDriver driver = CSharpGeneratorDriver.Create(generator); // Run the generation pass // (Note: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls) driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics); // We can now assert things about the resulting compilation: Debug.Assert(diagnostics.IsEmpty); // there were no diagnostics created by the generators Debug.Assert(outputCompilation.SyntaxTrees.Count() == 2); // we have two syntax trees, the original 'user' provided one, and the one added by the generator System.Collections.Immutable.ImmutableArray <Diagnostic> diagnostics1 = outputCompilation.GetDiagnostics(); Debug.Assert(diagnostics1.IsEmpty); // verify the compilation with the added source has no diagnostics // Or we can look at the results directly: GeneratorDriverRunResult runResult = driver.GetRunResult(); // The runResult contains the combined results of all generators passed to the driver Debug.Assert(runResult.GeneratedTrees.Length == 1); Debug.Assert(runResult.Diagnostics.IsEmpty); // Or you can access the individual results on a by-generator basis GeneratorRunResult generatorResult = runResult.Results[0]; Debug.Assert(generatorResult.Generator == generator); Debug.Assert(generatorResult.Diagnostics.IsEmpty); Debug.Assert(generatorResult.GeneratedSources.Length == 1); Debug.Assert(generatorResult.Exception is null); }