public async Task PropertiesGetterOnlyMixed() { using var tempWorkarea = TemporaryProjectWorkarea.Create(); var contents = @" using System; using System.Collections.Generic; using MessagePack; namespace TempProject { [MessagePackObject(true)] public class MyMessagePackObject { public int A { get; } public string B { get; set; } } } "; tempWorkarea.AddFileToTargetProject("MyMessagePackObject.cs", contents); var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None); await compiler.GenerateFileAsync( tempWorkarea.GetOutputCompilation().Compilation, tempWorkarea.OutputDirectory, "TempProjectResolver", "TempProject.Generated", false, string.Empty, Array.Empty <string>()); var compilation = tempWorkarea.GetOutputCompilation(); compilation.Compilation.GetDiagnostics().Should().NotContain(x => x.Severity == DiagnosticSeverity.Error); // Run tests with the generated resolver/formatter assembly. compilation.ExecuteWithGeneratedAssembly((ctx, assembly) => { var mpoType = assembly.GetType("TempProject.MyMessagePackObject"); var options = MessagePackSerializerOptions.Standard .WithResolver(CompositeResolver.Create( StandardResolver.Instance, TestUtilities.GetResolverInstance(assembly, "TempProject.Generated.Resolvers.TempProjectResolver"))); // Build `{ "A": -1, "B": "foobar" }`. var seq = new Sequence <byte>(); var writer = new MessagePackWriter(seq); writer.WriteMapHeader(2); writer.Write("A"); writer.Write(-1); writer.Write("B"); writer.Write("foobar"); writer.Flush(); // Verify deserialization dynamic result = MessagePackSerializer.Deserialize(mpoType, seq, options); ((int)result.A).Should().Be(0); // default ((string)result.B).Should().Be("foobar"); // from input }); }
public async Task Generics_Constraints_ReferenceType_Nullable(bool isSingleFileOutput) { using var tempWorkarea = TemporaryProjectWorkarea.Create(); var contents = @" using System; using System.Collections.Generic; using MessagePack; namespace TempProject { [MessagePackObject] public class MyGenericObject<T1, T2> where T1 : class? where T2 : class { [Key(0)] public T1 Content1 { get; set; } [Key(1)] public T2 Content2 { get; set; } } } "; tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents); var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None); await compiler.GenerateFileAsync( tempWorkarea.GetOutputCompilation().Compilation, isSingleFileOutput?Path.Combine(tempWorkarea.OutputDirectory, "Generated.cs") : tempWorkarea.OutputDirectory, "TempProjectResolver", "TempProject.Generated", false, string.Empty, Array.Empty <string>()); var compilation = tempWorkarea.GetOutputCompilation(); compilation.Compilation.GetDiagnostics().Where(x => x.WarningLevel == 0).Should().BeEmpty(); var symbols = compilation.GetNamedTypeSymbolsFromGenerated(); var formatterType = symbols.FirstOrDefault(x => x.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) == "global::TempProject.Generated.Formatters.TempProject.MyGenericObjectFormatter<T1, T2>"); formatterType.Should().NotBeNull(); // class? formatterType.TypeParameters[0].HasReferenceTypeConstraint.Should().BeTrue(); formatterType.TypeParameters[0].ConstraintTypes.Should().BeEmpty(); formatterType.TypeParameters[0].ReferenceTypeConstraintNullableAnnotation.Should().Be(NullableAnnotation.Annotated); // class formatterType.TypeParameters[1].HasReferenceTypeConstraint.Should().BeTrue(); formatterType.TypeParameters[1].ConstraintTypes.Should().BeEmpty(); formatterType.TypeParameters[1].ReferenceTypeConstraintNullableAnnotation.Should().Be(NullableAnnotation.None); }
public async Task CanGenerateMessagePackFormatterAttr() { using var tempWorkarea = TemporaryProjectWorkarea.Create(); var contents = @" using System; using System.Collections.Generic; using MessagePack; namespace TempProject { [MessagePackFormatter(typeof(MyFormatter))] public class MyMessagePackObject { public int Foo { get; set; } public class MyFormatter : IMessagePackFormatter<MyMessagePackObject> { public MyMessagePackObject Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { throw new NotImplementedException(); } public void Serialize(ref MessagePackWriter writer, MyMessagePackObject value, MessagePackSerializerOptions options) { throw new NotImplementedException(); } } } [MessagePackObject] public class Bar { [Key(0)] public MyMessagePackObject Baz { get; set; } } } "; tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents); var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None); // can compile(does not throw MessagePackGeneratorResolveFailedException : Serialization Object must mark MessagePackObjectAttribute. type: global::TempProject.MyMessagePackObject) await compiler.GenerateFileAsync( tempWorkarea.CsProjectPath, tempWorkarea.OutputDirectory, string.Empty, "TempProjectResolver", "TempProject.Generated", false, string.Empty); }
public async Task GenericsOfTFormatter_FormatterOnly(bool isSingleFileOutput) { using var tempWorkarea = TemporaryProjectWorkarea.Create(); var contents = @" using System; using System.Collections.Generic; using MessagePack; namespace TempProject { // This type is not used by the project. // It may be referenced by other projects. [MessagePackObject] public class MyGenericObject<T> { [Key(0)] public T Content { get; set; } } } "; tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents); var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None); await compiler.GenerateFileAsync( tempWorkarea.CsProjectPath, isSingleFileOutput?Path.Combine(tempWorkarea.OutputDirectory, "Generated.cs") : tempWorkarea.OutputDirectory, string.Empty, "TempProjectResolver", "TempProject.Generated", false, string.Empty); var compilation = tempWorkarea.GetOutputCompilation(); compilation.Compilation.GetDiagnostics().Where(x => x.WarningLevel == 0).Should().BeEmpty(); var symbols = compilation.GetNamedTypeSymbolsFromGenerated(); var types = symbols.Select(x => x.ToDisplayString()).ToArray(); types.Should().Contain("TempProject.Generated.Formatters.TempProject.MyGenericObjectFormatter<T>"); var formatters = symbols.SelectMany(x => x.Interfaces).Select(x => x.ToDisplayString()).ToArray(); formatters.Should().Contain("MessagePack.Formatters.IMessagePackFormatter<TempProject.MyGenericObject<T>>"); // The generated resolver doesn't know closed-type generic formatter. compilation.GetResolverKnownFormatterTypes().Should().BeEmpty(); }
public async Task NullableFormatter(bool isSingleFileOutput) { using var tempWorkarea = TemporaryProjectWorkarea.Create(false); var contents = @" using System; using System.Collections.Generic; using MessagePack; namespace TempProject { [MessagePackObject] public class MyObject { [Key(0)] public int? ValueNullableInt { get; set; } [Key(1)] public MyEnum? ValueNullableEnum { get; set; } [Key(2)] public ValueTuple<int, long>? ValueNullableStruct { get; set; } } public enum MyEnum { A, B, C } } "; tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents); var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None); await compiler.GenerateFileAsync( tempWorkarea.CsProjectPath, isSingleFileOutput?Path.Combine(tempWorkarea.OutputDirectory, "Generated.cs") : tempWorkarea.OutputDirectory, string.Empty, "TempProjectResolver", "TempProject.Generated", false, string.Empty); var compilation = tempWorkarea.GetOutputCompilation(); compilation.Compilation.GetDiagnostics().Where(x => x.WarningLevel == 0).Should().BeEmpty(); compilation.GetResolverKnownFormatterTypes().Should().Contain(new[] { "global::MessagePack.Formatters.NullableFormatter<(int, long)>", "global::MessagePack.Formatters.NullableFormatter<global::TempProject.MyEnum>", }); }
public async Task GenericsUnionFormatter(bool isSingleFileOutput) { using var tempWorkarea = TemporaryProjectWorkarea.Create(false); var contents = @" using System; using System.Collections.Generic; using MessagePack; namespace TempProject { [MessagePackObject] [Union(0, typeof(Wrapper<string>))] [Union(1, typeof(Wrapper<int[]>))] [Union(2, typeof(Wrapper<IEnumerable<Guid>>))] public class Wrapper<T> { [Key(0)] public T Content { get; set; } } } "; tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents); var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None); await compiler.GenerateFileAsync( tempWorkarea.CsProjectPath, isSingleFileOutput?Path.Combine(tempWorkarea.OutputDirectory, "Generated.cs") : tempWorkarea.OutputDirectory, string.Empty, "TempProjectResolver", "TempProject.Generated", false, string.Empty); var compilation = tempWorkarea.GetOutputCompilation(); compilation.Compilation.GetDiagnostics().Where(x => x.WarningLevel == 0).Should().BeEmpty(); var symbols = compilation.GetNamedTypeSymbolsFromGenerated(); var formatters = symbols.SelectMany(x => x.Interfaces).Select(x => x.ToDisplayString()).ToArray(); formatters.Should().Contain("MessagePack.Formatters.IMessagePackFormatter<TempProject.Wrapper<T>>"); compilation.GetResolverKnownFormatterTypes().Should().Contain(new[] { "TempProject.Generated.Formatters.TempProject.WrapperFormatter<global::System.Collections.Generic.IEnumerable<global::System.Guid>>", "TempProject.Generated.Formatters.TempProject.WrapperFormatter<int[]>", "TempProject.Generated.Formatters.TempProject.WrapperFormatter<string>", }); }
public async Task Generics_Constraints_Type(bool isSingleFileOutput) { using var tempWorkarea = TemporaryProjectWorkarea.Create(); var contents = @" using System; using System.Collections.Generic; using MessagePack; namespace TempProject { [MessagePackObject] public class MyGenericObject<T> where T : IDisposable { [Key(0)] public T Content { get; set; } } } "; tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents); var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None); await compiler.GenerateFileAsync( tempWorkarea.CsProjectPath, isSingleFileOutput?Path.Combine(tempWorkarea.OutputDirectory, "Generated.cs") : tempWorkarea.OutputDirectory, string.Empty, "TempProjectResolver", "TempProject.Generated", false, string.Empty); var compilation = tempWorkarea.GetOutputCompilation(); compilation.Compilation.GetDiagnostics().Where(x => x.WarningLevel == 0).Should().BeEmpty(); var symbols = compilation.GetNamedTypeSymbolsFromGenerated(); var formatterType = symbols.FirstOrDefault(x => x.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) == "global::TempProject.Generated.Formatters.TempProject.MyGenericObjectFormatter<T>"); formatterType.Should().NotBeNull(); // IDisposable formatterType.TypeParameters[0].HasReferenceTypeConstraint.Should().BeFalse(); formatterType.TypeParameters[0].HasValueTypeConstraint.Should().BeFalse(); formatterType.TypeParameters[0].HasConstructorConstraint.Should().BeFalse(); formatterType.TypeParameters[0].HasNotNullConstraint.Should().BeFalse(); formatterType.TypeParameters[0].HasUnmanagedTypeConstraint.Should().BeFalse(); formatterType.TypeParameters[0].ConstraintTypes.Should().Contain(x => x.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) == "global::System.IDisposable"); }
public async Task WellKnownGenericsFormatter(bool isSingleFileOutput) { using var tempWorkarea = TemporaryProjectWorkarea.Create(false); var contents = @" using System; using System.Collections.Generic; using MessagePack; namespace TempProject { [MessagePackObject] public class MyObject { [Key(0)] public List<int> ValueList { get; set; } [Key(1)] public List<List<int>> ValueListNested { get; set; } [Key(2)] public ValueTuple<int, string, long> ValueValueTuple { get; set; } } } "; tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents); var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None); await compiler.GenerateFileAsync( tempWorkarea.GetOutputCompilation().Compilation, isSingleFileOutput?Path.Combine(tempWorkarea.OutputDirectory, "Generated.cs") : tempWorkarea.OutputDirectory, "TempProjectResolver", "TempProject.Generated", false, string.Empty, Array.Empty <string>()); var compilation = tempWorkarea.GetOutputCompilation(); compilation.Compilation.GetDiagnostics().Where(x => x.WarningLevel == 0).Should().BeEmpty(); compilation.GetResolverKnownFormatterTypes().Should().Contain(new[] { "global::MessagePack.Formatters.ListFormatter<int>", "global::MessagePack.Formatters.ListFormatter<global::System.Collections.Generic.List<int>>", "global::MessagePack.Formatters.ValueTupleFormatter<int, string, long>", "TempProject.Generated.Formatters.TempProject.MyObjectFormatter", }); }
public async Task EnumFormatter() { using var tempWorkarea = TemporaryProjectWorkarea.Create(); var contents = @" using System; using System.Collections.Generic; using MessagePack; namespace TempProject { [MessagePackObject] public class MyMessagePackObject { [Key(0)] public MyEnum EnumValue { get; set; } } public enum MyEnum { A, B, C } } "; tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents); var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None); await compiler.GenerateFileAsync( tempWorkarea.CsProjectPath, tempWorkarea.OutputDirectory, string.Empty, "TempProjectResolver", "TempProject.Generated", false, string.Empty); var compilation = tempWorkarea.GetOutputCompilation(); var symbols = compilation.GetNamedTypeSymbolsFromGenerated(); symbols.Should().Contain(x => x.Name == "MyEnumFormatter"); }
public async Task GenericsOfT1T2Formatter(bool isSingleFileOutput) { using var tempWorkarea = TemporaryProjectWorkarea.Create(); var contents = @" using System; using System.Collections.Generic; using MessagePack; namespace TempProject { [MessagePackObject] public class MyGenericObject<T1, T2> { [Key(0)] public T1 ValueA { get; set; } [Key(1)] public T2 ValueB { get; set; } } [MessagePackObject] public class MyObject { [Key(0)] public MyGenericObject<int, string> Value { get; set; } } [MessagePackObject] public class MyObjectNested { [Key(0)] public MyGenericObject<MyGenericObject<int, string>, MyGenericObject<int, string>> Value { get; set; } } } "; tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents); var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None); await compiler.GenerateFileAsync( tempWorkarea.CsProjectPath, isSingleFileOutput?Path.Combine(tempWorkarea.OutputDirectory, "Generated.cs") : tempWorkarea.OutputDirectory, string.Empty, "TempProjectResolver", "TempProject.Generated", false, string.Empty); var compilation = tempWorkarea.GetOutputCompilation(); compilation.Compilation.GetDiagnostics().Where(x => x.WarningLevel == 0).Should().BeEmpty(); var symbols = compilation.GetNamedTypeSymbolsFromGenerated(); var types = symbols.Select(x => x.ToDisplayString()).ToArray(); types.Should().Contain("TempProject.Generated.Formatters.TempProject.MyGenericObjectFormatter<T1, T2>"); var formatters = symbols.SelectMany(x => x.Interfaces).Select(x => x.ToDisplayString()).ToArray(); formatters.Should().Contain("MessagePack.Formatters.IMessagePackFormatter<TempProject.MyGenericObject<T1, T2>>"); compilation.GetResolverKnownFormatterTypes().Should().Contain(new[] { "TempProject.Generated.Formatters.TempProject.MyGenericObjectFormatter<global::TempProject.MyGenericObject<int, string>, global::TempProject.MyGenericObject<int, string>>", "TempProject.Generated.Formatters.TempProject.MyGenericObjectFormatter<int, string>", "TempProject.Generated.Formatters.TempProject.MyObjectFormatter", "TempProject.Generated.Formatters.TempProject.MyObjectNestedFormatter", }); }
public async Task Generics_Constraints_Multiple(bool isSingleFileOutput) { using var tempWorkarea = TemporaryProjectWorkarea.Create(); var contents = @" using System; using System.Collections.Generic; using MessagePack; namespace TempProject { [MessagePackObject] public class MyGenericObject<T1, T2, T3, T4> where T1 : struct where T2 : IDisposable, new() where T3 : notnull where T4 : unmanaged { [Key(0)] public T1 Content1 { get; set; } [Key(1)] public T2 Content2 { get; set; } [Key(2)] public T3 Content3 { get; set; } [Key(3)] public T4 Content4 { get; set; } } } "; tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents); var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None); await compiler.GenerateFileAsync( tempWorkarea.GetOutputCompilation().Compilation, isSingleFileOutput?Path.Combine(tempWorkarea.OutputDirectory, "Generated.cs") : tempWorkarea.OutputDirectory, "TempProjectResolver", "TempProject.Generated", false, string.Empty, Array.Empty <string>()); var compilation = tempWorkarea.GetOutputCompilation(); compilation.Compilation.GetDiagnostics().Where(x => x.WarningLevel == 0).Should().BeEmpty(); var symbols = compilation.GetNamedTypeSymbolsFromGenerated(); var formatterType = symbols.FirstOrDefault(x => x.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) == "global::TempProject.Generated.Formatters.TempProject.MyGenericObjectFormatter<T1, T2, T3, T4>"); formatterType.Should().NotBeNull(); // struct formatterType.TypeParameters[0].HasReferenceTypeConstraint.Should().BeFalse(); formatterType.TypeParameters[0].HasValueTypeConstraint.Should().BeTrue(); formatterType.TypeParameters[0].HasConstructorConstraint.Should().BeFalse(); formatterType.TypeParameters[0].HasNotNullConstraint.Should().BeFalse(); formatterType.TypeParameters[0].HasUnmanagedTypeConstraint.Should().BeFalse(); formatterType.TypeParameters[0].ConstraintTypes.Should().BeEmpty(); // IDisposable, new() formatterType.TypeParameters[1].HasReferenceTypeConstraint.Should().BeFalse(); formatterType.TypeParameters[1].HasValueTypeConstraint.Should().BeFalse(); formatterType.TypeParameters[1].HasConstructorConstraint.Should().BeTrue(); formatterType.TypeParameters[1].HasNotNullConstraint.Should().BeFalse(); formatterType.TypeParameters[1].HasUnmanagedTypeConstraint.Should().BeFalse(); formatterType.TypeParameters[1].ConstraintTypes.Should().Contain(x => x.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) == "global::System.IDisposable"); // notnull formatterType.TypeParameters[2].HasReferenceTypeConstraint.Should().BeFalse(); formatterType.TypeParameters[2].HasValueTypeConstraint.Should().BeFalse(); formatterType.TypeParameters[2].HasConstructorConstraint.Should().BeFalse(); formatterType.TypeParameters[2].HasNotNullConstraint.Should().BeTrue(); formatterType.TypeParameters[2].HasUnmanagedTypeConstraint.Should().BeFalse(); formatterType.TypeParameters[2].ConstraintTypes.Should().BeEmpty(); // unmanaged formatterType.TypeParameters[3].HasReferenceTypeConstraint.Should().BeFalse(); formatterType.TypeParameters[3].HasValueTypeConstraint.Should().BeTrue(); // unmanaged constraint includes value-type constraint formatterType.TypeParameters[3].HasConstructorConstraint.Should().BeFalse(); formatterType.TypeParameters[3].HasNotNullConstraint.Should().BeFalse(); formatterType.TypeParameters[3].HasUnmanagedTypeConstraint.Should().BeTrue(); formatterType.TypeParameters[3].ConstraintTypes.Should().BeEmpty(); }
public async Task Generics_Constraints_NullableReferenceType(bool isSingleFileOutput) { using var tempWorkarea = TemporaryProjectWorkarea.Create(); var contents = @" using System; using System.Collections.Generic; using MessagePack; namespace TempProject { [MessagePackObject] public class MyGenericObject<T1, T2, T3, T4> where T1 : MyClass? where T2 : MyClass where T3 : MyGenericClass<MyGenericClass<MyClass?>?>? where T4 : MyClass, IMyInterface? { [Key(0)] public T1 Content { get; set; } } public class MyClass {} public class MyGenericClass<T> {} public interface IMyInterface {} } "; tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents); var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None); await compiler.GenerateFileAsync( tempWorkarea.GetOutputCompilation().Compilation, isSingleFileOutput?Path.Combine(tempWorkarea.OutputDirectory, "Generated.cs") : tempWorkarea.OutputDirectory, "TempProjectResolver", "TempProject.Generated", false, string.Empty, Array.Empty <string>()); var compilation = tempWorkarea.GetOutputCompilation(); compilation.Compilation.GetDiagnostics().Where(x => x.WarningLevel == 0).Should().BeEmpty(); var symbols = compilation.GetNamedTypeSymbolsFromGenerated(); var displayFormat = SymbolDisplayFormat.FullyQualifiedFormat.WithMiscellaneousOptions(SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier); var formatterType = symbols.FirstOrDefault(x => x.ToDisplayString(displayFormat) == "global::TempProject.Generated.Formatters.TempProject.MyGenericObjectFormatter<T1, T2, T3, T4>"); formatterType.Should().NotBeNull(); // MyClass? formatterType.TypeParameters[0].ConstraintTypes.Should().Contain(x => x.ToDisplayString(displayFormat) == "global::TempProject.MyClass?"); formatterType.TypeParameters[0].ConstraintNullableAnnotations[0].Should().Be(NullableAnnotation.Annotated); // MyClass formatterType.TypeParameters[1].ConstraintTypes.Should().Contain(x => x.ToDisplayString(displayFormat) == "global::TempProject.MyClass"); formatterType.TypeParameters[1].ConstraintNullableAnnotations[0].Should().Be(NullableAnnotation.None); // MyGenericClass<MyGenericClass<MyClass?>?>? formatterType.TypeParameters[2].ConstraintTypes.Should().Contain(x => x.ToDisplayString(displayFormat) == "global::TempProject.MyGenericClass<global::TempProject.MyGenericClass<global::TempProject.MyClass?>?>?"); formatterType.TypeParameters[2].ConstraintNullableAnnotations[0].Should().Be(NullableAnnotation.Annotated); // MyClass, IMyInterface? formatterType.TypeParameters[3].ConstraintTypes.Should().Contain(x => x.ToDisplayString(displayFormat) == "global::TempProject.MyClass"); formatterType.TypeParameters[3].ConstraintTypes.Should().Contain(x => x.ToDisplayString(displayFormat) == "global::TempProject.IMyInterface?"); formatterType.TypeParameters[3].ConstraintNullableAnnotations[0].Should().Be(NullableAnnotation.None); formatterType.TypeParameters[3].ConstraintNullableAnnotations[1].Should().Be(NullableAnnotation.Annotated); }
public async Task GenericsOfTFormatter_WithKnownTypes(bool isSingleFileOutput) { using var tempWorkarea = TemporaryProjectWorkarea.Create(false); var contents = @" using System; using System.Collections.Generic; using MessagePack; namespace TempProject { [MessagePackObject] public class MyObject : MyGenericObject<MyObject2> { } [MessagePackObject] public class MyObject2 { } [MessagePackObject] public class MyGenericObject<T> { [Key(0)] public List<T> Content1 { get; set; } [Key(1)] public T[] Content2 { get; set; } } } "; tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents); var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None); await compiler.GenerateFileAsync( tempWorkarea.GetOutputCompilation().Compilation, isSingleFileOutput?Path.Combine(tempWorkarea.OutputDirectory, "Generated.cs") : tempWorkarea.OutputDirectory, "TempProjectResolver", "TempProject.Generated", false, string.Empty, Array.Empty <string>()); var compilation = tempWorkarea.GetOutputCompilation(); compilation.Compilation.GetDiagnostics().Where(x => x.WarningLevel == 0).Should().BeEmpty(); var symbols = compilation.GetNamedTypeSymbolsFromGenerated(); var formatters = symbols.SelectMany(x => x.Interfaces).Select(x => x.ToDisplayString()).ToArray(); formatters.Should().Contain(new[] { "MessagePack.Formatters.IMessagePackFormatter<TempProject.MyObject>", "MessagePack.Formatters.IMessagePackFormatter<TempProject.MyObject2>", "MessagePack.Formatters.IMessagePackFormatter<TempProject.MyGenericObject<T>>", }); compilation.GetResolverKnownFormatterTypes().Should().Contain(new[] { "global::MessagePack.Formatters.ListFormatter<global::TempProject.MyObject2>", "global::MessagePack.Formatters.ArrayFormatter<global::TempProject.MyObject2>", // "TempProject.Generated.Formatters.TempProject.MyGenericObjectFormatter<string>", // MyGenericObjectFormatter<T> is not used as a property/field in the code. The generated resolver can ignore it. "TempProject.Generated.Formatters.TempProject.MyObjectFormatter", "TempProject.Generated.Formatters.TempProject.MyObject2Formatter", }); }