diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index e66973dd..582f454c 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -11,17 +11,16 @@ permissions: jobs: build-and-test: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest] - dotnet-version: [ '9.0.x' ] + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Setup .NET ${{ matrix.dotnet-version }} + - name: Setup .NET uses: actions/setup-dotnet@v4 with: - dotnet-version: ${{ matrix.dotnet-version }} + dotnet-version: | + 6.0.x + 8.0.x + 9.0.x - name: Restore dependencies run: dotnet restore - name: Build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 34d024c9..0f82a82f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -52,19 +52,18 @@ jobs: echo "Version tag '${{ steps.get_version.outputs.version }}' does not exist. Proceeding with release process." build-and-test: - runs-on: ${{ matrix.os }} + runs-on: ubuntu-latest needs: check-version-tag if: needs.check-version-tag.outputs.is_new_version == 'true' - strategy: - matrix: - os: [ubuntu-latest] - dotnet-version: [ '9.0.x' ] steps: - uses: actions/checkout@v4 - - name: Setup .NET ${{ matrix.dotnet-version }} + - name: Setup .NET uses: actions/setup-dotnet@v4 with: - dotnet-version: ${{ matrix.dotnet-version }} + dotnet-version: | + 6.0.x + 8.0.x + 9.0.x - name: Restore dependencies run: dotnet restore @@ -158,7 +157,10 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v4 with: - dotnet-version: '9.0.x' + dotnet-version: | + 6.0.x + 8.0.x + 9.0.x - name: Restore dependencies run: dotnet restore diff --git a/ReflectorNet.Tests.OuterAssembly/ReflectorNet.Tests.OuterAssembly.csproj b/ReflectorNet.Tests.OuterAssembly/ReflectorNet.Tests.OuterAssembly.csproj index f094f2f3..d533417b 100644 --- a/ReflectorNet.Tests.OuterAssembly/ReflectorNet.Tests.OuterAssembly.csproj +++ b/ReflectorNet.Tests.OuterAssembly/ReflectorNet.Tests.OuterAssembly.csproj @@ -1,13 +1,17 @@ - net8.0;net9.0 + net6.0;net8.0;net9.0 disable enable false - + + + + + diff --git a/ReflectorNet.Tests/ReflectorNet.Tests.csproj b/ReflectorNet.Tests/ReflectorNet.Tests.csproj index fd0fb898..3274cd2d 100644 --- a/ReflectorNet.Tests/ReflectorNet.Tests.csproj +++ b/ReflectorNet.Tests/ReflectorNet.Tests.csproj @@ -1,14 +1,24 @@  - net8.0;net9.0 + net6.0;net8.0;net9.0 11.0 disable enable false - + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + diff --git a/ReflectorNet.Tests/SchemaTests/CollectionsTests.cs b/ReflectorNet.Tests/SchemaTests/CollectionsTests.cs index 30868c5b..b0c2dd4c 100644 --- a/ReflectorNet.Tests/SchemaTests/CollectionsTests.cs +++ b/ReflectorNet.Tests/SchemaTests/CollectionsTests.cs @@ -57,8 +57,13 @@ public void GetTypeId_SimpleArray_ShouldAppendArray() foreach (var type in _collectionTypes) { var result = reflector.GetSchema(type); + var options = new JsonSerializerOptions + { + TypeInfoResolver = new System.Text.Json.Serialization.Metadata.DefaultJsonTypeInfoResolver(), + WriteIndented = true + }; - _output.WriteLine($"Type: {type.GetTypeShortName()}\n{result.ToJsonString(new JsonSerializerOptions { WriteIndented = true })}\n"); + _output.WriteLine($"Type: {type.GetTypeShortName()}\n{result.ToJsonString(options)}\n"); // Assert Assert.NotNull(result); diff --git a/ReflectorNet.Tests/SchemaTests/ReturnSchemaTests.cs b/ReflectorNet.Tests/SchemaTests/ReturnSchemaTests.cs index e7de08dd..8b9aaacb 100644 --- a/ReflectorNet.Tests/SchemaTests/ReturnSchemaTests.cs +++ b/ReflectorNet.Tests/SchemaTests/ReturnSchemaTests.cs @@ -14,6 +14,10 @@ namespace com.IvanMurzak.ReflectorNet.Tests.SchemaTests /// public class ReturnSchemaTests : SchemaTestBase { + // Method name constants for WrapperClass to avoid hardcoded strings + private const string EchoMethodName = "Echo"; + private const string EchoNullableMethodName = "EchoNullable"; + public ReturnSchemaTests(ITestOutputHelper output) : base(output) { } #region Test Helper Methods @@ -138,6 +142,57 @@ public class ComplexReturnType #endregion + #region Helper Methods for Testing + + /// + /// Tests that a method returns a complex object schema with expected type definitions + /// + private void TestComplexObjectSchema(string methodName, bool shouldBeRequired, params Type[] expectedDefinedTypes) + { + var schema = GetReturnSchemaForMethod(methodName); + Assert.NotNull(schema); + Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); + + if (shouldBeRequired) + AssertResultRequired(schema); + else + AssertResultNotRequired(schema); + + if (expectedDefinedTypes.Length > 0) + AssertResultDefines(schema, expectedDefinedTypes); + + AssertAllRefsDefined(schema); + } + + /// + /// Tests wrapper class methods with complex types + /// + private void TestWrapperComplexObjectSchema(Type wrapperType, string methodName, bool shouldBeRequired, params Type[] expectedDefinedTypes) + { + var reflector = new Reflector(); + var methodInfo = wrapperType.GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance)!; + var schema = reflector.GetReturnSchema(methodInfo); + + _output.WriteLine($"Return schema for {wrapperType.GetTypeShortName()}.{methodName}:"); + _output.WriteLine(schema?.ToString() ?? "null"); + _output.WriteLine(""); + + Assert.NotNull(schema); + Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); + + if (shouldBeRequired) + AssertResultRequired(schema); + else + AssertResultNotRequired(schema); + + if (expectedDefinedTypes.Length > 0) + AssertResultDefines(schema, expectedDefinedTypes); + + AssertAllRefsDefined(schema); + } + + #endregion + #region Void Return Type Tests [Theory] @@ -206,37 +261,13 @@ public void GetReturnSchema_TaskCustomType_UnwrapsToCustomTypeSchema() AssertAllRefsDefined(schema!); } - [Fact] - public void GetReturnSchema_TaskPerson_UnwrapsCorrectly() - { - var schema = GetReturnSchemaForMethod(nameof(TaskPersonMethod)); - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultRequired(schema); - AssertResultDefines(schema, typeof(Person), typeof(Address)); - AssertAllRefsDefined(schema); - } - - [Fact] - public void GetReturnSchema_TaskAddress_UnwrapsCorrectly() - { - var schema = GetReturnSchemaForMethod(nameof(TaskAddressMethod)); - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultRequired(schema); - AssertResultDefines(schema, typeof(Address)); - AssertAllRefsDefined(schema); - } - - [Fact] - public void GetReturnSchema_TaskCompany_UnwrapsCorrectly() + [Theory] + [InlineData(nameof(TaskPersonMethod), new[] { typeof(Person), typeof(Address) })] + [InlineData(nameof(TaskAddressMethod), new[] { typeof(Address) })] + [InlineData(nameof(TaskCompanyMethod), new[] { typeof(Company), typeof(Address), typeof(Person) })] + public void GetReturnSchema_TaskComplexType_UnwrapsCorrectly(string methodName, Type[] expectedDefinedTypes) { - var schema = GetReturnSchemaForMethod(nameof(TaskCompanyMethod)); - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultRequired(schema); - AssertResultDefines(schema, typeof(Company), typeof(Address), typeof(Person)); - AssertAllRefsDefined(schema); + TestComplexObjectSchema(methodName, shouldBeRequired: true, expectedDefinedTypes); } #endregion @@ -262,37 +293,13 @@ public void GetReturnSchema_TaskNullableCustomType_UnwrapsToCustomTypeSchemaWith AssertAllRefsDefined(schema!); } - [Fact] - public void GetReturnSchema_TaskNullablePerson_UnwrapsWithoutRequired() - { - var schema = GetReturnSchemaForMethod(nameof(TaskNullablePersonMethod)); - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultNotRequired(schema); - AssertResultDefines(schema, typeof(Person), typeof(Address)); - AssertAllRefsDefined(schema); - } - - [Fact] - public void GetReturnSchema_TaskNullableAddress_UnwrapsWithoutRequired() - { - var schema = GetReturnSchemaForMethod(nameof(TaskNullableAddressMethod)); - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultNotRequired(schema); - AssertResultDefines(schema, typeof(Address)); - AssertAllRefsDefined(schema); - } - - [Fact] - public void GetReturnSchema_TaskNullableCompany_UnwrapsWithoutRequired() + [Theory] + [InlineData(nameof(TaskNullablePersonMethod), new[] { typeof(Person), typeof(Address) })] + [InlineData(nameof(TaskNullableAddressMethod), new[] { typeof(Address) })] + [InlineData(nameof(TaskNullableCompanyMethod), new[] { typeof(Company), typeof(Address), typeof(Person) })] + public void GetReturnSchema_TaskNullableComplexType_UnwrapsWithoutRequired(string methodName, Type[] expectedDefinedTypes) { - var schema = GetReturnSchemaForMethod(nameof(TaskNullableCompanyMethod)); - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultNotRequired(schema); - AssertResultDefines(schema, typeof(Company), typeof(Address), typeof(Person)); - AssertAllRefsDefined(schema); + TestComplexObjectSchema(methodName, shouldBeRequired: false, expectedDefinedTypes); } #endregion @@ -317,37 +324,13 @@ public void GetReturnSchema_NullableTaskNullableCustomType_UnwrapsToCustomTypeSc AssertAllRefsDefined(schema!); } - [Fact] - public void GetReturnSchema_NullableTaskNullablePerson_UnwrapsWithoutRequired() - { - var schema = GetReturnSchemaForMethod(nameof(NullableTaskNullablePersonMethod)); - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultNotRequired(schema); - AssertResultDefines(schema, typeof(Person), typeof(Address)); - AssertAllRefsDefined(schema); - } - - [Fact] - public void GetReturnSchema_NullableTaskNullableAddress_UnwrapsWithoutRequired() - { - var schema = GetReturnSchemaForMethod(nameof(NullableTaskNullableAddressMethod)); - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultNotRequired(schema); - AssertResultDefines(schema, typeof(Address)); - AssertAllRefsDefined(schema); - } - - [Fact] - public void GetReturnSchema_NullableTaskNullableCompany_UnwrapsWithoutRequired() + [Theory] + [InlineData(nameof(NullableTaskNullablePersonMethod), new[] { typeof(Person), typeof(Address) })] + [InlineData(nameof(NullableTaskNullableAddressMethod), new[] { typeof(Address) })] + [InlineData(nameof(NullableTaskNullableCompanyMethod), new[] { typeof(Company), typeof(Address), typeof(Person) })] + public void GetReturnSchema_NullableTaskNullableComplexType_UnwrapsWithoutRequired(string methodName, Type[] expectedDefinedTypes) { - var schema = GetReturnSchemaForMethod(nameof(NullableTaskNullableCompanyMethod)); - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultNotRequired(schema); - AssertResultDefines(schema, typeof(Company), typeof(Address), typeof(Person)); - AssertAllRefsDefined(schema); + TestComplexObjectSchema(methodName, shouldBeRequired: false, expectedDefinedTypes); } #endregion @@ -372,37 +355,13 @@ public void GetReturnSchema_ValueTaskCustomType_UnwrapsToCustomTypeSchema() AssertAllRefsDefined(schema!); } - [Fact] - public void GetReturnSchema_ValueTaskPerson_UnwrapsCorrectly() - { - var schema = GetReturnSchemaForMethod(nameof(ValueTaskPersonMethod)); - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultRequired(schema); - AssertResultDefines(schema, typeof(Person), typeof(Address)); - AssertAllRefsDefined(schema); - } - - [Fact] - public void GetReturnSchema_ValueTaskAddress_UnwrapsCorrectly() - { - var schema = GetReturnSchemaForMethod(nameof(ValueTaskAddressMethod)); - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultRequired(schema); - AssertResultDefines(schema, typeof(Address)); - AssertAllRefsDefined(schema); - } - - [Fact] - public void GetReturnSchema_ValueTaskCompany_UnwrapsCorrectly() + [Theory] + [InlineData(nameof(ValueTaskPersonMethod), new[] { typeof(Person), typeof(Address) })] + [InlineData(nameof(ValueTaskAddressMethod), new[] { typeof(Address) })] + [InlineData(nameof(ValueTaskCompanyMethod), new[] { typeof(Company), typeof(Address), typeof(Person) })] + public void GetReturnSchema_ValueTaskComplexType_UnwrapsCorrectly(string methodName, Type[] expectedDefinedTypes) { - var schema = GetReturnSchemaForMethod(nameof(ValueTaskCompanyMethod)); - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultRequired(schema); - AssertResultDefines(schema, typeof(Company), typeof(Address), typeof(Person)); - AssertAllRefsDefined(schema); + TestComplexObjectSchema(methodName, shouldBeRequired: true, expectedDefinedTypes); } #endregion @@ -416,6 +375,7 @@ public void GetReturnSchema_ValueTaskNullablePrimitive_UnwrapsWithoutRequired(st { var schema = GetReturnSchemaForMethod(methodName); AssertPrimitiveReturnSchema(schema!, expectedType, shouldBeRequired: false); + AssertAllRefsDefined(schema!); } [Fact] @@ -426,37 +386,13 @@ public void GetReturnSchema_ValueTaskNullableCustomType_UnwrapsToCustomTypeSchem AssertAllRefsDefined(schema!); } - [Fact] - public void GetReturnSchema_ValueTaskNullablePerson_UnwrapsWithoutRequired() - { - var schema = GetReturnSchemaForMethod(nameof(ValueTaskNullablePersonMethod)); - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultNotRequired(schema); - AssertResultDefines(schema, typeof(Person), typeof(Address)); - AssertAllRefsDefined(schema); - } - - [Fact] - public void GetReturnSchema_ValueTaskNullableAddress_UnwrapsWithoutRequired() - { - var schema = GetReturnSchemaForMethod(nameof(ValueTaskNullableAddressMethod)); - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultNotRequired(schema); - AssertResultDefines(schema, typeof(Address)); - AssertAllRefsDefined(schema); - } - - [Fact] - public void GetReturnSchema_ValueTaskNullableCompany_UnwrapsWithoutRequired() + [Theory] + [InlineData(nameof(ValueTaskNullablePersonMethod), new[] { typeof(Person), typeof(Address) })] + [InlineData(nameof(ValueTaskNullableAddressMethod), new[] { typeof(Address) })] + [InlineData(nameof(ValueTaskNullableCompanyMethod), new[] { typeof(Company), typeof(Address), typeof(Person) })] + public void GetReturnSchema_ValueTaskNullableComplexType_UnwrapsWithoutRequired(string methodName, Type[] expectedDefinedTypes) { - var schema = GetReturnSchemaForMethod(nameof(ValueTaskNullableCompanyMethod)); - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultNotRequired(schema); - AssertResultDefines(schema, typeof(Company), typeof(Address), typeof(Person)); - AssertAllRefsDefined(schema); + TestComplexObjectSchema(methodName, shouldBeRequired: false, expectedDefinedTypes); } #endregion @@ -483,37 +419,13 @@ public void GetReturnSchema_ComplexType_ReturnsValidNestedSchema() AssertAllRefsDefined(schema!); } - [Fact] - public void GetReturnSchema_Person_ReturnsValidObjectSchema() - { - var schema = GetReturnSchemaForMethod(nameof(PersonMethod)); - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultRequired(schema); - AssertResultDefines(schema, typeof(Person), typeof(Address)); - AssertAllRefsDefined(schema); - } - - [Fact] - public void GetReturnSchema_Address_ReturnsValidObjectSchema() - { - var schema = GetReturnSchemaForMethod(nameof(AddressMethod)); - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultRequired(schema); - AssertResultDefines(schema, typeof(Address)); - AssertAllRefsDefined(schema); - } - - [Fact] - public void GetReturnSchema_Company_ReturnsValidObjectSchema() + [Theory] + [InlineData(nameof(PersonMethod), new[] { typeof(Person), typeof(Address) })] + [InlineData(nameof(AddressMethod), new[] { typeof(Address) })] + [InlineData(nameof(CompanyMethod), new[] { typeof(Company), typeof(Address), typeof(Person) })] + public void GetReturnSchema_ComplexType_ReturnsValidObjectSchema(string methodName, Type[] expectedDefinedTypes) { - var schema = GetReturnSchemaForMethod(nameof(CompanyMethod)); - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultRequired(schema); - AssertResultDefines(schema, typeof(Company), typeof(Address), typeof(Person)); - AssertAllRefsDefined(schema); + TestComplexObjectSchema(methodName, shouldBeRequired: true, expectedDefinedTypes); } #endregion @@ -537,37 +449,13 @@ public void GetReturnSchema_NullableComplexType_ReturnsValidNestedSchemaWithoutR AssertAllRefsDefined(schema!); } - [Fact] - public void GetReturnSchema_NullablePerson_ReturnsValidObjectSchemaWithoutRequired() - { - var schema = GetReturnSchemaForMethod(nameof(NullablePersonMethod)); - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultNotRequired(schema); - AssertResultDefines(schema, typeof(Person), typeof(Address)); - AssertAllRefsDefined(schema); - } - - [Fact] - public void GetReturnSchema_NullableAddress_ReturnsValidObjectSchemaWithoutRequired() - { - var schema = GetReturnSchemaForMethod(nameof(NullableAddressMethod)); - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultNotRequired(schema); - AssertResultDefines(schema, typeof(Address)); - AssertAllRefsDefined(schema); - } - - [Fact] - public void GetReturnSchema_NullableCompany_ReturnsValidObjectSchemaWithoutRequired() + [Theory] + [InlineData(nameof(NullablePersonMethod), new[] { typeof(Person), typeof(Address) })] + [InlineData(nameof(NullableAddressMethod), new[] { typeof(Address) })] + [InlineData(nameof(NullableCompanyMethod), new[] { typeof(Company), typeof(Address), typeof(Person) })] + public void GetReturnSchema_NullableComplexType_ReturnsValidObjectSchemaWithoutRequired(string methodName, Type[] expectedDefinedTypes) { - var schema = GetReturnSchemaForMethod(nameof(NullableCompanyMethod)); - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultNotRequired(schema); - AssertResultDefines(schema, typeof(Company), typeof(Address), typeof(Person)); - AssertAllRefsDefined(schema); + TestComplexObjectSchema(methodName, shouldBeRequired: false, expectedDefinedTypes); } #endregion @@ -601,74 +489,22 @@ public void GetReturnSchema_NullableStringArray_ReturnsArraySchemaWithoutRequire #region List Tests [Theory] - [InlineData(nameof(ListComplexTypeMethod), true)] -#if NET5_0_OR_GREATER - [InlineData(nameof(NullableListComplexTypeMethod), false)] -#else - [InlineData(nameof(NullableListComplexTypeMethod), true)] // netstandard2.1 cannot detect List? nullability -#endif - public void GetReturnSchema_ListComplexType_ReturnsArraySchemaWithComplexItems(string methodName, bool shouldBeRequired) + [InlineData(nameof(ListComplexTypeMethod), true, false)] + [InlineData(nameof(ListNullableComplexTypeMethod), true, true)] + [InlineData(nameof(NullableListNullableComplexTypeMethod), false, true)] + [InlineData(nameof(TaskListComplexTypeMethod), true, false)] + [InlineData(nameof(TaskNullableListComplexTypeMethod), false, false)] + [InlineData(nameof(NullableTaskNullableListComplexTypeMethod), false, false)] + [InlineData(nameof(TaskListNullableComplexTypeMethod), true, true)] + [InlineData(nameof(TaskNullableListNullableComplexTypeMethod), false, true)] + [InlineData(nameof(NullableTaskNullableListNullableComplexTypeMethod), false, true)] + [InlineData(nameof(NullableListComplexTypeMethod), false, false)] + [InlineData(nameof(NullableTaskListNullableComplexTypeMethod), false, true)] + [InlineData(nameof(NullableTaskListComplexTypeMethod), false, false)] + public void GetReturnSchema_ListComplexType_ReturnsCorrectSchema(string methodName, bool shouldBeRequired, bool itemsAreNullable) { var schema = GetReturnSchemaForMethod(methodName); - AssertComplexListReturnSchema(schema!, shouldBeRequired); - AssertAllRefsDefined(schema!); - } - - [Theory] - [InlineData(nameof(ListNullableComplexTypeMethod), true)] - [InlineData(nameof(NullableListNullableComplexTypeMethod), false)] - public void GetReturnSchema_ListNullableComplexType_ReturnsArraySchemaWithNullableComplexItems(string methodName, bool shouldBeRequired) - { - var schema = GetReturnSchemaForMethod(methodName); - AssertComplexListReturnSchema(schema!, shouldBeRequired, itemsAreNullable: true); - AssertAllRefsDefined(schema!); - } - - [Theory] - [InlineData(nameof(TaskListComplexTypeMethod), true)] -#if NET5_0_OR_GREATER - [InlineData(nameof(NullableTaskListComplexTypeMethod), false)] -#else - [InlineData(nameof(NullableTaskListComplexTypeMethod), true)] // netstandard2.1 cannot detect Task? nullability -#endif - public void GetReturnSchema_TaskListComplexType_UnwrapsToArraySchemaWithComplexItems(string methodName, bool shouldBeRequired) - { - var schema = GetReturnSchemaForMethod(methodName); - AssertComplexListReturnSchema(schema!, shouldBeRequired); - AssertAllRefsDefined(schema!); - } - - [Theory] - [InlineData(nameof(TaskNullableListComplexTypeMethod), false)] - [InlineData(nameof(NullableTaskNullableListComplexTypeMethod), false)] - public void GetReturnSchema_TaskNullableListComplexType_UnwrapsToArraySchemaWithoutRequired(string methodName, bool shouldBeRequired) - { - var schema = GetReturnSchemaForMethod(methodName); - AssertComplexListReturnSchema(schema!, shouldBeRequired); - AssertAllRefsDefined(schema!); - } - - [Theory] - [InlineData(nameof(TaskListNullableComplexTypeMethod), true)] -#if NET5_0_OR_GREATER - [InlineData(nameof(NullableTaskListNullableComplexTypeMethod), false)] -#else - [InlineData(nameof(NullableTaskListNullableComplexTypeMethod), true)] // netstandard2.1 cannot detect Task? nullability -#endif - public void GetReturnSchema_TaskListNullableComplexType_UnwrapsToArraySchemaWithNullableItems(string methodName, bool shouldBeRequired) - { - var schema = GetReturnSchemaForMethod(methodName); - AssertComplexListReturnSchema(schema!, shouldBeRequired, itemsAreNullable: true); - AssertAllRefsDefined(schema!); - } - - [Theory] - [InlineData(nameof(TaskNullableListNullableComplexTypeMethod), false)] - [InlineData(nameof(NullableTaskNullableListNullableComplexTypeMethod), false)] - public void GetReturnSchema_TaskNullableListNullableComplexType_UnwrapsToArraySchemaWithNullableItemsWithoutRequired(string methodName, bool shouldBeRequired) - { - var schema = GetReturnSchemaForMethod(methodName); - AssertComplexListReturnSchema(schema!, shouldBeRequired, itemsAreNullable: true); + AssertComplexListReturnSchema(schema!, shouldBeRequired, itemsAreNullable); AssertAllRefsDefined(schema!); } @@ -795,14 +631,21 @@ public void GetReturnSchema_NullMethodInfo_ThrowsArgumentNullException() } [Theory] - [InlineData(typeof(string), nameof(WrapperClass.Echo), JsonSchema.String, true)] // string with Echo (T) is non-nullable due to NullableContextAttribute(1) - [InlineData(typeof(int), nameof(WrapperClass.Echo), JsonSchema.Integer, true)] // int is value type, T is non-nullable - [InlineData(typeof(bool), nameof(WrapperClass.Echo), JsonSchema.Boolean, true)] // bool is value type, T is non-nullable - [InlineData(typeof(double), nameof(WrapperClass.Echo), JsonSchema.Number, true)] // double is value type, T is non-nullable - [InlineData(typeof(string), nameof(WrapperClass.EchoNullable), JsonSchema.String, false)] // T? with reference type is nullable - [InlineData(typeof(int), nameof(WrapperClass.EchoNullable), JsonSchema.Integer, false)] // T? with value type is also nullable (int? becomes int, but T? context is nullable) - [InlineData(typeof(bool), nameof(WrapperClass.EchoNullable), JsonSchema.Boolean, false)] // T? with value type is also nullable (bool? becomes bool, but T? context is nullable) - [InlineData(typeof(double), nameof(WrapperClass.EchoNullable), JsonSchema.Number, false)] // T? with value type is also nullable (double? becomes double, but T? context is nullable) + [InlineData(typeof(string), EchoMethodName, JsonSchema.String, true)] // string with Echo (T) is non-nullable due to NullableContextAttribute(1) + [InlineData(typeof(int), EchoMethodName, JsonSchema.Integer, true)] // int is value type, T is non-nullable + [InlineData(typeof(bool), EchoMethodName, JsonSchema.Boolean, true)] // bool is value type, T is non-nullable + [InlineData(typeof(double), EchoMethodName, JsonSchema.Number, true)] // double is value type, T is non-nullable +#if NET8_0_OR_GREATER + [InlineData(typeof(string), EchoNullableMethodName, JsonSchema.String, false)] // T? with reference type is nullable + [InlineData(typeof(int), EchoNullableMethodName, JsonSchema.Integer, false)] // T? with value type is also nullable (int? becomes int, but T? context is nullable) + [InlineData(typeof(bool), EchoNullableMethodName, JsonSchema.Boolean, false)] // T? with value type is also nullable (bool? becomes bool, but T? context is nullable) + [InlineData(typeof(double), EchoNullableMethodName, JsonSchema.Number, false)] // T? with value type is also nullable (double? becomes double, but T? context is nullable) +#else + [InlineData(typeof(string), EchoNullableMethodName, JsonSchema.String, true)] // T? with reference type is non-nullable due to lack of nullable context + [InlineData(typeof(int), EchoNullableMethodName, JsonSchema.Integer, true)] // T? with value type is non-nullable due to lack of nullable context + [InlineData(typeof(bool), EchoNullableMethodName, JsonSchema.Boolean, true)] // T? with value type is non-nullable due to lack of nullable context + [InlineData(typeof(double), EchoNullableMethodName, JsonSchema.Number, true)] // T? with value type is non-nullable due to lack of nullable context +#endif public void GetReturnSchema_WrapperEchoPrimitive_ReturnsCorrectSchema(Type genericType, string methodName, string expectedType, bool shouldBeRequired) { var wrapperType = typeof(WrapperClass<>).MakeGenericType(genericType); @@ -812,30 +655,19 @@ public void GetReturnSchema_WrapperEchoPrimitive_ReturnsCorrectSchema(Type gener } [Theory] - [InlineData(typeof(CustomReturnType), true)] - [InlineData(typeof(ComplexReturnType), true)] - public void GetReturnSchema_WrapperEchoCustomType_ReturnsCorrectSchema(Type genericType, bool shouldBeRequired) - { - var wrapperType = typeof(WrapperClass<>).MakeGenericType(genericType); - var schema = GetWrapperMethodReturnSchema(wrapperType, nameof(WrapperClass.Echo)); - - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - - if (shouldBeRequired) - AssertResultRequired(schema); - else - AssertResultNotRequired(schema); - AssertAllRefsDefined(schema); - } - - [Theory] - [InlineData(typeof(CustomReturnType), false)] - [InlineData(typeof(ComplexReturnType), false)] - public void GetReturnSchema_WrapperEchoNullableCustomType_ReturnsCorrectSchema(Type genericType, bool shouldBeRequired) + [InlineData(typeof(CustomReturnType), EchoMethodName, true)] + [InlineData(typeof(ComplexReturnType), EchoMethodName, true)] +#if NET8_0_OR_GREATER + [InlineData(typeof(CustomReturnType), EchoNullableMethodName, false)] + [InlineData(typeof(ComplexReturnType), EchoNullableMethodName, false)] +#else + [InlineData(typeof(CustomReturnType), EchoNullableMethodName, true)] + [InlineData(typeof(ComplexReturnType), EchoNullableMethodName, true)] +#endif + public void GetReturnSchema_WrapperEchoCustomType_ReturnsCorrectSchema(Type genericType, string methodName, bool shouldBeRequired) { var wrapperType = typeof(WrapperClass<>).MakeGenericType(genericType); - var schema = GetWrapperMethodReturnSchema(wrapperType, nameof(WrapperClass.EchoNullable)); + var schema = GetWrapperMethodReturnSchema(wrapperType, methodName); Assert.NotNull(schema); Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); @@ -848,128 +680,53 @@ public void GetReturnSchema_WrapperEchoNullableCustomType_ReturnsCorrectSchema(T } [Theory] - [InlineData(typeof(string[]), JsonSchema.String, true)] - [InlineData(typeof(int[]), JsonSchema.Integer, true)] - public void GetReturnSchema_WrapperEchoArray_ReturnsCorrectSchema(Type genericType, string expectedItemType, bool shouldBeRequired) - { - var wrapperType = typeof(WrapperClass<>).MakeGenericType(genericType); - var schema = GetWrapperMethodReturnSchema(wrapperType, nameof(WrapperClass.Echo)); - AssertArrayReturnSchema(schema!, expectedItemType, shouldBeRequired); - AssertAllRefsDefined(schema!); - } - - [Theory] -#if NET5_0_OR_GREATER - [InlineData(typeof(string[]), JsonSchema.String, false)] - [InlineData(typeof(int[]), JsonSchema.Integer, false)] + [InlineData(typeof(string[]), EchoMethodName, JsonSchema.String, true)] + [InlineData(typeof(int[]), EchoMethodName, JsonSchema.Integer, true)] +#if NET8_0_OR_GREATER + [InlineData(typeof(string[]), EchoNullableMethodName, JsonSchema.String, false)] + [InlineData(typeof(int[]), EchoNullableMethodName, JsonSchema.Integer, false)] #else - [InlineData(typeof(string[]), JsonSchema.String, true)] - [InlineData(typeof(int[]), JsonSchema.Integer, true)] + [InlineData(typeof(string[]), EchoNullableMethodName, JsonSchema.String, true)] + [InlineData(typeof(int[]), EchoNullableMethodName, JsonSchema.Integer, true)] #endif - public void GetReturnSchema_WrapperEchoNullableArray_ReturnsCorrectSchema(Type genericType, string expectedItemType, bool shouldBeRequired) + public void GetReturnSchema_WrapperEchoArray_ReturnsCorrectSchema(Type genericType, string methodName, string expectedItemType, bool shouldBeRequired) { var wrapperType = typeof(WrapperClass<>).MakeGenericType(genericType); - var schema = GetWrapperMethodReturnSchema(wrapperType, nameof(WrapperClass.EchoNullable)); + var schema = GetWrapperMethodReturnSchema(wrapperType, methodName); AssertArrayReturnSchema(schema!, expectedItemType, shouldBeRequired); AssertAllRefsDefined(schema!); } - [Fact] - public void GetReturnSchema_WrapperEchoListComplex_ReturnsCorrectSchema() - { - // WrapperClass.Echo has NullableContextAttribute(1), meaning T is non-nullable - // Therefore, WrapperClass>.Echo should return non-nullable List - var wrapperType = typeof(WrapperClass>); - var schema = GetWrapperMethodReturnSchema(wrapperType, nameof(WrapperClass>.Echo)); - AssertComplexListReturnSchema(schema!, shouldBeRequired: true); - AssertAllRefsDefined(schema!); - } - - [Fact] - public void GetReturnSchema_WrapperEchoNullableListComplex_ReturnsCorrectSchema() + [Theory] + [InlineData(EchoMethodName, true, false)] // WrapperClass.Echo has NullableContextAttribute(1), meaning T is non-nullable +#if NET8_0_OR_GREATER + [InlineData(EchoNullableMethodName, false, false)] +#endif + public void GetReturnSchema_WrapperEchoListComplex_ReturnsCorrectSchema(string methodName, bool shouldBeRequired, bool itemsAreNullable) { var wrapperType = typeof(WrapperClass>); - var schema = GetWrapperMethodReturnSchema(wrapperType, nameof(WrapperClass>.EchoNullable)); - AssertComplexListReturnSchema(schema!, shouldBeRequired: false); + var schema = GetWrapperMethodReturnSchema(wrapperType, methodName); + AssertComplexListReturnSchema(schema!, shouldBeRequired, itemsAreNullable); AssertAllRefsDefined(schema!); } - [Fact] - public void GetReturnSchema_WrapperEchoPerson_ReturnsCorrectSchema() - { - var wrapperType = typeof(WrapperClass<>).MakeGenericType(typeof(Person)); - var schema = GetWrapperMethodReturnSchema(wrapperType, nameof(WrapperClass.Echo)); - - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultRequired(schema); - AssertResultDefines(schema, typeof(Person), typeof(Address)); - AssertAllRefsDefined(schema); - } - - [Fact] - public void GetReturnSchema_WrapperEchoAddress_ReturnsCorrectSchema() - { - var wrapperType = typeof(WrapperClass<>).MakeGenericType(typeof(Address)); - var schema = GetWrapperMethodReturnSchema(wrapperType, nameof(WrapperClass
.Echo)); - - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultRequired(schema); - AssertResultDefines(schema, typeof(Address)); - AssertAllRefsDefined(schema); - } - - [Fact] - public void GetReturnSchema_WrapperEchoCompany_ReturnsCorrectSchema() - { - var wrapperType = typeof(WrapperClass<>).MakeGenericType(typeof(Company)); - var schema = GetWrapperMethodReturnSchema(wrapperType, nameof(WrapperClass.Echo)); - - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultRequired(schema); - AssertResultDefines(schema, typeof(Company), typeof(Address), typeof(Person)); - AssertAllRefsDefined(schema); - } - - [Fact] - public void GetReturnSchema_WrapperEchoNullablePerson_ReturnsCorrectSchema() - { - var wrapperType = typeof(WrapperClass<>).MakeGenericType(typeof(Person)); - var schema = GetWrapperMethodReturnSchema(wrapperType, nameof(WrapperClass.EchoNullable)); - - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultNotRequired(schema); - AssertResultDefines(schema, typeof(Person), typeof(Address)); - AssertAllRefsDefined(schema); - } - - [Fact] - public void GetReturnSchema_WrapperEchoNullableAddress_ReturnsCorrectSchema() - { - var wrapperType = typeof(WrapperClass<>).MakeGenericType(typeof(Address)); - var schema = GetWrapperMethodReturnSchema(wrapperType, nameof(WrapperClass
.EchoNullable)); - - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultNotRequired(schema); - AssertResultDefines(schema, typeof(Address)); - AssertAllRefsDefined(schema); - } - - [Fact] - public void GetReturnSchema_WrapperEchoNullableCompany_ReturnsCorrectSchema() + [Theory] + [InlineData(typeof(Person), EchoMethodName, true, new[] { typeof(Person), typeof(Address) })] + [InlineData(typeof(Address), EchoMethodName, true, new[] { typeof(Address) })] + [InlineData(typeof(Company), EchoMethodName, true, new[] { typeof(Company), typeof(Address), typeof(Person) })] +#if NET8_0_OR_GREATER + [InlineData(typeof(Person), EchoNullableMethodName, false, new[] { typeof(Person), typeof(Address) })] + [InlineData(typeof(Address), EchoNullableMethodName, false, new[] { typeof(Address) })] + [InlineData(typeof(Company), EchoNullableMethodName, false, new[] { typeof(Company), typeof(Address), typeof(Person) })] +#else + [InlineData(typeof(Person), EchoNullableMethodName, true, new[] { typeof(Person), typeof(Address) })] + [InlineData(typeof(Address), EchoNullableMethodName, true, new[] { typeof(Address) })] + [InlineData(typeof(Company), EchoNullableMethodName, true, new[] { typeof(Company), typeof(Address), typeof(Person) })] +#endif + public void GetReturnSchema_WrapperEchoComplexType_ReturnsCorrectSchema(Type genericType, string methodName, bool shouldBeRequired, Type[] expectedDefinedTypes) { - var wrapperType = typeof(WrapperClass<>).MakeGenericType(typeof(Company)); - var schema = GetWrapperMethodReturnSchema(wrapperType, nameof(WrapperClass.EchoNullable)); - - Assert.NotNull(schema); - Assert.Equal(JsonSchema.Object, schema[JsonSchema.Type]?.ToString()); - AssertResultNotRequired(schema); - AssertResultDefines(schema, typeof(Company), typeof(Address), typeof(Person)); - AssertAllRefsDefined(schema); + var wrapperType = typeof(WrapperClass<>).MakeGenericType(genericType); + TestWrapperComplexObjectSchema(wrapperType, methodName, shouldBeRequired, expectedDefinedTypes); } #endregion diff --git a/ReflectorNet.Tests/Utils/MethodUtilsTests.cs b/ReflectorNet.Tests/Utils/MethodUtilsTests.cs index e437581e..940d1582 100644 --- a/ReflectorNet.Tests/Utils/MethodUtilsTests.cs +++ b/ReflectorNet.Tests/Utils/MethodUtilsTests.cs @@ -490,9 +490,11 @@ private static void AssertWrapperMethodNullability(Type genericTypeArgument, str [InlineData(typeof(int), nameof(WrapperClass.Echo), false)] // WrapperClass.Echo returns T where T=int (non-nullable) [InlineData(typeof(string), nameof(WrapperClass.Echo), false)] // WrapperClass.Echo returns T where T=string (non-nullable) [InlineData(typeof(Company), nameof(WrapperClass.Echo), false)] // WrapperClass.Echo returns T where T=Company (non-nullable) +#if NET8_0_OR_GREATER [InlineData(typeof(int), nameof(WrapperClass.EchoNullable), true)] // WrapperClass.EchoNullable returns T? where T=int (nullable) [InlineData(typeof(string), nameof(WrapperClass.EchoNullable), true)] // WrapperClass.EchoNullable returns T? where T=string (nullable) [InlineData(typeof(Company), nameof(WrapperClass.EchoNullable), true)] // WrapperClass.EchoNullable returns T? where T=Company (nullable) +#endif public void IsReturnTypeNullable_GenericTypeParameter_WithNonNullableTypes(Type genericTypeArgument, string methodName, bool expectedNullable) { AssertWrapperMethodNullability(genericTypeArgument, methodName, expectedNullable); @@ -514,7 +516,9 @@ public void IsReturnTypeNullable_GenericTypeParameter_WithNullableValueTypes(Typ [Theory] [InlineData(nameof(WrapperClass>.Echo), false)] // WrapperClass>.Echo returns T where T=List (non-nullable) +#if NET8_0_OR_GREATER [InlineData(nameof(WrapperClass>.EchoNullable), true)] // WrapperClass>.EchoNullable returns T? where T=List (nullable) +#endif public void IsReturnTypeNullable_GenericTypeParameter_WithComplexTypes(string methodName, bool expectedNullable) { AssertWrapperMethodNullability(typeof(List), methodName, expectedNullable); diff --git a/ReflectorNet/ReflectorNet.csproj b/ReflectorNet/ReflectorNet.csproj index 7cfca754..7aded211 100644 --- a/ReflectorNet/ReflectorNet.csproj +++ b/ReflectorNet/ReflectorNet.csproj @@ -1,7 +1,7 @@  - netstandard2.1;net8.0;net9.0 + netstandard2.1;net6.0;net8.0;net9.0 10.0 disable enable @@ -26,7 +26,12 @@ - + + + + + +