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>());
        }
Exemple #2
0
        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);
        }
Exemple #3
0
        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);
        }
Exemple #4
0
        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);
        }
Exemple #5
0
        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());
        }
Exemple #6
0
        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);
        }
Exemple #9
0
        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();