|
2 | 2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | 3 | // See the LICENSE file in the project root for more information. |
4 | 4 |
|
| 5 | +using System.Collections.Generic; |
| 6 | +using System.Collections.Immutable; |
| 7 | +using System.Linq; |
| 8 | +using System.Reflection; |
| 9 | +using System.Text.Json.Serialization; |
5 | 10 | using Microsoft.CodeAnalysis; |
6 | | -using Microsoft.CodeAnalysis.Diagnostics; |
| 11 | +using Microsoft.CodeAnalysis.CSharp; |
7 | 12 | using Xunit; |
8 | 13 |
|
9 | 14 | namespace System.Text.Json.SourceGeneration.UnitTests |
10 | 15 | { |
11 | | - public static class GeneratorTests |
| 16 | + public class GeneratorTests |
12 | 17 | { |
13 | 18 | [Fact] |
14 | | - public static void SourceGeneratorInitializationPass() |
| 19 | + public void TypeDiscoveryPrimitivePOCO() |
15 | 20 | { |
| 21 | + string source = @" |
| 22 | + using System; |
| 23 | + using System.Text.Json.Serialization; |
| 24 | +
|
| 25 | + namespace HelloWorld |
| 26 | + { |
| 27 | + [JsonSerializable] |
| 28 | + public class MyType { |
| 29 | + public int PublicPropertyInt { get; set; } |
| 30 | + public string PublicPropertyString { get; set; } |
| 31 | + private int PrivatePropertyInt { get; set; } |
| 32 | + private string PrivatePropertyString { get; set; } |
| 33 | +
|
| 34 | + public double PublicDouble; |
| 35 | + public char PublicChar; |
| 36 | + private double PrivateDouble; |
| 37 | + private char PrivateChar; |
| 38 | +
|
| 39 | + public void MyMethod() { } |
| 40 | + public void MySecondMethod() { } |
| 41 | + } |
| 42 | + }"; |
| 43 | + |
| 44 | + Compilation compilation = CreateCompilation(source); |
| 45 | + |
| 46 | + JsonSerializerSourceGenerator generator = new JsonSerializerSourceGenerator(); |
| 47 | + |
| 48 | + Compilation outCompilation = RunGenerators(compilation, out var generatorDiags, generator); |
| 49 | + |
| 50 | + // Check base functionality of found types. |
| 51 | + Assert.Equal(1, generator.foundTypes.Count); |
| 52 | + Assert.Equal("HelloWorld.MyType", generator.foundTypes["MyType"].FullName); |
| 53 | + |
| 54 | + // Check for received properties in created type. |
| 55 | + string[] expectedPropertyNames = { "PublicPropertyInt", "PublicPropertyString", "PrivatePropertyInt", "PrivatePropertyString" }; |
| 56 | + string[] receivedPropertyNames = generator.foundTypes["MyType"].GetProperties().Select(property => property.Name).ToArray(); |
| 57 | + Assert.Equal(expectedPropertyNames, receivedPropertyNames); |
| 58 | + |
| 59 | + // Check for fields in created type. |
| 60 | + string[] expectedFieldNames = { "PublicDouble", "PublicChar", "PrivateDouble", "PrivateChar" }; |
| 61 | + string[] receivedFieldNames = generator.foundTypes["MyType"].GetFields().Select(field => field.Name).ToArray(); |
| 62 | + Assert.Equal(expectedFieldNames, receivedFieldNames); |
| 63 | + |
| 64 | + // Check for methods in created type. |
| 65 | + string[] expectedMethodNames = { "get_PublicPropertyInt", "set_PublicPropertyInt", "get_PublicPropertyString", "set_PublicPropertyString", "get_PrivatePropertyInt", "set_PrivatePropertyInt", "get_PrivatePropertyString", "set_PrivatePropertyString", "MyMethod", "MySecondMethod" }; |
| 66 | + string[] receivedMethodNames = generator.foundTypes["MyType"].GetMethods().Select(method => method.Name).ToArray(); |
| 67 | + Assert.Equal(expectedMethodNames, receivedMethodNames); |
16 | 68 | } |
17 | 69 |
|
18 | 70 | [Fact] |
19 | | - public static void SourceGeneratorInitializationFail() |
| 71 | + public void TypeDiscoveryPrimitiveTemporaryPOCO() |
20 | 72 | { |
| 73 | + string source = @" |
| 74 | + using System; |
| 75 | + using System.Text.Json.Serialization; |
| 76 | +
|
| 77 | + namespace HelloWorld |
| 78 | + { |
| 79 | + [JsonSerializable] |
| 80 | + public class MyType { |
| 81 | + public int PublicPropertyInt { get; set; } |
| 82 | + public string PublicPropertyString { get; set; } |
| 83 | + private int PrivatePropertyInt { get; set; } |
| 84 | + private string PrivatePropertyString { get; set; } |
| 85 | +
|
| 86 | + public double PublicDouble; |
| 87 | + public char PublicChar; |
| 88 | + private double PrivateDouble; |
| 89 | + private char PrivateChar; |
| 90 | +
|
| 91 | + public void MyMethod() { } |
| 92 | + public void MySecondMethod() { } |
| 93 | + } |
| 94 | +
|
| 95 | + [JsonSerializable(typeof(JsonConverterAttribute))] |
| 96 | + public class NotMyType { } |
| 97 | +
|
| 98 | + }"; |
| 99 | + |
| 100 | + Compilation compilation = CreateCompilation(source); |
| 101 | + |
| 102 | + JsonSerializerSourceGenerator generator = new JsonSerializerSourceGenerator(); |
| 103 | + |
| 104 | + Compilation outCompilation = RunGenerators(compilation, out var generatorDiags, generator); |
| 105 | + |
| 106 | + // Check base functionality of found types. |
| 107 | + Assert.Equal(2, generator.foundTypes.Count); |
| 108 | + |
| 109 | + // Check for MyType. |
| 110 | + Assert.Equal("HelloWorld.MyType", generator.foundTypes["MyType"].FullName); |
| 111 | + |
| 112 | + // Check for received properties in created type. |
| 113 | + string[] expectedPropertyNamesMyType = { "PublicPropertyInt", "PublicPropertyString", "PrivatePropertyInt", "PrivatePropertyString" }; |
| 114 | + string[] receivedPropertyNamesMyType = generator.foundTypes["MyType"].GetProperties().Select(property => property.Name).ToArray(); |
| 115 | + Assert.Equal(expectedPropertyNamesMyType, receivedPropertyNamesMyType); |
| 116 | + |
| 117 | + // Check for fields in created type. |
| 118 | + string[] expectedFieldNamesMyType = { "PublicDouble", "PublicChar", "PrivateDouble", "PrivateChar" }; |
| 119 | + string[] receivedFieldNamesMyType = generator.foundTypes["MyType"].GetFields().Select(field => field.Name).ToArray(); |
| 120 | + Assert.Equal(expectedFieldNamesMyType, receivedFieldNamesMyType); |
| 121 | + |
| 122 | + // Check for methods in created type. |
| 123 | + string[] expectedMethodNamesMyType = { "get_PublicPropertyInt", "set_PublicPropertyInt", "get_PublicPropertyString", "set_PublicPropertyString", "get_PrivatePropertyInt", "set_PrivatePropertyInt", "get_PrivatePropertyString", "set_PrivatePropertyString", "MyMethod", "MySecondMethod" }; |
| 124 | + string[] receivedMethodNamesMyType = generator.foundTypes["MyType"].GetMethods().Select(method => method.Name).ToArray(); |
| 125 | + Assert.Equal(expectedMethodNamesMyType, receivedMethodNamesMyType); |
| 126 | + |
| 127 | + // Check for NotMyType. |
| 128 | + Assert.Equal("System.Text.Json.Serialization.JsonConverterAttribute", generator.foundTypes["NotMyType"].FullName); |
| 129 | + |
| 130 | + // Check for received properties in created type. |
| 131 | + string[] expectedPropertyNamesNotMyType = { "ConverterType" }; |
| 132 | + string[] receivedPropertyNamesNotMyType = generator.foundTypes["NotMyType"].GetProperties().Select(property => property.Name).ToArray(); |
| 133 | + Assert.Equal(expectedPropertyNamesNotMyType, receivedPropertyNamesNotMyType); |
| 134 | + |
| 135 | + // Check for fields in created type. |
| 136 | + string[] expectedFieldNamesNotMyType = { }; |
| 137 | + string[] receivedFieldNamesNotMyType = generator.foundTypes["NotMyType"].GetFields().Select(field => field.Name).ToArray(); |
| 138 | + Assert.Equal(expectedFieldNamesNotMyType, receivedFieldNamesNotMyType); |
| 139 | + |
| 140 | + // Check for methods in created type. |
| 141 | + string[] expectedMethodNamesNotMyType = { "get_ConverterType", "CreateConverter" }; |
| 142 | + string[] receivedMethodNamesNotMyType = generator.foundTypes["NotMyType"].GetMethods().Select(method => method.Name).ToArray(); |
| 143 | + Assert.Equal(expectedMethodNamesNotMyType, receivedMethodNamesNotMyType); |
21 | 144 | } |
22 | 145 |
|
23 | | - [Fact] |
24 | | - public static void SourceGeneratorExecutionPass() |
| 146 | + private Compilation CreateCompilation(string source) |
25 | 147 | { |
| 148 | + // Bypass System.Runtime error. |
| 149 | + Assembly systemRuntimeAssembly = Assembly.Load("System.Runtime, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); |
| 150 | + string systemRuntimeAssemblyPath = systemRuntimeAssembly.Location; |
| 151 | + |
| 152 | + MetadataReference[] references = new MetadataReference[] { |
| 153 | + MetadataReference.CreateFromFile(typeof(object).Assembly.Location), |
| 154 | + MetadataReference.CreateFromFile(typeof(Attribute).Assembly.Location), |
| 155 | + MetadataReference.CreateFromFile(typeof(JsonSerializableAttribute).Assembly.Location), |
| 156 | + MetadataReference.CreateFromFile(typeof(JsonSerializerOptions).Assembly.Location), |
| 157 | + MetadataReference.CreateFromFile(typeof(Type).Assembly.Location), |
| 158 | + MetadataReference.CreateFromFile(typeof(KeyValuePair).Assembly.Location), |
| 159 | + MetadataReference.CreateFromFile(systemRuntimeAssemblyPath), |
| 160 | + }; |
| 161 | + |
| 162 | + return CSharpCompilation.Create( |
| 163 | + "TestAssembly", |
| 164 | + syntaxTrees: new[] { CSharpSyntaxTree.ParseText(source) }, |
| 165 | + references: references, |
| 166 | + options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) |
| 167 | + ); |
26 | 168 | } |
27 | 169 |
|
28 | | - [Fact] |
29 | | - public static void SourceGeneratorExecutionFail() |
| 170 | + private GeneratorDriver CreateDriver(Compilation compilation, params ISourceGenerator[] generators) |
| 171 | + => new CSharpGeneratorDriver( |
| 172 | + new CSharpParseOptions(kind: SourceCodeKind.Regular, documentationMode: DocumentationMode.Parse), |
| 173 | + ImmutableArray.Create(generators), |
| 174 | + ImmutableArray<AdditionalText>.Empty); |
| 175 | + |
| 176 | + private Compilation RunGenerators(Compilation compilation, out ImmutableArray<Diagnostic> diagnostics, params ISourceGenerator[] generators) |
30 | 177 | { |
| 178 | + CreateDriver(compilation, generators).RunFullGeneration(compilation, out Compilation outCompilation, out diagnostics); |
| 179 | + return outCompilation; |
31 | 180 | } |
32 | 181 | } |
33 | 182 | } |
0 commit comments