public static void LocalJsonSerializableAttributeUnexpectedShape(string assemblyName, bool includeSTJ) { string source = @"using System; using System.Text.Json.Serialization; [assembly: JsonSerializable(typeof(int))] namespace System.Text.Json.Serialization { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public sealed class JsonSerializableAttribute : JsonAttribute { public JsonSerializableAttribute(string typeInfoPropertyName, Type type) { } } }"; Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences: null, assemblyName, includeSTJ); JsonSourceGenerator generator = new JsonSourceGenerator(); CompilationHelper.RunGenerators(compilation, out ImmutableArray <Diagnostic> generatorDiags, generator); Assert.Null(generator.GetSerializableTypes()); CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Info, Array.Empty <string>()); CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, Array.Empty <string>()); CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Error, Array.Empty <string>()); }
public void Record() { // Compile the referenced assembly first. Compilation referencedCompilation = CompilationHelper.CreateReferencedLibRecordCompilation(); // Emit the image of the referenced assembly. byte[] referencedImage = CompilationHelper.CreateAssemblyImage(referencedCompilation); string source = @" using System.Text.Json.Serialization; namespace HelloWorld { [JsonSerializable(typeof(AppRecord))] internal partial class JsonContext : JsonSerializerContext { } public record AppRecord(int Id) { public string Address1 { get; set; } public string Address2 { get; set; } public string City { get; set; } public string State { get; set; } public string PostalCode { get; set; } public string Name { get; set; } [JsonInclude] public string PhoneNumber; [JsonInclude] public string Country; } }"; MetadataReference[] additionalReferences = { MetadataReference.CreateFromImage(referencedImage) }; Compilation compilation = CompilationHelper.CreateCompilation(source); JsonSourceGenerator generator = new JsonSourceGenerator(); Compilation newCompilation = CompilationHelper.RunGenerators(compilation, out ImmutableArray <Diagnostic> generatorDiags, generator); // Make sure compilation was successful. CheckCompilationDiagnosticsErrors(generatorDiags); CheckCompilationDiagnosticsErrors(newCompilation.GetDiagnostics()); Dictionary <string, Type> types = generator.GetSerializableTypes(); // Check base functionality of found types. Assert.Equal(1, types.Count); Type recordType = types["HelloWorld.AppRecord"]; Assert.Equal("HelloWorld.AppRecord", recordType.FullName); // Check for received fields, properties and methods for NotMyType. string[] expectedFieldsNames = { "Country", "PhoneNumber" }; string[] expectedPropertyNames = { "Address1", "Address2", "City", "Id", "Name", "PostalCode", "State" }; CheckFieldsPropertiesMethods(recordType, expectedFieldsNames, expectedPropertyNames); Assert.Equal(1, recordType.GetConstructors().Length); }
public void MetadataLoadFilePathHandle() { // Create a MetadataReference from new code. string referencedSource = @" namespace ReferencedAssembly { public class ReferencedType { public int ReferencedPublicInt; public double ReferencedPublicDouble; } }"; // Compile the referenced assembly first. Compilation referencedCompilation = CompilationHelper.CreateCompilation(referencedSource); // Emit the image of the referenced assembly. byte[] referencedImage; using (MemoryStream ms = new MemoryStream()) { var emitResult = referencedCompilation.Emit(ms); if (!emitResult.Success) { throw new InvalidOperationException(); } referencedImage = ms.ToArray(); } string source = @" using System.Text.Json.Serialization; using ReferencedAssembly; [assembly: JsonSerializable(typeof(HelloWorld.MyType))] [assembly: JsonSerializable(typeof(ReferencedAssembly.ReferencedType))] namespace HelloWorld { public class MyType { public void MyMethod() { } public void MySecondMethod() { } } }"; MetadataReference[] additionalReferences = { MetadataReference.CreateFromImage(referencedImage) }; // Compilation using the referenced image should fail if out MetadataLoadContext does not handle. Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences); JsonSourceGenerator generator = new JsonSourceGenerator(); Compilation newCompilation = CompilationHelper.RunGenerators(compilation, out ImmutableArray <Diagnostic> generatorDiags, generator); // Make sure compilation was successful. Assert.Empty(generatorDiags.Where(diag => diag.Severity.Equals(DiagnosticSeverity.Error))); Assert.Empty(newCompilation.GetDiagnostics().Where(diag => diag.Severity.Equals(DiagnosticSeverity.Error))); // Should find both types since compilation above was successful. Assert.Equal(2, generator.GetSerializableTypes().Count); }
public void ContextTypeNotInNamespace() { string source = @" using System.Text.Json.Serialization; [JsonSerializable(typeof(MyType))] internal partial class JsonContext : JsonSerializerContext { } public class MyType { public int PublicPropertyInt { get; set; } public string PublicPropertyString { get; set; } private int PrivatePropertyInt { get; set; } private string PrivatePropertyString { get; set; } public double PublicDouble; public char PublicChar; private double PrivateDouble; private char PrivateChar; public void MyMethod() { } public void MySecondMethod() { } public void UsePrivates() { PrivateDouble = 0; PrivateChar = ' '; double d = PrivateDouble; char c = PrivateChar; } }"; Compilation compilation = CompilationHelper.CreateCompilation(source); JsonSourceGenerator generator = new JsonSourceGenerator(); Compilation newCompilation = CompilationHelper.RunGenerators(compilation, out ImmutableArray <Diagnostic> generatorDiags, generator); // Make sure compilation was successful. CheckCompilationDiagnosticsErrors(generatorDiags); CheckCompilationDiagnosticsErrors(newCompilation.GetDiagnostics()); Dictionary <string, Type> types = generator.GetSerializableTypes(); // Check base functionality of found types. Assert.Equal(1, types.Count); Type myType = types["MyType"]; Assert.Equal("MyType", myType.FullName); // Check for received fields, properties and methods in created type. string[] expectedPropertyNames = { "PublicPropertyInt", "PublicPropertyString", }; string[] expectedFieldNames = { "PublicChar", "PublicDouble" }; string[] expectedMethodNames = { "get_PrivatePropertyInt", "get_PrivatePropertyString", "get_PublicPropertyInt", "get_PublicPropertyString", "MyMethod", "MySecondMethod", "set_PrivatePropertyInt", "set_PrivatePropertyString", "set_PublicPropertyInt", "set_PublicPropertyString", "UsePrivates" }; CheckFieldsPropertiesMethods(myType, expectedFieldNames, expectedPropertyNames, expectedMethodNames); }
public void TestMultipleDefinitions() { // Adding a dependency to an assembly that has internal definitions of public types // should not result in a collision and break generation. // Verify usage of the extension GetBestTypeByMetadataName(this Compilation) instead of Compilation.GetTypeByMetadataName(). var referencedSource = @" namespace System.Text.Json.Serialization { internal class JsonSerializerContext { } internal class JsonSerializableAttribute { } internal class JsonSourceGenerationOptionsAttribute { } }"; // Compile the referenced assembly first. Compilation referencedCompilation = CompilationHelper.CreateCompilation(referencedSource); // Obtain the image of the referenced assembly. byte[] referencedImage = CompilationHelper.CreateAssemblyImage(referencedCompilation); // Generate the code string source = @" using System.Text.Json.Serialization; namespace HelloWorld { [JsonSerializable(typeof(HelloWorld.MyType))] internal partial class JsonContext : JsonSerializerContext { } public class MyType { public int MyInt { get; set; } } }"; MetadataReference[] additionalReferences = { MetadataReference.CreateFromImage(referencedImage) }; Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences); JsonSourceGenerator generator = new JsonSourceGenerator(); Compilation newCompilation = CompilationHelper.RunGenerators( compilation, out ImmutableArray <Diagnostic> generatorDiags, generator); // Make sure compilation was successful. Assert.Empty(generatorDiags.Where(diag => diag.Severity.Equals(DiagnosticSeverity.Error))); Assert.Empty(newCompilation.GetDiagnostics().Where(diag => diag.Severity.Equals(DiagnosticSeverity.Error))); // Should find the generated type. Dictionary <string, Type> types = generator.GetSerializableTypes(); Assert.Equal(1, types.Count); Assert.Equal("HelloWorld.MyType", types.Keys.First()); }
public void RecordDerivedFromRecordInExternalAssembly() { // Compile the referenced assembly first. Compilation referencedCompilation = CompilationHelper.CreateReferencedSimpleLibRecordCompilation(); // Emit the image of the referenced assembly. byte[] referencedImage = CompilationHelper.CreateAssemblyImage(referencedCompilation); string source = @" using System.Text.Json.Serialization; using ReferencedAssembly; namespace HelloWorld { [JsonSerializable(typeof(AppRecord))] internal partial class JsonContext : JsonSerializerContext { } internal record AppRecord : LibRecord { public string ExtraData { get; set; } } }"; MetadataReference[] additionalReferences = { MetadataReference.CreateFromImage(referencedImage) }; Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences); JsonSourceGenerator generator = new JsonSourceGenerator(); Compilation newCompilation = CompilationHelper.RunGenerators(compilation, out ImmutableArray <Diagnostic> generatorDiags, generator); // Make sure compilation was successful. CheckCompilationDiagnosticsErrors(generatorDiags); CheckCompilationDiagnosticsErrors(newCompilation.GetDiagnostics()); Dictionary <string, Type> types = generator.GetSerializableTypes(); Assert.Equal(1, types.Count); Type recordType = types["HelloWorld.AppRecord"]; Assert.Equal("HelloWorld.AppRecord", recordType.FullName); string[] expectedFieldsNames = { "Country", "PhoneNumber" }; string[] expectedPropertyNames = { "Address1", "Address2", "City", "ExtraData", "Id", "Name", "PostalCode", "State" }; CheckFieldsPropertiesMethods(recordType, expectedFieldsNames, expectedPropertyNames, inspectBaseTypes: true); Assert.Equal(1, recordType.GetConstructors().Length); }
public static void LocalJsonSerializableAttributeExpectedShape(string assemblyName, bool includeSTJ) { string source = @"using System; using System.Text.Json.Serialization; namespace System.Text.Json.Serialization { [JsonSerializable(typeof(int))] [JsonSerializable(typeof(string), TypeInfoPropertyName = ""Str"")] internal partial class JsonContext : JsonSerializerContext { } [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public sealed class JsonSerializableAttribute : JsonAttribute { public string TypeInfoPropertyName { get; set; } public JsonSerializableAttribute(Type type) { } } }"; Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences: null, assemblyName, includeSTJ); JsonSourceGenerator generator = new JsonSourceGenerator(); CompilationHelper.RunGenerators(compilation, out ImmutableArray <Diagnostic> generatorDiags, generator); Dictionary <string, Type> types = generator.GetSerializableTypes(); if (includeSTJ) { Assert.Equal("System.Int32", types["System.Int32"].FullName); Assert.Equal("System.String", types["System.String"].FullName); } else { Assert.Null(types); } CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Info, Array.Empty <string>()); CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, Array.Empty <string>()); CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Error, Array.Empty <string>()); }
public void TypeDiscoveryPrimitiveExternalPOCO() { // Compile the referenced assembly first. Compilation referencedCompilation = CompilationHelper.CreateReferencedLocationCompilation(); // Emit the image of the referenced assembly. byte[] referencedImage = CompilationHelper.CreateAssemblyImage(referencedCompilation); string source = @" using System.Text.Json.Serialization; using ReferencedAssembly; namespace HelloWorld { [JsonSerializable(typeof(HelloWorld.MyType))] [JsonSerializable(typeof(ReferencedAssembly.Location))] internal partial class JsonContext : JsonSerializerContext { } public class MyType { public int PublicPropertyInt { get; set; } public string PublicPropertyString { get; set; } private int PrivatePropertyInt { get; set; } private string PrivatePropertyString { get; set; } public double PublicDouble; public char PublicChar; private double PrivateDouble; private char PrivateChar; public void MyMethod() { } public void MySecondMethod() { } public void UsePrivates() { PrivateDouble = 0; PrivateChar = ' '; double x = PrivateDouble; string s = PrivateChar.ToString(); } } }"; MetadataReference[] additionalReferences = { MetadataReference.CreateFromImage(referencedImage) }; Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences); JsonSourceGenerator generator = new JsonSourceGenerator(); Compilation newCompilation = CompilationHelper.RunGenerators(compilation, out ImmutableArray <Diagnostic> generatorDiags, generator); // Make sure compilation was successful. CheckCompilationDiagnosticsErrors(generatorDiags); CheckCompilationDiagnosticsErrors(newCompilation.GetDiagnostics()); Dictionary <string, Type> types = generator.GetSerializableTypes(); // Check base functionality of found types. Assert.Equal(2, types.Count); Type myType = types["HelloWorld.MyType"]; Type notMyType = types["ReferencedAssembly.Location"]; // Check for MyType. Assert.Equal("HelloWorld.MyType", myType.FullName); // Check for received fields, properties and methods for MyType. string[] expectedFieldNamesMyType = { "PublicChar", "PublicDouble" }; string[] expectedPropertyNamesMyType = { "PublicPropertyInt", "PublicPropertyString" }; string[] expectedMethodNamesMyType = { "get_PrivatePropertyInt", "get_PrivatePropertyString", "get_PublicPropertyInt", "get_PublicPropertyString", "MyMethod", "MySecondMethod", "set_PrivatePropertyInt", "set_PrivatePropertyString", "set_PublicPropertyInt", "set_PublicPropertyString", "UsePrivates" }; CheckFieldsPropertiesMethods(myType, expectedFieldNamesMyType, expectedPropertyNamesMyType, expectedMethodNamesMyType); // Check for NotMyType. Assert.Equal("ReferencedAssembly.Location", notMyType.FullName); // Check for received fields, properties and methods for NotMyType. string[] expectedFieldNamesNotMyType = { }; string[] expectedPropertyNamesNotMyType = { "Address1", "Address2", "City", "Country", "Id", "Name", "PhoneNumber", "PostalCode", "State" }; string[] expectedMethodNamesNotMyType = { "get_Address1", "get_Address2", "get_City", "get_Country", "get_Id", "get_Name", "get_PhoneNumber", "get_PostalCode", "get_State", "set_Address1", "set_Address2", "set_City", "set_Country", "set_Id", "set_Name", "set_PhoneNumber", "set_PostalCode", "set_State" }; CheckFieldsPropertiesMethods(notMyType, expectedFieldNamesNotMyType, expectedPropertyNamesNotMyType, expectedMethodNamesNotMyType); }
public void CanGetAttributes() { string source = @" using System; using System.Text.Json.Serialization; namespace HelloWorld { [JsonSerializable(typeof(HelloWorld.MyType))] internal partial class JsonContext : JsonSerializerContext { } public class MyType { [JsonInclude] public double PublicDouble; [JsonPropertyName(""PPublicDouble"")] public char PublicChar; [JsonIgnore] private double PrivateDouble; private char PrivateChar; public MyType() {{ }} [JsonConstructor] public MyType(double d) {{ PrivateDouble = d; }} [JsonPropertyName(""TestName"")] public int PublicPropertyInt { get; set; } [JsonExtensionData] public string PublicPropertyString { get; set; } [JsonIgnore] private int PrivatePropertyInt { get; set; } private string PrivatePropertyString { get; set; } [Obsolete(""Testing"", true)] public void MyMethod() { } public void MySecondMethod() { } } }"; Compilation compilation = CompilationHelper.CreateCompilation(source); JsonSourceGenerator generator = new JsonSourceGenerator(); Compilation outCompilation = CompilationHelper.RunGenerators(compilation, out ImmutableArray <Diagnostic> generatorDiags, generator); // Check base functionality of found types. Dictionary <string, Type> types = generator.GetSerializableTypes(); Assert.Equal(1, types.Count); Type foundType = types.First().Value; Assert.Equal("HelloWorld.MyType", foundType.FullName); // Check for ConstructorInfoWrapper attribute usage. (string, string[])[] receivedCtorsWithAttributeNames = foundType.GetConstructors().Select(ctor => (ctor.DeclaringType.FullName, ctor.GetCustomAttributesData().Cast <CustomAttributeData>().Select(attributeData => attributeData.AttributeType.Name).ToArray())).ToArray();