diff --git a/JsonApiDotNetCore.sln.DotSettings b/JsonApiDotNetCore.sln.DotSettings index 6c29a58aef..3576ab2bd8 100644 --- a/JsonApiDotNetCore.sln.DotSettings +++ b/JsonApiDotNetCore.sln.DotSettings @@ -583,6 +583,7 @@ False False False + IP False <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /> diff --git a/src/Examples/DapperExample/TranslationToSql/ParameterFormatter.cs b/src/Examples/DapperExample/TranslationToSql/ParameterFormatter.cs index 5dc1591bca..90861d66c4 100644 --- a/src/Examples/DapperExample/TranslationToSql/ParameterFormatter.cs +++ b/src/Examples/DapperExample/TranslationToSql/ParameterFormatter.cs @@ -8,7 +8,7 @@ namespace DapperExample.TranslationToSql; /// internal sealed class ParameterFormatter { - private static readonly HashSet NumericTypes = + private static readonly HashSet SimpleTypes = [ typeof(bool), typeof(int), @@ -53,7 +53,7 @@ private void WriteValue(object? parameterValue, StringBuilder builder) { string value = (string)RuntimeTypeConverter.ConvertType(parameterValue, typeof(string))!; - if (NumericTypes.Contains(parameterValue.GetType())) + if (SimpleTypes.Contains(parameterValue.GetType())) { builder.Append(value); } diff --git a/src/JsonApiDotNetCore.Annotations/Resources/RuntimeTypeConverter.cs b/src/JsonApiDotNetCore.Annotations/Resources/RuntimeTypeConverter.cs index 74a4eb877c..679d726a5d 100644 --- a/src/JsonApiDotNetCore.Annotations/Resources/RuntimeTypeConverter.cs +++ b/src/JsonApiDotNetCore.Annotations/Resources/RuntimeTypeConverter.cs @@ -53,7 +53,7 @@ public static class RuntimeTypeConverter { if (!CanContainNull(type)) { - string targetTypeName = type.GetFriendlyTypeName(); + string targetTypeName = GetFriendlyTypeName(type); throw new FormatException($"Failed to convert 'null' to type '{targetTypeName}'."); } @@ -67,7 +67,9 @@ public static class RuntimeTypeConverter return value; } - string? stringValue = value is IFormattable cultureAwareValue ? cultureAwareValue.ToString(null, cultureInfo) : value.ToString(); + string? stringValue = value is IFormattable cultureAwareValue + ? cultureAwareValue.ToString(value is DateTime or DateTimeOffset or DateOnly or TimeOnly ? "O" : null, cultureInfo) + : value.ToString(); if (string.IsNullOrEmpty(stringValue)) { @@ -115,6 +117,11 @@ public static class RuntimeTypeConverter return isNullableTypeRequested ? (TimeOnly?)convertedValue : convertedValue; } + if (nonNullableType == typeof(Uri)) + { + return new Uri(stringValue); + } + if (nonNullableType.IsEnum) { object convertedValue = Enum.Parse(nonNullableType, stringValue); @@ -128,8 +135,8 @@ public static class RuntimeTypeConverter } catch (Exception exception) when (exception is FormatException or OverflowException or InvalidCastException or ArgumentException) { - string runtimeTypeName = runtimeType.GetFriendlyTypeName(); - string targetTypeName = type.GetFriendlyTypeName(); + string runtimeTypeName = GetFriendlyTypeName(runtimeType); + string targetTypeName = GetFriendlyTypeName(type); throw new FormatException($"Failed to convert '{value}' of type '{runtimeTypeName}' to type '{targetTypeName}'.", exception); } @@ -157,4 +164,27 @@ public static bool CanContainNull(Type type) return type.IsValueType ? DefaultTypeCache.GetOrAdd(type, Activator.CreateInstance) : null; } + + /// + /// Gets the name of a type, including the names of its generic type arguments, without any namespaces. + /// + /// > + /// ]]> + /// + /// + public static string GetFriendlyTypeName(Type type) + { + ArgumentNullException.ThrowIfNull(type); + + // Based on https://stackoverflow.com/questions/2581642/how-do-i-get-the-type-name-of-a-generic-type-argument. + + if (type.IsGenericType) + { + string typeArguments = type.GetGenericArguments().Select(GetFriendlyTypeName).Aggregate((firstType, secondType) => $"{firstType}, {secondType}"); + return $"{type.Name[..type.Name.IndexOf('`')]}<{typeArguments}>"; + } + + return type.Name; + } } diff --git a/src/JsonApiDotNetCore.Annotations/TypeExtensions.cs b/src/JsonApiDotNetCore.Annotations/TypeExtensions.cs index 89b8158554..61a173066c 100644 --- a/src/JsonApiDotNetCore.Annotations/TypeExtensions.cs +++ b/src/JsonApiDotNetCore.Annotations/TypeExtensions.cs @@ -30,27 +30,4 @@ private static bool AreTypesEqual(Type left, Type right, bool isLeftGeneric) { return isLeftGeneric ? right.IsGenericType && right.GetGenericTypeDefinition() == left : left == right; } - - /// - /// Gets the name of a type, including the names of its generic type arguments. - /// - /// > - /// ]]> - /// - /// - public static string GetFriendlyTypeName(this Type type) - { - ArgumentNullException.ThrowIfNull(type); - - // Based on https://stackoverflow.com/questions/2581642/how-do-i-get-the-type-name-of-a-generic-type-argument. - - if (type.IsGenericType) - { - string typeArguments = type.GetGenericArguments().Select(GetFriendlyTypeName).Aggregate((firstType, secondType) => $"{firstType}, {secondType}"); - return $"{type.Name[..type.Name.IndexOf('`')]}<{typeArguments}>"; - } - - return type.Name; - } } diff --git a/src/JsonApiDotNetCore/Queries/Expressions/LiteralConstantExpression.cs b/src/JsonApiDotNetCore/Queries/Expressions/LiteralConstantExpression.cs index 50c3b2cd54..f717629af1 100644 --- a/src/JsonApiDotNetCore/Queries/Expressions/LiteralConstantExpression.cs +++ b/src/JsonApiDotNetCore/Queries/Expressions/LiteralConstantExpression.cs @@ -35,7 +35,9 @@ public LiteralConstantExpression(object typedValue, string stringValue) { ArgumentNullException.ThrowIfNull(typedValue); - return typedValue is IFormattable cultureAwareValue ? cultureAwareValue.ToString(null, CultureInfo.InvariantCulture) : typedValue.ToString(); + return typedValue is IFormattable cultureAwareValue + ? cultureAwareValue.ToString(typedValue is DateTime or DateTimeOffset or DateOnly or TimeOnly ? "O" : null, CultureInfo.InvariantCulture) + : typedValue.ToString(); } public override TResult Accept(QueryExpressionVisitor visitor, TArgument argument) diff --git a/src/JsonApiDotNetCore/Queries/Parsing/FilterParser.cs b/src/JsonApiDotNetCore/Queries/Parsing/FilterParser.cs index 914abd7802..3babdae45e 100644 --- a/src/JsonApiDotNetCore/Queries/Parsing/FilterParser.cs +++ b/src/JsonApiDotNetCore/Queries/Parsing/FilterParser.cs @@ -532,7 +532,8 @@ protected virtual ConstantValueConverter GetConstantValueConverterForType(Type d } catch (FormatException exception) { - throw new QueryParseException($"Failed to convert '{stringValue}' of type 'String' to type '{destinationType.Name}'.", position, exception); + string destinationTypeName = RuntimeTypeConverter.GetFriendlyTypeName(destinationType); + throw new QueryParseException($"Failed to convert '{stringValue}' of type 'String' to type '{destinationTypeName}'.", position, exception); } }; } diff --git a/src/JsonApiDotNetCore/Serialization/JsonConverters/ResourceObjectConverter.cs b/src/JsonApiDotNetCore/Serialization/JsonConverters/ResourceObjectConverter.cs index d20bdd5f0d..529c76a1d2 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonConverters/ResourceObjectConverter.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonConverters/ResourceObjectConverter.cs @@ -214,7 +214,7 @@ public override ResourceObject Read(ref Utf8JsonReader reader, Type typeToConver { attributeValue = JsonSerializer.Deserialize(ref reader, property.PropertyType, options); } - catch (JsonException) + catch (JsonException exception) { // Inside a JsonConverter there is no way to know where in the JSON object tree we are. And the serializer // is unable to provide the correct position either. So we avoid an exception and postpone producing an error @@ -222,7 +222,7 @@ public override ResourceObject Read(ref Utf8JsonReader reader, Type typeToConver var jsonElement = ReadSubTree(ref reader, options); attributeValue = new JsonInvalidAttributeInfo(attributeName, property.PropertyType, jsonElement.ToString(), - jsonElement.ValueKind); + jsonElement.ValueKind, exception); } } diff --git a/src/JsonApiDotNetCore/Serialization/Request/Adapters/ResourceObjectAdapter.cs b/src/JsonApiDotNetCore/Serialization/Request/Adapters/ResourceObjectAdapter.cs index 71fafe7363..2df888846e 100644 --- a/src/JsonApiDotNetCore/Serialization/Request/Adapters/ResourceObjectAdapter.cs +++ b/src/JsonApiDotNetCore/Serialization/Request/Adapters/ResourceObjectAdapter.cs @@ -86,13 +86,14 @@ private static void AssertNoInvalidAttribute(object? attributeValue, RequestAdap { if (info == JsonInvalidAttributeInfo.Id) { - throw new ModelConversionException(state.Position, "Resource ID is read-only.", null); + throw new ModelConversionException(state.Position, "Resource ID is read-only.", null, innerException: info.InnerException); } - string typeName = info.AttributeType.GetFriendlyTypeName(); + string typeName = RuntimeTypeConverter.GetFriendlyTypeName(info.AttributeType); throw new ModelConversionException(state.Position, "Incompatible attribute value found.", - $"Failed to convert attribute '{info.AttributeName}' with value '{info.JsonValue}' of type '{info.JsonType}' to type '{typeName}'."); + $"Failed to convert attribute '{info.AttributeName}' with value '{info.JsonValue}' of type '{info.JsonType}' to type '{typeName}'.", + innerException: info.InnerException); } } diff --git a/src/JsonApiDotNetCore/Serialization/Request/JsonInvalidAttributeInfo.cs b/src/JsonApiDotNetCore/Serialization/Request/JsonInvalidAttributeInfo.cs index 4004e83de9..db362c11f5 100644 --- a/src/JsonApiDotNetCore/Serialization/Request/JsonInvalidAttributeInfo.cs +++ b/src/JsonApiDotNetCore/Serialization/Request/JsonInvalidAttributeInfo.cs @@ -7,14 +7,15 @@ namespace JsonApiDotNetCore.Serialization.Request; /// internal sealed class JsonInvalidAttributeInfo { - public static readonly JsonInvalidAttributeInfo Id = new("id", typeof(string), "-", JsonValueKind.Undefined); + public static readonly JsonInvalidAttributeInfo Id = new("id", typeof(string), "-", JsonValueKind.Undefined, null); public string AttributeName { get; } public Type AttributeType { get; } public string? JsonValue { get; } public JsonValueKind JsonType { get; } + public Exception? InnerException { get; } - public JsonInvalidAttributeInfo(string attributeName, Type attributeType, string? jsonValue, JsonValueKind jsonType) + public JsonInvalidAttributeInfo(string attributeName, Type attributeType, string? jsonValue, JsonValueKind jsonType, Exception? innerException) { ArgumentNullException.ThrowIfNull(attributeName); ArgumentNullException.ThrowIfNull(attributeType); @@ -23,5 +24,6 @@ public JsonInvalidAttributeInfo(string attributeName, Type attributeType, string AttributeType = attributeType; JsonValue = jsonValue; JsonType = jsonType; + InnerException = innerException; } } diff --git a/src/JsonApiDotNetCore/Serialization/Request/ModelConversionException.cs b/src/JsonApiDotNetCore/Serialization/Request/ModelConversionException.cs index 02db72573d..b34ec38a64 100644 --- a/src/JsonApiDotNetCore/Serialization/Request/ModelConversionException.cs +++ b/src/JsonApiDotNetCore/Serialization/Request/ModelConversionException.cs @@ -15,8 +15,9 @@ public sealed class ModelConversionException : Exception public HttpStatusCode? StatusCode { get; } public string? SourcePointer { get; } - public ModelConversionException(RequestAdapterPosition position, string? genericMessage, string? specificMessage, HttpStatusCode? statusCode = null) - : base(genericMessage) + public ModelConversionException(RequestAdapterPosition position, string? genericMessage, string? specificMessage, HttpStatusCode? statusCode = null, + Exception? innerException = null) + : base(genericMessage, innerException) { ArgumentNullException.ThrowIfNull(position); diff --git a/test/JsonApiDotNetCoreTests/IntegrationTests/QueryStrings/CustomFunctions/Sum/SumFilterParser.cs b/test/JsonApiDotNetCoreTests/IntegrationTests/QueryStrings/CustomFunctions/Sum/SumFilterParser.cs index 11cb521a07..cb33eaf030 100644 --- a/test/JsonApiDotNetCoreTests/IntegrationTests/QueryStrings/CustomFunctions/Sum/SumFilterParser.cs +++ b/test/JsonApiDotNetCoreTests/IntegrationTests/QueryStrings/CustomFunctions/Sum/SumFilterParser.cs @@ -1,3 +1,4 @@ +using System.Numerics; using JsonApiDotNetCore.Queries.Expressions; using JsonApiDotNetCore.Queries.Parsing; using JsonApiDotNetCore.QueryStrings.FieldChains; @@ -11,21 +12,6 @@ internal sealed class SumFilterParser(IResourceFactory resourceFactory) { private static readonly FieldChainPattern SingleToManyRelationshipChain = FieldChainPattern.Parse("M"); - private static readonly HashSet NumericTypes = - [ - typeof(sbyte), - typeof(byte), - typeof(short), - typeof(ushort), - typeof(int), - typeof(uint), - typeof(long), - typeof(ulong), - typeof(float), - typeof(double), - typeof(decimal) - ]; - protected override bool IsFunction(string name) { if (name == SumExpression.Keyword) @@ -103,6 +89,6 @@ private QueryExpression ParseSumSelector() private static bool IsNumericType(Type type) { Type innerType = Nullable.GetUnderlyingType(type) ?? type; - return NumericTypes.Contains(innerType); + return innerType.GetInterfaces().Any(@interface => @interface.Name == typeof(INumber<>).Name && @interface.Namespace == typeof(INumber<>).Namespace); } } diff --git a/test/JsonApiDotNetCoreTests/UnitTests/TypeConversion/RuntimeTypeConverterTests.cs b/test/JsonApiDotNetCoreTests/UnitTests/TypeConversion/RuntimeTypeConverterTests.cs index c7b0bf9450..f9189c7c18 100644 --- a/test/JsonApiDotNetCoreTests/UnitTests/TypeConversion/RuntimeTypeConverterTests.cs +++ b/test/JsonApiDotNetCoreTests/UnitTests/TypeConversion/RuntimeTypeConverterTests.cs @@ -1,3 +1,6 @@ +using System.Net; +using System.Numerics; +using System.Text; using FluentAssertions; using JsonApiDotNetCore.Resources; using Xunit; @@ -17,13 +20,22 @@ public sealed class RuntimeTypeConverterTests [InlineData(typeof(uint))] [InlineData(typeof(long))] [InlineData(typeof(ulong))] + [InlineData(typeof(Int128))] + [InlineData(typeof(UInt128))] + [InlineData(typeof(BigInteger))] + [InlineData(typeof(Half))] [InlineData(typeof(float))] [InlineData(typeof(double))] [InlineData(typeof(decimal))] - [InlineData(typeof(Guid))] - [InlineData(typeof(DateTime))] + [InlineData(typeof(Complex))] + [InlineData(typeof(Rune))] [InlineData(typeof(DateTimeOffset))] + [InlineData(typeof(DateTime))] + [InlineData(typeof(DateOnly))] + [InlineData(typeof(TimeOnly))] [InlineData(typeof(TimeSpan))] + [InlineData(typeof(Guid))] + [InlineData(typeof(IPNetwork))] [InlineData(typeof(DayOfWeek))] public void Cannot_convert_null_to_value_type(Type type) { @@ -45,13 +57,22 @@ public void Cannot_convert_null_to_value_type(Type type) [InlineData(typeof(uint?))] [InlineData(typeof(long?))] [InlineData(typeof(ulong?))] + [InlineData(typeof(Int128?))] + [InlineData(typeof(UInt128?))] + [InlineData(typeof(BigInteger?))] + [InlineData(typeof(Half?))] [InlineData(typeof(float?))] [InlineData(typeof(double?))] [InlineData(typeof(decimal?))] - [InlineData(typeof(Guid?))] - [InlineData(typeof(DateTime?))] + [InlineData(typeof(Complex?))] + [InlineData(typeof(Rune?))] [InlineData(typeof(DateTimeOffset?))] + [InlineData(typeof(DateTime?))] + [InlineData(typeof(DateOnly?))] + [InlineData(typeof(TimeOnly?))] [InlineData(typeof(TimeSpan?))] + [InlineData(typeof(Guid?))] + [InlineData(typeof(IPNetwork?))] [InlineData(typeof(DayOfWeek?))] [InlineData(typeof(string))] [InlineData(typeof(IFace))] @@ -129,12 +150,18 @@ public void Returns_same_instance_for_interface() [InlineData(typeof(long?), null)] [InlineData(typeof(ulong), 0)] [InlineData(typeof(ulong?), null)] + [InlineData(typeof(Int128?), null)] + [InlineData(typeof(UInt128?), null)] + [InlineData(typeof(BigInteger?), null)] + [InlineData(typeof(Half?), null)] [InlineData(typeof(float), 0)] [InlineData(typeof(float?), null)] [InlineData(typeof(double), 0)] [InlineData(typeof(double?), null)] [InlineData(typeof(decimal), 0)] [InlineData(typeof(decimal?), null)] + [InlineData(typeof(Complex?), null)] + [InlineData(typeof(Rune?), null)] [InlineData(typeof(DayOfWeek), DayOfWeek.Sunday)] [InlineData(typeof(DayOfWeek?), null)] [InlineData(typeof(string), "")] diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/AttributeTypeTests.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/AttributeTypeTests.cs new file mode 100644 index 0000000000..5ee0786722 --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/AttributeTypeTests.cs @@ -0,0 +1,963 @@ +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Net; +using System.Reflection; +using FluentAssertions; +using Humanizer; +using JsonApiDotNetCore.Resources; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Kiota.Abstractions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Http.HttpClientLibrary; +using OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode; +using OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models; +using OpenApiTests; +using OpenApiTests.AttributeTypes; +using TestBuildingBlocks; +using Xunit; +using Xunit.Abstractions; +using ClientDayOfWeek = OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.DayOfWeekObject; +using IJsonApiOptions = JsonApiDotNetCore.Configuration.IJsonApiOptions; +using ServerDayOfWeek = System.DayOfWeek; + +namespace OpenApiKiotaEndToEndTests.AttributeTypes; + +public sealed class AttributeTypeTests : IClassFixture>, IDisposable +{ + private readonly IntegrationTestContext _testContext; + private readonly TestableHttpClientRequestAdapterFactory _requestAdapterFactory; + private readonly AttributeTypesFakers _fakers = new(); + + public AttributeTypeTests(IntegrationTestContext testContext, ITestOutputHelper testOutputHelper) + { + _testContext = testContext; + _requestAdapterFactory = new TestableHttpClientRequestAdapterFactory(testOutputHelper); + + testContext.UseController(); + + testContext.ConfigureServices(services => services.AddScoped(typeof(IResourceChangeTracker<>), typeof(NeverSameResourceChangeTracker<>))); + + var options = testContext.Factory.Services.GetRequiredService(); + options.SerializerOptions.Converters.Add(new UtcDateTimeJsonConverter()); + options.SerializerOptions.Converters.Add(new TimeSpanAsXmlJsonConverter()); + } + + [Fact] + public async Task Can_create_resource_with_all_attributes_set_to_valid_values() + { + // Arrange + TypeContainer newContainer = _fakers.TypeContainer.GenerateOne(); + newContainer.TestTimeOnly = newContainer.TestTimeOnly.TruncateToWholeSeconds(); + newContainer.TestNullableTimeOnly = newContainer.TestNullableTimeOnly?.TruncateToWholeSeconds(); + + using HttpClientRequestAdapter requestAdapter = _requestAdapterFactory.CreateAdapter(_testContext.Factory); + AttributeTypesClient apiClient = new(requestAdapter); + + var requestBody = new CreateTypeContainerRequestDocument + { + Data = new DataInCreateTypeContainerRequest + { + Type = ResourceType.TypeContainers, + Attributes = new AttributesInCreateTypeContainerRequest + { + TestBoolean = newContainer.TestBoolean, + TestNullableBoolean = newContainer.TestNullableBoolean, + TestByte = newContainer.TestByte, + TestNullableByte = newContainer.TestNullableByte, + TestSignedByte = newContainer.TestSignedByte, + TestNullableSignedByte = newContainer.TestNullableSignedByte, + TestInt16 = newContainer.TestInt16, + TestNullableInt16 = newContainer.TestNullableInt16, + TestUnsignedInt16 = newContainer.TestUnsignedInt16, + TestNullableUnsignedInt16 = newContainer.TestNullableUnsignedInt16, + TestInt32 = newContainer.TestInt32, + TestNullableInt32 = newContainer.TestNullableInt32, + TestUnsignedInt32 = checked((int)newContainer.TestUnsignedInt32), + TestNullableUnsignedInt32 = checked((int?)newContainer.TestNullableUnsignedInt32), + TestInt64 = newContainer.TestInt64, + TestNullableInt64 = newContainer.TestNullableInt64, + TestUnsignedInt64 = checked((long)newContainer.TestUnsignedInt64), + TestNullableUnsignedInt64 = checked((long?)newContainer.TestNullableUnsignedInt64), + TestInt128 = newContainer.TestInt128.ToString(CultureInfo.InvariantCulture), + TestNullableInt128 = newContainer.TestNullableInt128?.ToString(CultureInfo.InvariantCulture), + TestUnsignedInt128 = newContainer.TestUnsignedInt128.ToString(), + TestNullableUnsignedInt128 = newContainer.TestNullableUnsignedInt128?.ToString(), + TestBigInteger = newContainer.TestBigInteger.ToString(CultureInfo.InvariantCulture), + TestNullableBigInteger = newContainer.TestNullableBigInteger?.ToString(CultureInfo.InvariantCulture), + TestHalf = newContainer.TestHalf.AsFloat(), + TestNullableHalf = newContainer.TestNullableHalf?.AsFloat(), + TestFloat = newContainer.TestFloat, + TestNullableFloat = newContainer.TestNullableFloat, + TestDouble = newContainer.TestDouble, + TestNullableDouble = newContainer.TestNullableDouble, + TestDecimal = (double)newContainer.TestDecimal, + TestNullableDecimal = (double?)newContainer.TestNullableDecimal, + TestComplex = newContainer.TestComplex.ToString(CultureInfo.InvariantCulture), + TestNullableComplex = newContainer.TestNullableComplex?.ToString(CultureInfo.InvariantCulture), + TestChar = newContainer.TestChar.ToString(CultureInfo.InvariantCulture), + TestNullableChar = newContainer.TestNullableChar?.ToString(CultureInfo.InvariantCulture), + TestString = newContainer.TestString, + TestNullableString = newContainer.TestNullableString, + TestRune = newContainer.TestRune.ToString(), + TestNullableRune = newContainer.TestNullableRune?.ToString(), + TestDateTimeOffset = newContainer.TestDateTimeOffset, + TestNullableDateTimeOffset = newContainer.TestNullableDateTimeOffset, + TestDateTime = newContainer.TestDateTime, + TestNullableDateTime = newContainer.TestNullableDateTime, + TestDateOnly = newContainer.TestDateOnly, + TestNullableDateOnly = newContainer.TestNullableDateOnly, + TestTimeOnly = newContainer.TestTimeOnly, + TestNullableTimeOnly = newContainer.TestNullableTimeOnly, + TestTimeSpan = newContainer.TestTimeSpan, + TestNullableTimeSpan = newContainer.TestNullableTimeSpan, + TestEnum = MapEnum(newContainer.TestEnum), + TestNullableEnum = MapEnum(newContainer.TestNullableEnum), + TestGuid = newContainer.TestGuid, + TestNullableGuid = newContainer.TestNullableGuid, + TestUri = newContainer.TestUri.ToString(), + TestNullableUri = newContainer.TestNullableUri?.ToString(), + TestIPAddress = newContainer.TestIPAddress.ToString(), + TestNullableIPAddress = newContainer.TestNullableIPAddress?.ToString(), + TestIPNetwork = newContainer.TestIPNetwork.ToString(), + TestNullableIPNetwork = newContainer.TestNullableIPNetwork?.ToString(), + TestVersion = newContainer.TestVersion.ToString(), + TestNullableVersion = newContainer.TestNullableVersion?.ToString() + } + } + }; + + // Act + PrimaryTypeContainerResponseDocument? response = await apiClient.TypeContainers.PostAsync(requestBody); + + // Assert + response.Should().NotBeNull(); + response.Data.Should().NotBeNull(); + response.Data.Attributes.Should().NotBeNull(); + response.Data.Attributes.TestBoolean.Should().Be(newContainer.TestBoolean); + response.Data.Attributes.TestNullableBoolean.Should().Be(newContainer.TestNullableBoolean); + response.Data.Attributes.TestByte.Should().Be(newContainer.TestByte); + response.Data.Attributes.TestNullableByte.Should().Be(newContainer.TestNullableByte); + response.Data.Attributes.TestSignedByte.Should().Be(newContainer.TestSignedByte); + response.Data.Attributes.TestNullableSignedByte.Should().Be(newContainer.TestNullableSignedByte); + response.Data.Attributes.TestInt16.Should().Be(newContainer.TestInt16); + response.Data.Attributes.TestNullableInt16.Should().Be(newContainer.TestNullableInt16); + response.Data.Attributes.TestUnsignedInt16.Should().Be(newContainer.TestUnsignedInt16); + response.Data.Attributes.TestNullableUnsignedInt16.Should().Be(newContainer.TestNullableUnsignedInt16); + response.Data.Attributes.TestInt32.Should().Be(newContainer.TestInt32); + response.Data.Attributes.TestNullableInt32.Should().Be(newContainer.TestNullableInt32); + response.Data.Attributes.TestUnsignedInt32.Should().Be(checked((int)newContainer.TestUnsignedInt32)); + response.Data.Attributes.TestNullableUnsignedInt32.Should().Be(checked((int?)newContainer.TestNullableUnsignedInt32)); + response.Data.Attributes.TestInt64.Should().Be(newContainer.TestInt64); + response.Data.Attributes.TestNullableInt64.Should().Be(newContainer.TestNullableInt64); + response.Data.Attributes.TestUnsignedInt64.Should().Be(checked((long)newContainer.TestUnsignedInt64)); + response.Data.Attributes.TestNullableUnsignedInt64.Should().Be(checked((long?)newContainer.TestNullableUnsignedInt64)); + response.Data.Attributes.TestInt128.Should().Be(newContainer.TestInt128.ToString(CultureInfo.InvariantCulture)); + response.Data.Attributes.TestNullableInt128.Should().Be(newContainer.TestNullableInt128?.ToString(CultureInfo.InvariantCulture)); + response.Data.Attributes.TestUnsignedInt128.Should().Be(newContainer.TestUnsignedInt128.ToString(CultureInfo.InvariantCulture)); + response.Data.Attributes.TestNullableUnsignedInt128.Should().Be(newContainer.TestNullableUnsignedInt128?.ToString(CultureInfo.InvariantCulture)); + response.Data.Attributes.TestBigInteger.Should().Be(newContainer.TestBigInteger.ToString(CultureInfo.InvariantCulture)); + response.Data.Attributes.TestNullableBigInteger.Should().Be(newContainer.TestNullableBigInteger?.ToString(CultureInfo.InvariantCulture)); + response.Data.Attributes.TestHalf.Should().Be(newContainer.TestHalf.AsFloat()); + response.Data.Attributes.TestNullableHalf.Should().Be(newContainer.TestNullableHalf?.AsFloat()); + response.Data.Attributes.TestFloat.Should().Be(newContainer.TestFloat); + response.Data.Attributes.TestNullableFloat.Should().Be(newContainer.TestNullableFloat); + response.Data.Attributes.TestDouble.Should().Be(newContainer.TestDouble); + response.Data.Attributes.TestNullableDouble.Should().Be(newContainer.TestNullableDouble); + response.Data.Attributes.TestDecimal.Should().Be((double)newContainer.TestDecimal); + response.Data.Attributes.TestNullableDecimal.Should().Be((double?)newContainer.TestNullableDecimal); + response.Data.Attributes.TestComplex.Should().Be(newContainer.TestComplex.ToString(CultureInfo.InvariantCulture)); + response.Data.Attributes.TestNullableComplex.Should().Be(newContainer.TestNullableComplex?.ToString(CultureInfo.InvariantCulture)); + response.Data.Attributes.TestChar.Should().Be(newContainer.TestChar.ToString(CultureInfo.InvariantCulture)); + response.Data.Attributes.TestNullableChar.Should().Be(newContainer.TestNullableChar?.ToString(CultureInfo.InvariantCulture)); + response.Data.Attributes.TestString.Should().Be(newContainer.TestString); + response.Data.Attributes.TestNullableString.Should().Be(newContainer.TestNullableString); + response.Data.Attributes.TestRune.Should().Be(newContainer.TestRune.ToString()); + response.Data.Attributes.TestNullableRune.Should().Be(newContainer.TestNullableRune?.ToString()); + response.Data.Attributes.TestDateTimeOffset.Should().Be(newContainer.TestDateTimeOffset); + response.Data.Attributes.TestNullableDateTimeOffset.Should().Be(newContainer.TestNullableDateTimeOffset); + response.Data.Attributes.TestDateTime.Should().Be(newContainer.TestDateTime); + response.Data.Attributes.TestNullableDateTime.Should().Be(newContainer.TestNullableDateTime); + response.Data.Attributes.TestDateOnly.Should().Be((Date)newContainer.TestDateOnly); + response.Data.Attributes.TestNullableDateOnly.Should().Be((Date?)newContainer.TestNullableDateOnly); + response.Data.Attributes.TestTimeOnly.Should().Be((Time)newContainer.TestTimeOnly); + response.Data.Attributes.TestNullableTimeOnly.Should().Be((Time?)newContainer.TestNullableTimeOnly); + response.Data.Attributes.TestTimeSpan.Should().Be(newContainer.TestTimeSpan); + response.Data.Attributes.TestNullableTimeSpan.Should().Be(newContainer.TestNullableTimeSpan); + response.Data.Attributes.TestEnum.Should().Be(MapEnum(newContainer.TestEnum)); + response.Data.Attributes.TestNullableEnum.Should().Be(MapEnum(newContainer.TestNullableEnum)); + response.Data.Attributes.TestGuid.Should().Be(newContainer.TestGuid); + response.Data.Attributes.TestNullableGuid.Should().Be(newContainer.TestNullableGuid); + response.Data.Attributes.TestUri.Should().Be(newContainer.TestUri.ToString()); + response.Data.Attributes.TestNullableUri.Should().Be(newContainer.TestNullableUri?.ToString()); + response.Data.Attributes.TestIPAddress.Should().Be(newContainer.TestIPAddress.ToString()); + response.Data.Attributes.TestNullableIPAddress.Should().Be(newContainer.TestNullableIPAddress?.ToString()); + response.Data.Attributes.TestIPNetwork.Should().Be(newContainer.TestIPNetwork.ToString()); + response.Data.Attributes.TestNullableIPNetwork.Should().Be(newContainer.TestNullableIPNetwork?.ToString()); + response.Data.Attributes.TestVersion.Should().Be(newContainer.TestVersion.ToString()); + response.Data.Attributes.TestNullableVersion.Should().Be(newContainer.TestNullableVersion?.ToString()); + + long newContainerId = long.Parse(response.Data.Id.Should().NotBeNull().And.Subject); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + TypeContainer containerInDatabase = await dbContext.TypeContainers.FirstWithIdAsync(newContainerId); + + containerInDatabase.TestBoolean.Should().Be(newContainer.TestBoolean); + containerInDatabase.TestNullableBoolean.Should().Be(newContainer.TestNullableBoolean); + containerInDatabase.TestByte.Should().Be(newContainer.TestByte); + containerInDatabase.TestNullableByte.Should().Be(newContainer.TestNullableByte); + containerInDatabase.TestSignedByte.Should().Be(newContainer.TestSignedByte); + containerInDatabase.TestNullableSignedByte.Should().Be(newContainer.TestNullableSignedByte); + containerInDatabase.TestInt16.Should().Be(newContainer.TestInt16); + containerInDatabase.TestNullableInt16.Should().Be(newContainer.TestNullableInt16); + containerInDatabase.TestUnsignedInt16.Should().Be(newContainer.TestUnsignedInt16); + containerInDatabase.TestNullableUnsignedInt16.Should().Be(newContainer.TestNullableUnsignedInt16); + containerInDatabase.TestInt32.Should().Be(newContainer.TestInt32); + containerInDatabase.TestNullableInt32.Should().Be(newContainer.TestNullableInt32); + containerInDatabase.TestUnsignedInt32.Should().Be(newContainer.TestUnsignedInt32); + containerInDatabase.TestNullableUnsignedInt32.Should().Be(newContainer.TestNullableUnsignedInt32); + containerInDatabase.TestInt64.Should().Be(newContainer.TestInt64); + containerInDatabase.TestNullableInt64.Should().Be(newContainer.TestNullableInt64); + containerInDatabase.TestUnsignedInt64.Should().Be(newContainer.TestUnsignedInt64); + containerInDatabase.TestNullableUnsignedInt64.Should().Be(newContainer.TestNullableUnsignedInt64); + containerInDatabase.TestInt128.Should().Be(newContainer.TestInt128); + containerInDatabase.TestNullableInt128.Should().Be(newContainer.TestNullableInt128); + containerInDatabase.TestUnsignedInt128.Should().Be(newContainer.TestUnsignedInt128); + containerInDatabase.TestNullableUnsignedInt128.Should().Be(newContainer.TestNullableUnsignedInt128); + containerInDatabase.TestBigInteger.Should().Be(newContainer.TestBigInteger); + containerInDatabase.TestNullableBigInteger.Should().Be(newContainer.TestNullableBigInteger); + containerInDatabase.TestHalf.Should().Be(newContainer.TestHalf); + containerInDatabase.TestNullableHalf.Should().Be(newContainer.TestNullableHalf); + containerInDatabase.TestFloat.Should().Be(newContainer.TestFloat); + containerInDatabase.TestNullableFloat.Should().Be(newContainer.TestNullableFloat); + containerInDatabase.TestDouble.Should().Be(newContainer.TestDouble); + containerInDatabase.TestNullableDouble.Should().Be(newContainer.TestNullableDouble); + containerInDatabase.TestDecimal.Should().Be(newContainer.TestDecimal); + containerInDatabase.TestNullableDecimal.Should().Be(newContainer.TestNullableDecimal); + containerInDatabase.TestComplex.Should().Be(newContainer.TestComplex); + containerInDatabase.TestNullableComplex.Should().Be(newContainer.TestNullableComplex); + containerInDatabase.TestChar.Should().Be(newContainer.TestChar); + containerInDatabase.TestNullableChar.Should().Be(newContainer.TestNullableChar); + containerInDatabase.TestString.Should().Be(newContainer.TestString); + containerInDatabase.TestNullableString.Should().Be(newContainer.TestNullableString); + containerInDatabase.TestRune.Should().Be(newContainer.TestRune); + containerInDatabase.TestNullableRune.Should().Be(newContainer.TestNullableRune); + containerInDatabase.TestDateTimeOffset.Should().Be(newContainer.TestDateTimeOffset); + containerInDatabase.TestNullableDateTimeOffset.Should().Be(newContainer.TestNullableDateTimeOffset); + containerInDatabase.TestDateTime.Should().Be(newContainer.TestDateTime); + containerInDatabase.TestNullableDateTime.Should().Be(newContainer.TestNullableDateTime); + containerInDatabase.TestDateOnly.Should().Be(newContainer.TestDateOnly); + containerInDatabase.TestNullableDateOnly.Should().Be(newContainer.TestNullableDateOnly); + containerInDatabase.TestTimeOnly.Should().Be(newContainer.TestTimeOnly); + containerInDatabase.TestNullableTimeOnly.Should().Be(newContainer.TestNullableTimeOnly); + containerInDatabase.TestTimeSpan.Should().Be(newContainer.TestTimeSpan); + containerInDatabase.TestNullableTimeSpan.Should().Be(newContainer.TestNullableTimeSpan); + containerInDatabase.TestEnum.Should().Be(newContainer.TestEnum); + containerInDatabase.TestNullableEnum.Should().Be(newContainer.TestNullableEnum); + containerInDatabase.TestGuid.Should().Be(newContainer.TestGuid); + containerInDatabase.TestNullableGuid.Should().Be(newContainer.TestNullableGuid); + containerInDatabase.TestUri.Should().Be(newContainer.TestUri); + containerInDatabase.TestNullableUri.Should().Be(newContainer.TestNullableUri); + containerInDatabase.TestIPAddress.Should().Be(newContainer.TestIPAddress); + containerInDatabase.TestNullableIPAddress.Should().Be(newContainer.TestNullableIPAddress); + containerInDatabase.TestIPNetwork.Should().Be(newContainer.TestIPNetwork); + containerInDatabase.TestNullableIPNetwork.Should().Be(newContainer.TestNullableIPNetwork); + containerInDatabase.TestVersion.Should().Be(newContainer.TestVersion); + containerInDatabase.TestNullableVersion.Should().Be(newContainer.TestNullableVersion); + }); + } + + [Fact] + public async Task Can_update_resource_with_nullable_attributes_set_to_null() + { + // Arrange + TypeContainer existingContainer = _fakers.TypeContainer.GenerateOne(); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + dbContext.TypeContainers.Add(existingContainer); + await dbContext.SaveChangesAsync(); + }); + + using HttpClientRequestAdapter requestAdapter = _requestAdapterFactory.CreateAdapter(_testContext.Factory); + AttributeTypesClient apiClient = new(requestAdapter); + + var requestBody = new UpdateTypeContainerRequestDocument + { + Data = new DataInUpdateTypeContainerRequest + { + Type = ResourceType.TypeContainers, + Id = existingContainer.StringId!, + Attributes = new AttributesInUpdateTypeContainerRequest + { + TestNullableBoolean = null, + TestNullableByte = null, + TestNullableSignedByte = null, + TestNullableInt16 = null, + TestNullableUnsignedInt16 = null, + TestNullableInt32 = null, + TestNullableUnsignedInt32 = null, + TestNullableInt64 = null, + TestNullableUnsignedInt64 = null, + TestNullableInt128 = null, + TestNullableUnsignedInt128 = null, + TestNullableBigInteger = null, + TestNullableHalf = null, + TestNullableFloat = null, + TestNullableDouble = null, + TestNullableDecimal = null, + TestNullableComplex = null, + TestNullableChar = null, + TestNullableString = null, + TestNullableRune = null, + TestNullableDateTimeOffset = null, + TestNullableDateTime = null, + TestNullableDateOnly = null, + TestNullableTimeOnly = null, + TestNullableTimeSpan = null, + TestNullableEnum = null, + TestNullableGuid = null, + TestNullableUri = null, + TestNullableIPAddress = null, + TestNullableIPNetwork = null, + TestNullableVersion = null + } + } + }; + + // Act + PrimaryTypeContainerResponseDocument? response = await apiClient.TypeContainers[existingContainer.StringId!].PatchAsync(requestBody); + + // Assert + response.Should().NotBeNull(); + response.Data.Should().NotBeNull(); + response.Data.Attributes.Should().NotBeNull(); + response.Data.Attributes.TestNullableBoolean.Should().BeNull(); + response.Data.Attributes.TestNullableByte.Should().BeNull(); + response.Data.Attributes.TestNullableSignedByte.Should().BeNull(); + response.Data.Attributes.TestNullableInt16.Should().BeNull(); + response.Data.Attributes.TestNullableUnsignedInt16.Should().BeNull(); + response.Data.Attributes.TestNullableInt32.Should().BeNull(); + response.Data.Attributes.TestNullableUnsignedInt32.Should().BeNull(); + response.Data.Attributes.TestNullableInt64.Should().BeNull(); + response.Data.Attributes.TestNullableUnsignedInt64.Should().BeNull(); + response.Data.Attributes.TestNullableInt128.Should().BeNull(); + response.Data.Attributes.TestNullableUnsignedInt128.Should().BeNull(); + response.Data.Attributes.TestNullableBigInteger.Should().BeNull(); + response.Data.Attributes.TestNullableHalf.Should().BeNull(); + response.Data.Attributes.TestNullableFloat.Should().BeNull(); + response.Data.Attributes.TestNullableDouble.Should().BeNull(); + response.Data.Attributes.TestNullableDecimal.Should().BeNull(); + response.Data.Attributes.TestNullableComplex.Should().BeNull(); + response.Data.Attributes.TestNullableChar.Should().BeNull(); + response.Data.Attributes.TestNullableString.Should().BeNull(); + response.Data.Attributes.TestNullableRune.Should().BeNull(); + response.Data.Attributes.TestNullableDateTimeOffset.Should().BeNull(); + response.Data.Attributes.TestNullableDateTime.Should().BeNull(); + response.Data.Attributes.TestNullableDateOnly.Should().BeNull(); + response.Data.Attributes.TestNullableTimeOnly.Should().BeNull(); + response.Data.Attributes.TestNullableTimeSpan.Should().BeNull(); + response.Data.Attributes.TestNullableEnum.Should().BeNull(); + response.Data.Attributes.TestNullableGuid.Should().BeNull(); + response.Data.Attributes.TestNullableUri.Should().BeNull(); + response.Data.Attributes.TestNullableIPAddress.Should().BeNull(); + response.Data.Attributes.TestNullableIPNetwork.Should().BeNull(); + response.Data.Attributes.TestNullableVersion.Should().BeNull(); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + TypeContainer containerInDatabase = await dbContext.TypeContainers.FirstWithIdAsync(existingContainer.Id); + + containerInDatabase.TestNullableBoolean.Should().BeNull(); + containerInDatabase.TestNullableByte.Should().BeNull(); + containerInDatabase.TestNullableSignedByte.Should().BeNull(); + containerInDatabase.TestNullableInt16.Should().BeNull(); + containerInDatabase.TestNullableUnsignedInt16.Should().BeNull(); + containerInDatabase.TestNullableInt32.Should().BeNull(); + containerInDatabase.TestNullableUnsignedInt32.Should().BeNull(); + containerInDatabase.TestNullableInt64.Should().BeNull(); + containerInDatabase.TestNullableUnsignedInt64.Should().BeNull(); + containerInDatabase.TestNullableInt128.Should().BeNull(); + containerInDatabase.TestNullableUnsignedInt128.Should().BeNull(); + containerInDatabase.TestNullableBigInteger.Should().BeNull(); + containerInDatabase.TestNullableHalf.Should().BeNull(); + containerInDatabase.TestNullableFloat.Should().BeNull(); + containerInDatabase.TestNullableDouble.Should().BeNull(); + containerInDatabase.TestNullableDecimal.Should().BeNull(); + containerInDatabase.TestNullableComplex.Should().BeNull(); + containerInDatabase.TestNullableChar.Should().BeNull(); + containerInDatabase.TestNullableString.Should().BeNull(); + containerInDatabase.TestNullableRune.Should().BeNull(); + containerInDatabase.TestNullableDateTimeOffset.Should().BeNull(); + containerInDatabase.TestNullableDateTime.Should().BeNull(); + containerInDatabase.TestNullableDateOnly.Should().BeNull(); + containerInDatabase.TestNullableTimeOnly.Should().BeNull(); + containerInDatabase.TestNullableTimeSpan.Should().BeNull(); + containerInDatabase.TestNullableEnum.Should().BeNull(); + containerInDatabase.TestNullableGuid.Should().BeNull(); + containerInDatabase.TestNullableUri.Should().BeNull(); + containerInDatabase.TestNullableIPAddress.Should().BeNull(); + containerInDatabase.TestNullableIPNetwork.Should().BeNull(); + containerInDatabase.TestNullableVersion.Should().BeNull(); + }); + } + + [Theory] + [InlineData(nameof(TypeContainer.TestBoolean), false)] + [InlineData(nameof(TypeContainer.TestByte), false)] + [InlineData(nameof(TypeContainer.TestSignedByte), false)] + [InlineData(nameof(TypeContainer.TestInt16), false)] + [InlineData(nameof(TypeContainer.TestUnsignedInt16), false)] + [InlineData(nameof(TypeContainer.TestInt32), false)] + [InlineData(nameof(TypeContainer.TestUnsignedInt32), false)] + [InlineData(nameof(TypeContainer.TestInt64), false)] + [InlineData(nameof(TypeContainer.TestUnsignedInt64), false)] + [InlineData(nameof(TypeContainer.TestInt128), false)] + [InlineData(nameof(TypeContainer.TestUnsignedInt128), false)] + [InlineData(nameof(TypeContainer.TestBigInteger), false)] + [InlineData(nameof(TypeContainer.TestHalf), false)] + [InlineData(nameof(TypeContainer.TestFloat), false)] + [InlineData(nameof(TypeContainer.TestDouble), false)] + [InlineData(nameof(TypeContainer.TestDecimal), false)] + [InlineData(nameof(TypeContainer.TestComplex), false)] + [InlineData(nameof(TypeContainer.TestChar), false)] + [InlineData(nameof(TypeContainer.TestString), true)] + [InlineData(nameof(TypeContainer.TestRune), false)] + [InlineData(nameof(TypeContainer.TestDateTimeOffset), false)] + [InlineData(nameof(TypeContainer.TestDateTime), false)] + [InlineData(nameof(TypeContainer.TestDateOnly), false)] + [InlineData(nameof(TypeContainer.TestTimeOnly), false)] + [InlineData(nameof(TypeContainer.TestTimeSpan), false)] + [InlineData(nameof(TypeContainer.TestEnum), false)] + [InlineData(nameof(TypeContainer.TestGuid), false)] + [InlineData(nameof(TypeContainer.TestUri), true)] + [InlineData(nameof(TypeContainer.TestIPAddress), true)] + [InlineData(nameof(TypeContainer.TestIPNetwork), false)] + [InlineData(nameof(TypeContainer.TestVersion), true)] + public async Task Cannot_update_resource_with_attribute_set_to_null(string propertyName, bool failAtModelValidation) + { + // Arrange + TypeContainer existingContainer = _fakers.TypeContainer.GenerateOne(); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + dbContext.TypeContainers.Add(existingContainer); + await dbContext.SaveChangesAsync(); + }); + + using HttpClientRequestAdapter requestAdapter = _requestAdapterFactory.CreateAdapter(_testContext.Factory); + AttributeTypesClient apiClient = new(requestAdapter); + + var requestBody = new UpdateTypeContainerRequestDocument + { + Data = new DataInUpdateTypeContainerRequest + { + Type = ResourceType.TypeContainers, + Id = existingContainer.StringId!, + Attributes = new AttributesInUpdateTypeContainerRequest() + } + }; + + SetAttributeValueInUpdateRequestToNull(requestBody.Data.Attributes, propertyName); + + // Act + Func action = async () => await apiClient.TypeContainers[existingContainer.StringId!].PatchAsync(requestBody); + + // Assert + ErrorResponseDocument exception = (await action.Should().ThrowExactlyAsync()).Which; + exception.ResponseStatusCode.Should().Be((int)HttpStatusCode.UnprocessableEntity); + exception.Message.Should().Be($"Exception of type '{typeof(ErrorResponseDocument).FullName}' was thrown."); + exception.Errors.Should().HaveCount(1); + + ErrorObject error = exception.Errors.ElementAt(0); + error.Status.Should().Be("422"); + + if (failAtModelValidation) + { + error.Title.Should().Be("Input validation failed."); + error.Detail.Should().Be($"The {propertyName} field is required."); + } + else + { + error.Title.Should().Be("Failed to deserialize request body: Incompatible attribute value found."); + error.Detail.Should().Be(GetExpectedConverterErrorMessage(propertyName, null)); + } + + error.Source.Should().NotBeNull(); + error.Source.Pointer.Should().Be($"/data/attributes/{propertyName.Camelize()}"); + } + + [Theory] + [InlineData(nameof(TypeContainer.TestInt128), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableInt128), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestUnsignedInt128), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt128), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestBigInteger), "The value could not be parsed.")] + [InlineData(nameof(TypeContainer.TestNullableBigInteger), "The value could not be parsed.")] + [InlineData(nameof(TypeContainer.TestComplex), "Arithmetic operation resulted in an overflow.")] + [InlineData(nameof(TypeContainer.TestNullableComplex), "Arithmetic operation resulted in an overflow.")] + [InlineData(nameof(TypeContainer.TestIPAddress), "An invalid IP address was specified.")] + [InlineData(nameof(TypeContainer.TestNullableIPAddress), "An invalid IP address was specified.")] + [InlineData(nameof(TypeContainer.TestIPNetwork), "An invalid IP network was specified.")] + [InlineData(nameof(TypeContainer.TestNullableIPNetwork), "An invalid IP network was specified.")] + [InlineData(nameof(TypeContainer.TestVersion), "The JSON value is not in a supported Version format.")] + [InlineData(nameof(TypeContainer.TestNullableVersion), "The JSON value is not in a supported Version format.")] + public async Task Cannot_update_resource_with_attribute_set_to_invalid_value(string propertyName, string innerParseError) + { + // Arrange + TypeContainer existingContainer = _fakers.TypeContainer.GenerateOne(); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + dbContext.TypeContainers.Add(existingContainer); + await dbContext.SaveChangesAsync(); + }); + + using HttpClientRequestAdapter requestAdapter = _requestAdapterFactory.CreateAdapter(_testContext.Factory); + AttributeTypesClient apiClient = new(requestAdapter); + + var requestBody = new UpdateTypeContainerRequestDocument + { + Data = new DataInUpdateTypeContainerRequest + { + Type = ResourceType.TypeContainers, + Id = existingContainer.StringId!, + Attributes = new AttributesInUpdateTypeContainerRequest() + } + }; + + SetAttributeValueInUpdateRequestToInvalid(requestBody.Data.Attributes, propertyName); + + // Act + Func action = async () => await apiClient.TypeContainers[existingContainer.StringId!].PatchAsync(requestBody); + + // Assert + ErrorResponseDocument exception = (await action.Should().ThrowExactlyAsync()).Which; + exception.ResponseStatusCode.Should().Be((int)HttpStatusCode.UnprocessableEntity); + exception.Message.Should().Be($"Exception of type '{typeof(ErrorResponseDocument).FullName}' was thrown."); + exception.Errors.Should().HaveCount(1); + + ErrorObject error = exception.Errors.ElementAt(0); + error.Status.Should().Be("422"); + error.Title.Should().Be("Failed to deserialize request body: Incompatible attribute value found."); + error.Detail.Should().Be(GetExpectedConverterErrorMessage(propertyName, "invalid")); + error.Source.Should().NotBeNull(); + error.Source.Pointer.Should().Be($"/data/attributes/{propertyName.Camelize()}"); + error.Meta.Should().NotBeNull(); + + error.Meta.AdditionalData.Should().ContainKey("stackTrace").WhoseValue.Should().BeOfType().Subject.With(array => + { + string stackTrace = string.Join(Environment.NewLine, array.GetValue().Select(item => item.Should().BeOfType().Subject.GetValue())); + stackTrace.Should().Contain(innerParseError); + }); + } + + [Theory] + [InlineData(nameof(TypeContainer.TestBoolean))] + [InlineData(nameof(TypeContainer.TestNullableBoolean))] + [InlineData(nameof(TypeContainer.TestByte))] + [InlineData(nameof(TypeContainer.TestNullableByte))] + [InlineData(nameof(TypeContainer.TestSignedByte))] + [InlineData(nameof(TypeContainer.TestNullableSignedByte))] + [InlineData(nameof(TypeContainer.TestInt16))] + [InlineData(nameof(TypeContainer.TestNullableInt16))] + [InlineData(nameof(TypeContainer.TestUnsignedInt16))] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt16))] + [InlineData(nameof(TypeContainer.TestInt32))] + [InlineData(nameof(TypeContainer.TestNullableInt32))] + [InlineData(nameof(TypeContainer.TestUnsignedInt32))] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt32))] + [InlineData(nameof(TypeContainer.TestInt64))] + [InlineData(nameof(TypeContainer.TestNullableInt64))] + [InlineData(nameof(TypeContainer.TestUnsignedInt64))] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt64))] + [InlineData(nameof(TypeContainer.TestInt128))] + [InlineData(nameof(TypeContainer.TestNullableInt128))] + [InlineData(nameof(TypeContainer.TestUnsignedInt128))] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt128))] + [InlineData(nameof(TypeContainer.TestBigInteger))] + [InlineData(nameof(TypeContainer.TestNullableBigInteger))] + [InlineData(nameof(TypeContainer.TestHalf))] + [InlineData(nameof(TypeContainer.TestNullableHalf))] + [InlineData(nameof(TypeContainer.TestFloat))] + [InlineData(nameof(TypeContainer.TestNullableFloat))] + [InlineData(nameof(TypeContainer.TestDouble))] + [InlineData(nameof(TypeContainer.TestNullableDouble))] + [InlineData(nameof(TypeContainer.TestDecimal))] + [InlineData(nameof(TypeContainer.TestNullableDecimal))] + [InlineData(nameof(TypeContainer.TestComplex))] + [InlineData(nameof(TypeContainer.TestNullableComplex))] + [InlineData(nameof(TypeContainer.TestChar))] + [InlineData(nameof(TypeContainer.TestNullableChar))] + [InlineData(nameof(TypeContainer.TestString))] + [InlineData(nameof(TypeContainer.TestNullableString))] + [InlineData(nameof(TypeContainer.TestRune))] + [InlineData(nameof(TypeContainer.TestNullableRune))] + [InlineData(nameof(TypeContainer.TestDateTimeOffset))] + [InlineData(nameof(TypeContainer.TestNullableDateTimeOffset))] + [InlineData(nameof(TypeContainer.TestDateTime))] + [InlineData(nameof(TypeContainer.TestNullableDateTime))] + [InlineData(nameof(TypeContainer.TestDateOnly))] + [InlineData(nameof(TypeContainer.TestNullableDateOnly))] + [InlineData(nameof(TypeContainer.TestTimeOnly))] + [InlineData(nameof(TypeContainer.TestNullableTimeOnly))] + [InlineData(nameof(TypeContainer.TestTimeSpan))] + [InlineData(nameof(TypeContainer.TestNullableTimeSpan))] + [InlineData(nameof(TypeContainer.TestEnum))] + [InlineData(nameof(TypeContainer.TestNullableEnum))] + [InlineData(nameof(TypeContainer.TestGuid))] + [InlineData(nameof(TypeContainer.TestNullableGuid))] + [InlineData(nameof(TypeContainer.TestUri))] + [InlineData(nameof(TypeContainer.TestNullableUri))] + [InlineData(nameof(TypeContainer.TestIPAddress))] + [InlineData(nameof(TypeContainer.TestNullableIPAddress))] + [InlineData(nameof(TypeContainer.TestIPNetwork))] + [InlineData(nameof(TypeContainer.TestNullableIPNetwork))] + [InlineData(nameof(TypeContainer.TestVersion))] + [InlineData(nameof(TypeContainer.TestNullableVersion))] + public async Task Can_filter_with_valid_value(string propertyName) + { + // Arrange + TypeContainer existingContainer = _fakers.TypeContainer.GenerateOne(); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + await dbContext.ClearTableAsync(); + dbContext.TypeContainers.Add(existingContainer); + await dbContext.SaveChangesAsync(); + }); + + using HttpClientRequestAdapter requestAdapter = _requestAdapterFactory.CreateAdapter(_testContext.Factory); + AttributeTypesClient apiClient = new(requestAdapter); + + string filterValue = GetFilterValue(existingContainer, propertyName); + + using IDisposable scope = _requestAdapterFactory.WithQueryString(new Dictionary + { + ["filter"] = $"equals({propertyName.Camelize()},'{filterValue}')" + }); + + // Act + TypeContainerCollectionResponseDocument? response = await apiClient.TypeContainers.GetAsync(); + + // Assert + response.Should().NotBeNull(); + response.Data.Should().HaveCount(1); + response.Data.ElementAt(0).Id.Should().Be(existingContainer.StringId); + } + + [Theory] + [InlineData(nameof(TypeContainer.TestNullableBoolean))] + [InlineData(nameof(TypeContainer.TestNullableByte))] + [InlineData(nameof(TypeContainer.TestNullableSignedByte))] + [InlineData(nameof(TypeContainer.TestNullableInt16))] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt16))] + [InlineData(nameof(TypeContainer.TestNullableInt32))] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt32))] + [InlineData(nameof(TypeContainer.TestNullableInt64))] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt64))] + [InlineData(nameof(TypeContainer.TestNullableInt128))] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt128))] + [InlineData(nameof(TypeContainer.TestNullableBigInteger))] + [InlineData(nameof(TypeContainer.TestNullableHalf))] + [InlineData(nameof(TypeContainer.TestNullableFloat))] + [InlineData(nameof(TypeContainer.TestNullableDouble))] + [InlineData(nameof(TypeContainer.TestNullableDecimal))] + [InlineData(nameof(TypeContainer.TestNullableComplex))] + [InlineData(nameof(TypeContainer.TestNullableChar))] + [InlineData(nameof(TypeContainer.TestNullableString))] + [InlineData(nameof(TypeContainer.TestNullableRune))] + [InlineData(nameof(TypeContainer.TestNullableDateTimeOffset))] + [InlineData(nameof(TypeContainer.TestNullableDateTime))] + [InlineData(nameof(TypeContainer.TestNullableDateOnly))] + [InlineData(nameof(TypeContainer.TestNullableTimeOnly))] + [InlineData(nameof(TypeContainer.TestNullableTimeSpan))] + [InlineData(nameof(TypeContainer.TestNullableEnum))] + [InlineData(nameof(TypeContainer.TestNullableGuid))] + [InlineData(nameof(TypeContainer.TestNullableUri))] + [InlineData(nameof(TypeContainer.TestNullableIPAddress))] + [InlineData(nameof(TypeContainer.TestNullableIPNetwork))] + [InlineData(nameof(TypeContainer.TestNullableVersion))] + public async Task Can_filter_with_null_value(string propertyName) + { + // Arrange + TypeContainer existingContainer = _fakers.TypeContainer.GenerateOne(); + SetResourcePropertyValueToNull(existingContainer, propertyName); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + await dbContext.ClearTableAsync(); + dbContext.TypeContainers.Add(existingContainer); + await dbContext.SaveChangesAsync(); + }); + + using HttpClientRequestAdapter requestAdapter = _requestAdapterFactory.CreateAdapter(_testContext.Factory); + AttributeTypesClient apiClient = new(requestAdapter); + + using IDisposable scope = _requestAdapterFactory.WithQueryString(new Dictionary + { + ["filter"] = $"equals({propertyName.Camelize()},null)" + }); + + // Act + TypeContainerCollectionResponseDocument? response = await apiClient.TypeContainers.GetAsync(); + + // Assert + response.Should().NotBeNull(); + response.Data.Should().HaveCount(1); + response.Data.ElementAt(0).Id.Should().Be(existingContainer.StringId); + } + + [Theory] + [InlineData(nameof(TypeContainer.TestBoolean))] + [InlineData(nameof(TypeContainer.TestByte))] + [InlineData(nameof(TypeContainer.TestSignedByte))] + [InlineData(nameof(TypeContainer.TestInt16))] + [InlineData(nameof(TypeContainer.TestUnsignedInt16))] + [InlineData(nameof(TypeContainer.TestInt32))] + [InlineData(nameof(TypeContainer.TestUnsignedInt32))] + [InlineData(nameof(TypeContainer.TestInt64))] + [InlineData(nameof(TypeContainer.TestUnsignedInt64))] + [InlineData(nameof(TypeContainer.TestInt128))] + [InlineData(nameof(TypeContainer.TestUnsignedInt128))] + [InlineData(nameof(TypeContainer.TestBigInteger))] + [InlineData(nameof(TypeContainer.TestHalf))] + [InlineData(nameof(TypeContainer.TestFloat))] + [InlineData(nameof(TypeContainer.TestDouble))] + [InlineData(nameof(TypeContainer.TestDecimal))] + [InlineData(nameof(TypeContainer.TestComplex))] + [InlineData(nameof(TypeContainer.TestChar))] + [InlineData(nameof(TypeContainer.TestRune))] + [InlineData(nameof(TypeContainer.TestDateTimeOffset))] + [InlineData(nameof(TypeContainer.TestDateTime))] + [InlineData(nameof(TypeContainer.TestDateOnly))] + [InlineData(nameof(TypeContainer.TestTimeOnly))] + [InlineData(nameof(TypeContainer.TestTimeSpan))] + [InlineData(nameof(TypeContainer.TestEnum))] + [InlineData(nameof(TypeContainer.TestGuid))] + [InlineData(nameof(TypeContainer.TestIPNetwork))] + public async Task Cannot_filter_with_null_value(string propertyName) + { + // Arrange + using HttpClientRequestAdapter requestAdapter = _requestAdapterFactory.CreateAdapter(_testContext.Factory); + AttributeTypesClient apiClient = new(requestAdapter); + + using IDisposable scope = _requestAdapterFactory.WithQueryString(new Dictionary + { + ["filter"] = $"equals({propertyName.Camelize()},null)" + }); + + // Act + Func action = async () => await apiClient.TypeContainers.GetAsync(); + + // Assert + ErrorResponseDocument exception = (await action.Should().ThrowExactlyAsync()).Which; + exception.ResponseStatusCode.Should().Be((int)HttpStatusCode.BadRequest); + exception.Message.Should().Be($"Exception of type '{typeof(ErrorResponseDocument).FullName}' was thrown."); + exception.Errors.Should().HaveCount(1); + + ErrorObject error = exception.Errors.ElementAt(0); + error.Status.Should().Be("400"); + error.Title.Should().Be("The specified filter is invalid."); + error.Detail.Should().StartWith("Function, field name or value between quotes expected. Failed at position"); + error.Source.Should().NotBeNull(); + error.Source.Parameter.Should().Be("filter"); + } + + [Theory] + [InlineData(nameof(TypeContainer.TestBoolean), "String 'invalid' was not recognized as a valid Boolean.")] + [InlineData(nameof(TypeContainer.TestNullableBoolean), "String 'invalid' was not recognized as a valid Boolean.")] + [InlineData(nameof(TypeContainer.TestByte), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableByte), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestSignedByte), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableSignedByte), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestInt16), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableInt16), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestUnsignedInt16), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt16), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestInt32), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableInt32), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestUnsignedInt32), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt32), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestInt64), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableInt64), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestUnsignedInt64), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt64), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestInt128), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableInt128), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestUnsignedInt128), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt128), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestBigInteger), "The value could not be parsed.")] + [InlineData(nameof(TypeContainer.TestNullableBigInteger), "The value could not be parsed.")] + [InlineData(nameof(TypeContainer.TestHalf), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableHalf), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestFloat), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableFloat), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestDouble), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableDouble), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestDecimal), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableDecimal), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestComplex), "Arithmetic operation resulted in an overflow.")] + [InlineData(nameof(TypeContainer.TestNullableComplex), "Arithmetic operation resulted in an overflow.")] + [InlineData(nameof(TypeContainer.TestChar), "String must be exactly one character long.")] + [InlineData(nameof(TypeContainer.TestNullableChar), "String must be exactly one character long.")] + [InlineData(nameof(TypeContainer.TestDateTimeOffset), "The string 'invalid' was not recognized as a valid DateTime.")] + [InlineData(nameof(TypeContainer.TestNullableDateTimeOffset), "The string 'invalid' was not recognized as a valid DateTime.")] + [InlineData(nameof(TypeContainer.TestDateTime), "The string 'invalid' was not recognized as a valid DateTime.")] + [InlineData(nameof(TypeContainer.TestNullableDateTime), "The string 'invalid' was not recognized as a valid DateTime.")] + [InlineData(nameof(TypeContainer.TestDateOnly), "String 'invalid' was not recognized as a valid DateOnly.")] + [InlineData(nameof(TypeContainer.TestNullableDateOnly), "String 'invalid' was not recognized as a valid DateOnly.")] + [InlineData(nameof(TypeContainer.TestTimeOnly), "String 'invalid' was not recognized as a valid TimeOnly.")] + [InlineData(nameof(TypeContainer.TestNullableTimeOnly), "String 'invalid' was not recognized as a valid TimeOnly.")] + [InlineData(nameof(TypeContainer.TestTimeSpan), "String 'invalid' was not recognized as a valid TimeSpan.")] + [InlineData(nameof(TypeContainer.TestNullableTimeSpan), "String 'invalid' was not recognized as a valid TimeSpan.")] + [InlineData(nameof(TypeContainer.TestEnum), "Requested value 'invalid' was not found.")] + [InlineData(nameof(TypeContainer.TestNullableEnum), "Requested value 'invalid' was not found.")] + [InlineData(nameof(TypeContainer.TestGuid), "Unrecognized Guid format.")] + [InlineData(nameof(TypeContainer.TestNullableGuid), "Unrecognized Guid format.")] + [InlineData(nameof(TypeContainer.TestUri), "Invalid URI: The format of the URI could not be determined.")] + [InlineData(nameof(TypeContainer.TestNullableUri), "Invalid URI: The format of the URI could not be determined.")] + [InlineData(nameof(TypeContainer.TestIPAddress), "An invalid IP address was specified.")] + [InlineData(nameof(TypeContainer.TestNullableIPAddress), "An invalid IP address was specified.")] + [InlineData(nameof(TypeContainer.TestIPNetwork), "An invalid IP network was specified.")] + [InlineData(nameof(TypeContainer.TestNullableIPNetwork), "An invalid IP network was specified.")] + [InlineData(nameof(TypeContainer.TestVersion), "Version string portion was too short or too long.")] + [InlineData(nameof(TypeContainer.TestNullableVersion), "Version string portion was too short or too long.")] + public async Task Cannot_filter_with_invalid_value(string propertyName, string innerParseError) + { + // Arrange + using HttpClientRequestAdapter requestAdapter = _requestAdapterFactory.CreateAdapter(_testContext.Factory); + AttributeTypesClient apiClient = new(requestAdapter); + + using IDisposable scope = _requestAdapterFactory.WithQueryString(new Dictionary + { + ["filter"] = $"equals({propertyName.Camelize()},'invalid')" + }); + + // Act + Func action = async () => await apiClient.TypeContainers.GetAsync(); + + // Assert + ErrorResponseDocument exception = (await action.Should().ThrowExactlyAsync()).Which; + exception.ResponseStatusCode.Should().Be((int)HttpStatusCode.BadRequest); + exception.Message.Should().Be($"Exception of type '{typeof(ErrorResponseDocument).FullName}' was thrown."); + exception.Errors.Should().HaveCount(1); + + ErrorObject error = exception.Errors.ElementAt(0); + error.Status.Should().Be("400"); + error.Title.Should().Be("The specified filter is invalid."); + error.Detail.Should().StartWith($"{GetExpectedQueryStringErrorMessage(propertyName, "invalid")} Failed at position"); + error.Source.Should().NotBeNull(); + error.Source.Parameter.Should().Be("filter"); + error.Meta.Should().NotBeNull(); + + error.Meta.AdditionalData.Should().ContainKey("stackTrace").WhoseValue.Should().BeOfType().Subject.With(array => + { + string stackTrace = string.Join(Environment.NewLine, array.GetValue().Select(item => item.Should().BeOfType().Subject.GetValue())); + stackTrace.Should().Contain(innerParseError); + }); + } + + private static void SetAttributeValueInUpdateRequestToNull(AttributesInUpdateTypeContainerRequest attributes, string propertyName) + { + MethodInfo? propertySetter = typeof(AttributesInUpdateTypeContainerRequest).GetProperty(propertyName)?.SetMethod; + + if (propertySetter == null) + { + throw new InvalidOperationException($"Unknown property '{propertyName}'."); + } + + propertySetter.Invoke(attributes, [null]); + } + + private static void SetAttributeValueInUpdateRequestToInvalid(AttributesInUpdateTypeContainerRequest attributes, string propertyName) + { + MethodInfo? propertySetter = typeof(AttributesInUpdateTypeContainerRequest).GetProperty(propertyName)?.SetMethod; + + if (propertySetter == null) + { + throw new InvalidOperationException($"Unknown property '{propertyName}'."); + } + + propertySetter.Invoke(attributes, ["invalid"]); + } + + private static void SetResourcePropertyValueToNull(TypeContainer container, string propertyName) + { + PropertyInfo? property = typeof(TypeContainer).GetProperty(propertyName); + + if (property?.SetMethod == null) + { + throw new InvalidOperationException($"Unknown property '{propertyName}'."); + } + + object? typedValue = RuntimeTypeConverter.GetDefaultValue(property.PropertyType); + property.SetMethod.Invoke(container, [typedValue]); + } + + private static string GetFilterValue(TypeContainer container, string propertyName) + { + PropertyInfo? property = typeof(TypeContainer).GetProperty(propertyName); + + if (property?.GetMethod == null) + { + throw new InvalidOperationException($"Unknown property '{propertyName}'."); + } + + object? typedValue = property.GetMethod.Invoke(container, []); + + if (typedValue == null) + { + throw new InvalidOperationException($"Property '{propertyName}' is null."); + } + + Func? converter = TypeConverterRegistry.Instance.FindToStringConverter(property.PropertyType); + return converter != null ? converter(typedValue) : (string)RuntimeTypeConverter.ConvertType(typedValue, typeof(string))!; + } + + private static string GetExpectedConverterErrorMessage(string propertyName, string? actualValue) + { + PropertyInfo? property = typeof(TypeContainer).GetProperty(propertyName); + + if (property == null) + { + throw new InvalidOperationException($"Unknown property '{propertyName}'."); + } + + string propertyType = RuntimeTypeConverter.GetFriendlyTypeName(property.PropertyType); + string jsonType = actualValue == null ? "Null" : "String"; + return $"Failed to convert attribute '{propertyName.Camelize()}' with value '{actualValue}' of type '{jsonType}' to type '{propertyType}'."; + } + + private static string GetExpectedQueryStringErrorMessage(string propertyName, string actualValue) + { + PropertyInfo? property = typeof(TypeContainer).GetProperty(propertyName); + + if (property == null) + { + throw new InvalidOperationException($"Unknown property '{propertyName}'."); + } + + string propertyType = RuntimeTypeConverter.GetFriendlyTypeName(property.PropertyType); + return $"Failed to convert '{actualValue}' of type 'String' to type '{propertyType}'."; + } + + [return: NotNullIfNotNull(nameof(fromEnum))] + private static TToEnum? MapEnum(TFromEnum? fromEnum) + where TFromEnum : struct, Enum + where TToEnum : struct, Enum + { + if (fromEnum == null) + { + return default(TToEnum); + } + + string stringValue = fromEnum.Value.ToString("G"); + return Enum.Parse(stringValue, false); + } + + public void Dispose() + { + _requestAdapterFactory.Dispose(); + } +} diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/AttributeTypesClient.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/AttributeTypesClient.cs new file mode 100644 index 0000000000..df5afbe780 --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/AttributeTypesClient.cs @@ -0,0 +1,54 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Store; +using Microsoft.Kiota.Abstractions; +using Microsoft.Kiota.Serialization.Form; +using Microsoft.Kiota.Serialization.Json; +using Microsoft.Kiota.Serialization.Multipart; +using Microsoft.Kiota.Serialization.Text; +using OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.TypeContainers; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode +{ + /// + /// The main entry point of the SDK, exposes the configuration and the fluent API. + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class AttributeTypesClient : BaseRequestBuilder + { + /// The typeContainers property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.TypeContainers.TypeContainersRequestBuilder TypeContainers + { + get => new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.TypeContainers.TypeContainersRequestBuilder(PathParameters, RequestAdapter); + } + + /// + /// Instantiates a new and sets the default values. + /// + /// The backing store to use for the models. + /// The request adapter to use to execute the requests. + public AttributeTypesClient(IRequestAdapter requestAdapter, IBackingStoreFactory backingStore = default) : base(requestAdapter, "{+baseurl}", new Dictionary()) + { + ApiClientBuilder.RegisterDefaultSerializer(); + ApiClientBuilder.RegisterDefaultSerializer(); + ApiClientBuilder.RegisterDefaultSerializer(); + ApiClientBuilder.RegisterDefaultSerializer(); + ApiClientBuilder.RegisterDefaultDeserializer(); + ApiClientBuilder.RegisterDefaultDeserializer(); + ApiClientBuilder.RegisterDefaultDeserializer(); + if (string.IsNullOrEmpty(RequestAdapter.BaseUrl)) + { + RequestAdapter.BaseUrl = "http://localhost"; + } + PathParameters.TryAdd("baseurl", RequestAdapter.BaseUrl); + RequestAdapter.EnableBackingStore(backingStore); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/AttributesInCreateRequest.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/AttributesInCreateRequest.cs new file mode 100644 index 0000000000..d281130fc3 --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/AttributesInCreateRequest.cs @@ -0,0 +1,75 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions.Store; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class AttributesInCreateRequest : IBackedModel, IParsable + #pragma warning restore CS1591 + { + /// Stores model information. + public IBackingStore BackingStore { get; private set; } + + /// The openapiDiscriminator property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceType? OpenapiDiscriminator + { + get { return BackingStore?.Get("openapi:discriminator"); } + set { BackingStore?.Set("openapi:discriminator", value); } + } + + /// + /// Instantiates a new and sets the default values. + /// + public AttributesInCreateRequest() + { + BackingStore = BackingStoreFactorySingleton.Instance.CreateBackingStore(); + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.AttributesInCreateRequest CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + var mappingValue = parseNode.GetChildNode("openapi:discriminator")?.GetStringValue(); + return mappingValue switch + { + "typeContainers" => new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.AttributesInCreateTypeContainerRequest(), + _ => new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.AttributesInCreateRequest(), + }; + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "openapi:discriminator", n => { OpenapiDiscriminator = n.GetEnumValue(); } }, + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteEnumValue("openapi:discriminator", OpenapiDiscriminator); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/AttributesInCreateTypeContainerRequest.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/AttributesInCreateTypeContainerRequest.cs new file mode 100644 index 0000000000..ef5aee9c4b --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/AttributesInCreateTypeContainerRequest.cs @@ -0,0 +1,609 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class AttributesInCreateTypeContainerRequest : global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.AttributesInCreateRequest, IParsable + #pragma warning restore CS1591 + { + /// The testBigInteger property + public string? TestBigInteger + { + get { return BackingStore?.Get("testBigInteger"); } + set { BackingStore?.Set("testBigInteger", value); } + } + + /// The testBoolean property + public bool? TestBoolean + { + get { return BackingStore?.Get("testBoolean"); } + set { BackingStore?.Set("testBoolean", value); } + } + + /// The testByte property + public int? TestByte + { + get { return BackingStore?.Get("testByte"); } + set { BackingStore?.Set("testByte", value); } + } + + /// The testChar property + public string? TestChar + { + get { return BackingStore?.Get("testChar"); } + set { BackingStore?.Set("testChar", value); } + } + + /// The testComplex property + public string? TestComplex + { + get { return BackingStore?.Get("testComplex"); } + set { BackingStore?.Set("testComplex", value); } + } + + /// The testDateOnly property + public Date? TestDateOnly + { + get { return BackingStore?.Get("testDateOnly"); } + set { BackingStore?.Set("testDateOnly", value); } + } + + /// The testDateTime property + public DateTimeOffset? TestDateTime + { + get { return BackingStore?.Get("testDateTime"); } + set { BackingStore?.Set("testDateTime", value); } + } + + /// The testDateTimeOffset property + public DateTimeOffset? TestDateTimeOffset + { + get { return BackingStore?.Get("testDateTimeOffset"); } + set { BackingStore?.Set("testDateTimeOffset", value); } + } + + /// The testDecimal property + public double? TestDecimal + { + get { return BackingStore?.Get("testDecimal"); } + set { BackingStore?.Set("testDecimal", value); } + } + + /// The testDouble property + public double? TestDouble + { + get { return BackingStore?.Get("testDouble"); } + set { BackingStore?.Set("testDouble", value); } + } + + /// The testEnum property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.DayOfWeekObject? TestEnum + { + get { return BackingStore?.Get("testEnum"); } + set { BackingStore?.Set("testEnum", value); } + } + + /// The testFloat property + public float? TestFloat + { + get { return BackingStore?.Get("testFloat"); } + set { BackingStore?.Set("testFloat", value); } + } + + /// The testGuid property + public Guid? TestGuid + { + get { return BackingStore?.Get("testGuid"); } + set { BackingStore?.Set("testGuid", value); } + } + + /// The testHalf property + public float? TestHalf + { + get { return BackingStore?.Get("testHalf"); } + set { BackingStore?.Set("testHalf", value); } + } + + /// The testInt128 property + public string? TestInt128 + { + get { return BackingStore?.Get("testInt128"); } + set { BackingStore?.Set("testInt128", value); } + } + + /// The testInt16 property + public int? TestInt16 + { + get { return BackingStore?.Get("testInt16"); } + set { BackingStore?.Set("testInt16", value); } + } + + /// The testInt32 property + public int? TestInt32 + { + get { return BackingStore?.Get("testInt32"); } + set { BackingStore?.Set("testInt32", value); } + } + + /// The testInt64 property + public long? TestInt64 + { + get { return BackingStore?.Get("testInt64"); } + set { BackingStore?.Set("testInt64", value); } + } + + /// The testIPAddress property + public string? TestIPAddress + { + get { return BackingStore?.Get("testIPAddress"); } + set { BackingStore?.Set("testIPAddress", value); } + } + + /// The testIPNetwork property + public string? TestIPNetwork + { + get { return BackingStore?.Get("testIPNetwork"); } + set { BackingStore?.Set("testIPNetwork", value); } + } + + /// The testNullableBigInteger property + public string? TestNullableBigInteger + { + get { return BackingStore?.Get("testNullableBigInteger"); } + set { BackingStore?.Set("testNullableBigInteger", value); } + } + + /// The testNullableBoolean property + public bool? TestNullableBoolean + { + get { return BackingStore?.Get("testNullableBoolean"); } + set { BackingStore?.Set("testNullableBoolean", value); } + } + + /// The testNullableByte property + public int? TestNullableByte + { + get { return BackingStore?.Get("testNullableByte"); } + set { BackingStore?.Set("testNullableByte", value); } + } + + /// The testNullableChar property + public string? TestNullableChar + { + get { return BackingStore?.Get("testNullableChar"); } + set { BackingStore?.Set("testNullableChar", value); } + } + + /// The testNullableComplex property + public string? TestNullableComplex + { + get { return BackingStore?.Get("testNullableComplex"); } + set { BackingStore?.Set("testNullableComplex", value); } + } + + /// The testNullableDateOnly property + public Date? TestNullableDateOnly + { + get { return BackingStore?.Get("testNullableDateOnly"); } + set { BackingStore?.Set("testNullableDateOnly", value); } + } + + /// The testNullableDateTime property + public DateTimeOffset? TestNullableDateTime + { + get { return BackingStore?.Get("testNullableDateTime"); } + set { BackingStore?.Set("testNullableDateTime", value); } + } + + /// The testNullableDateTimeOffset property + public DateTimeOffset? TestNullableDateTimeOffset + { + get { return BackingStore?.Get("testNullableDateTimeOffset"); } + set { BackingStore?.Set("testNullableDateTimeOffset", value); } + } + + /// The testNullableDecimal property + public double? TestNullableDecimal + { + get { return BackingStore?.Get("testNullableDecimal"); } + set { BackingStore?.Set("testNullableDecimal", value); } + } + + /// The testNullableDouble property + public double? TestNullableDouble + { + get { return BackingStore?.Get("testNullableDouble"); } + set { BackingStore?.Set("testNullableDouble", value); } + } + + /// The testNullableEnum property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.DayOfWeekObject? TestNullableEnum + { + get { return BackingStore?.Get("testNullableEnum"); } + set { BackingStore?.Set("testNullableEnum", value); } + } + + /// The testNullableFloat property + public float? TestNullableFloat + { + get { return BackingStore?.Get("testNullableFloat"); } + set { BackingStore?.Set("testNullableFloat", value); } + } + + /// The testNullableGuid property + public Guid? TestNullableGuid + { + get { return BackingStore?.Get("testNullableGuid"); } + set { BackingStore?.Set("testNullableGuid", value); } + } + + /// The testNullableHalf property + public float? TestNullableHalf + { + get { return BackingStore?.Get("testNullableHalf"); } + set { BackingStore?.Set("testNullableHalf", value); } + } + + /// The testNullableInt128 property + public string? TestNullableInt128 + { + get { return BackingStore?.Get("testNullableInt128"); } + set { BackingStore?.Set("testNullableInt128", value); } + } + + /// The testNullableInt16 property + public int? TestNullableInt16 + { + get { return BackingStore?.Get("testNullableInt16"); } + set { BackingStore?.Set("testNullableInt16", value); } + } + + /// The testNullableInt32 property + public int? TestNullableInt32 + { + get { return BackingStore?.Get("testNullableInt32"); } + set { BackingStore?.Set("testNullableInt32", value); } + } + + /// The testNullableInt64 property + public long? TestNullableInt64 + { + get { return BackingStore?.Get("testNullableInt64"); } + set { BackingStore?.Set("testNullableInt64", value); } + } + + /// The testNullableIPAddress property + public string? TestNullableIPAddress + { + get { return BackingStore?.Get("testNullableIPAddress"); } + set { BackingStore?.Set("testNullableIPAddress", value); } + } + + /// The testNullableIPNetwork property + public string? TestNullableIPNetwork + { + get { return BackingStore?.Get("testNullableIPNetwork"); } + set { BackingStore?.Set("testNullableIPNetwork", value); } + } + + /// The testNullableRune property + public string? TestNullableRune + { + get { return BackingStore?.Get("testNullableRune"); } + set { BackingStore?.Set("testNullableRune", value); } + } + + /// The testNullableSignedByte property + public int? TestNullableSignedByte + { + get { return BackingStore?.Get("testNullableSignedByte"); } + set { BackingStore?.Set("testNullableSignedByte", value); } + } + + /// The testNullableString property + public string? TestNullableString + { + get { return BackingStore?.Get("testNullableString"); } + set { BackingStore?.Set("testNullableString", value); } + } + + /// The testNullableTimeOnly property + public Time? TestNullableTimeOnly + { + get { return BackingStore?.Get("testNullableTimeOnly"); } + set { BackingStore?.Set("testNullableTimeOnly", value); } + } + + /// The testNullableTimeSpan property + public TimeSpan? TestNullableTimeSpan + { + get { return BackingStore?.Get("testNullableTimeSpan"); } + set { BackingStore?.Set("testNullableTimeSpan", value); } + } + + /// The testNullableUnsignedInt128 property + public string? TestNullableUnsignedInt128 + { + get { return BackingStore?.Get("testNullableUnsignedInt128"); } + set { BackingStore?.Set("testNullableUnsignedInt128", value); } + } + + /// The testNullableUnsignedInt16 property + public int? TestNullableUnsignedInt16 + { + get { return BackingStore?.Get("testNullableUnsignedInt16"); } + set { BackingStore?.Set("testNullableUnsignedInt16", value); } + } + + /// The testNullableUnsignedInt32 property + public int? TestNullableUnsignedInt32 + { + get { return BackingStore?.Get("testNullableUnsignedInt32"); } + set { BackingStore?.Set("testNullableUnsignedInt32", value); } + } + + /// The testNullableUnsignedInt64 property + public long? TestNullableUnsignedInt64 + { + get { return BackingStore?.Get("testNullableUnsignedInt64"); } + set { BackingStore?.Set("testNullableUnsignedInt64", value); } + } + + /// The testNullableUri property + public string? TestNullableUri + { + get { return BackingStore?.Get("testNullableUri"); } + set { BackingStore?.Set("testNullableUri", value); } + } + + /// The testNullableVersion property + public string? TestNullableVersion + { + get { return BackingStore?.Get("testNullableVersion"); } + set { BackingStore?.Set("testNullableVersion", value); } + } + + /// The testRune property + public string? TestRune + { + get { return BackingStore?.Get("testRune"); } + set { BackingStore?.Set("testRune", value); } + } + + /// The testSignedByte property + public int? TestSignedByte + { + get { return BackingStore?.Get("testSignedByte"); } + set { BackingStore?.Set("testSignedByte", value); } + } + + /// The testString property + public string? TestString + { + get { return BackingStore?.Get("testString"); } + set { BackingStore?.Set("testString", value); } + } + + /// The testTimeOnly property + public Time? TestTimeOnly + { + get { return BackingStore?.Get("testTimeOnly"); } + set { BackingStore?.Set("testTimeOnly", value); } + } + + /// The testTimeSpan property + public TimeSpan? TestTimeSpan + { + get { return BackingStore?.Get("testTimeSpan"); } + set { BackingStore?.Set("testTimeSpan", value); } + } + + /// The testUnsignedInt128 property + public string? TestUnsignedInt128 + { + get { return BackingStore?.Get("testUnsignedInt128"); } + set { BackingStore?.Set("testUnsignedInt128", value); } + } + + /// The testUnsignedInt16 property + public int? TestUnsignedInt16 + { + get { return BackingStore?.Get("testUnsignedInt16"); } + set { BackingStore?.Set("testUnsignedInt16", value); } + } + + /// The testUnsignedInt32 property + public int? TestUnsignedInt32 + { + get { return BackingStore?.Get("testUnsignedInt32"); } + set { BackingStore?.Set("testUnsignedInt32", value); } + } + + /// The testUnsignedInt64 property + public long? TestUnsignedInt64 + { + get { return BackingStore?.Get("testUnsignedInt64"); } + set { BackingStore?.Set("testUnsignedInt64", value); } + } + + /// The testUri property + public string? TestUri + { + get { return BackingStore?.Get("testUri"); } + set { BackingStore?.Set("testUri", value); } + } + + /// The testVersion property + public string? TestVersion + { + get { return BackingStore?.Get("testVersion"); } + set { BackingStore?.Set("testVersion", value); } + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.AttributesInCreateTypeContainerRequest CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.AttributesInCreateTypeContainerRequest(); + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public override IDictionary> GetFieldDeserializers() + { + return new Dictionary>(base.GetFieldDeserializers()) + { + { "testBigInteger", n => { TestBigInteger = n.GetStringValue(); } }, + { "testBoolean", n => { TestBoolean = n.GetBoolValue(); } }, + { "testByte", n => { TestByte = n.GetIntValue(); } }, + { "testChar", n => { TestChar = n.GetStringValue(); } }, + { "testComplex", n => { TestComplex = n.GetStringValue(); } }, + { "testDateOnly", n => { TestDateOnly = n.GetDateValue(); } }, + { "testDateTime", n => { TestDateTime = n.GetDateTimeOffsetValue(); } }, + { "testDateTimeOffset", n => { TestDateTimeOffset = n.GetDateTimeOffsetValue(); } }, + { "testDecimal", n => { TestDecimal = n.GetDoubleValue(); } }, + { "testDouble", n => { TestDouble = n.GetDoubleValue(); } }, + { "testEnum", n => { TestEnum = n.GetEnumValue(); } }, + { "testFloat", n => { TestFloat = n.GetFloatValue(); } }, + { "testGuid", n => { TestGuid = n.GetGuidValue(); } }, + { "testHalf", n => { TestHalf = n.GetFloatValue(); } }, + { "testIPAddress", n => { TestIPAddress = n.GetStringValue(); } }, + { "testIPNetwork", n => { TestIPNetwork = n.GetStringValue(); } }, + { "testInt128", n => { TestInt128 = n.GetStringValue(); } }, + { "testInt16", n => { TestInt16 = n.GetIntValue(); } }, + { "testInt32", n => { TestInt32 = n.GetIntValue(); } }, + { "testInt64", n => { TestInt64 = n.GetLongValue(); } }, + { "testNullableBigInteger", n => { TestNullableBigInteger = n.GetStringValue(); } }, + { "testNullableBoolean", n => { TestNullableBoolean = n.GetBoolValue(); } }, + { "testNullableByte", n => { TestNullableByte = n.GetIntValue(); } }, + { "testNullableChar", n => { TestNullableChar = n.GetStringValue(); } }, + { "testNullableComplex", n => { TestNullableComplex = n.GetStringValue(); } }, + { "testNullableDateOnly", n => { TestNullableDateOnly = n.GetDateValue(); } }, + { "testNullableDateTime", n => { TestNullableDateTime = n.GetDateTimeOffsetValue(); } }, + { "testNullableDateTimeOffset", n => { TestNullableDateTimeOffset = n.GetDateTimeOffsetValue(); } }, + { "testNullableDecimal", n => { TestNullableDecimal = n.GetDoubleValue(); } }, + { "testNullableDouble", n => { TestNullableDouble = n.GetDoubleValue(); } }, + { "testNullableEnum", n => { TestNullableEnum = n.GetEnumValue(); } }, + { "testNullableFloat", n => { TestNullableFloat = n.GetFloatValue(); } }, + { "testNullableGuid", n => { TestNullableGuid = n.GetGuidValue(); } }, + { "testNullableHalf", n => { TestNullableHalf = n.GetFloatValue(); } }, + { "testNullableIPAddress", n => { TestNullableIPAddress = n.GetStringValue(); } }, + { "testNullableIPNetwork", n => { TestNullableIPNetwork = n.GetStringValue(); } }, + { "testNullableInt128", n => { TestNullableInt128 = n.GetStringValue(); } }, + { "testNullableInt16", n => { TestNullableInt16 = n.GetIntValue(); } }, + { "testNullableInt32", n => { TestNullableInt32 = n.GetIntValue(); } }, + { "testNullableInt64", n => { TestNullableInt64 = n.GetLongValue(); } }, + { "testNullableRune", n => { TestNullableRune = n.GetStringValue(); } }, + { "testNullableSignedByte", n => { TestNullableSignedByte = n.GetIntValue(); } }, + { "testNullableString", n => { TestNullableString = n.GetStringValue(); } }, + { "testNullableTimeOnly", n => { TestNullableTimeOnly = n.GetTimeValue(); } }, + { "testNullableTimeSpan", n => { TestNullableTimeSpan = n.GetTimeSpanValue(); } }, + { "testNullableUnsignedInt128", n => { TestNullableUnsignedInt128 = n.GetStringValue(); } }, + { "testNullableUnsignedInt16", n => { TestNullableUnsignedInt16 = n.GetIntValue(); } }, + { "testNullableUnsignedInt32", n => { TestNullableUnsignedInt32 = n.GetIntValue(); } }, + { "testNullableUnsignedInt64", n => { TestNullableUnsignedInt64 = n.GetLongValue(); } }, + { "testNullableUri", n => { TestNullableUri = n.GetStringValue(); } }, + { "testNullableVersion", n => { TestNullableVersion = n.GetStringValue(); } }, + { "testRune", n => { TestRune = n.GetStringValue(); } }, + { "testSignedByte", n => { TestSignedByte = n.GetIntValue(); } }, + { "testString", n => { TestString = n.GetStringValue(); } }, + { "testTimeOnly", n => { TestTimeOnly = n.GetTimeValue(); } }, + { "testTimeSpan", n => { TestTimeSpan = n.GetTimeSpanValue(); } }, + { "testUnsignedInt128", n => { TestUnsignedInt128 = n.GetStringValue(); } }, + { "testUnsignedInt16", n => { TestUnsignedInt16 = n.GetIntValue(); } }, + { "testUnsignedInt32", n => { TestUnsignedInt32 = n.GetIntValue(); } }, + { "testUnsignedInt64", n => { TestUnsignedInt64 = n.GetLongValue(); } }, + { "testUri", n => { TestUri = n.GetStringValue(); } }, + { "testVersion", n => { TestVersion = n.GetStringValue(); } }, + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public override void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + base.Serialize(writer); + writer.WriteStringValue("testBigInteger", TestBigInteger); + writer.WriteBoolValue("testBoolean", TestBoolean); + writer.WriteIntValue("testByte", TestByte); + writer.WriteStringValue("testChar", TestChar); + writer.WriteStringValue("testComplex", TestComplex); + writer.WriteDateValue("testDateOnly", TestDateOnly); + writer.WriteDateTimeOffsetValue("testDateTime", TestDateTime); + writer.WriteDateTimeOffsetValue("testDateTimeOffset", TestDateTimeOffset); + writer.WriteDoubleValue("testDecimal", TestDecimal); + writer.WriteDoubleValue("testDouble", TestDouble); + writer.WriteEnumValue("testEnum", TestEnum); + writer.WriteFloatValue("testFloat", TestFloat); + writer.WriteGuidValue("testGuid", TestGuid); + writer.WriteFloatValue("testHalf", TestHalf); + writer.WriteStringValue("testInt128", TestInt128); + writer.WriteIntValue("testInt16", TestInt16); + writer.WriteIntValue("testInt32", TestInt32); + writer.WriteLongValue("testInt64", TestInt64); + writer.WriteStringValue("testIPAddress", TestIPAddress); + writer.WriteStringValue("testIPNetwork", TestIPNetwork); + writer.WriteStringValue("testNullableBigInteger", TestNullableBigInteger); + writer.WriteBoolValue("testNullableBoolean", TestNullableBoolean); + writer.WriteIntValue("testNullableByte", TestNullableByte); + writer.WriteStringValue("testNullableChar", TestNullableChar); + writer.WriteStringValue("testNullableComplex", TestNullableComplex); + writer.WriteDateValue("testNullableDateOnly", TestNullableDateOnly); + writer.WriteDateTimeOffsetValue("testNullableDateTime", TestNullableDateTime); + writer.WriteDateTimeOffsetValue("testNullableDateTimeOffset", TestNullableDateTimeOffset); + writer.WriteDoubleValue("testNullableDecimal", TestNullableDecimal); + writer.WriteDoubleValue("testNullableDouble", TestNullableDouble); + writer.WriteEnumValue("testNullableEnum", TestNullableEnum); + writer.WriteFloatValue("testNullableFloat", TestNullableFloat); + writer.WriteGuidValue("testNullableGuid", TestNullableGuid); + writer.WriteFloatValue("testNullableHalf", TestNullableHalf); + writer.WriteStringValue("testNullableInt128", TestNullableInt128); + writer.WriteIntValue("testNullableInt16", TestNullableInt16); + writer.WriteIntValue("testNullableInt32", TestNullableInt32); + writer.WriteLongValue("testNullableInt64", TestNullableInt64); + writer.WriteStringValue("testNullableIPAddress", TestNullableIPAddress); + writer.WriteStringValue("testNullableIPNetwork", TestNullableIPNetwork); + writer.WriteStringValue("testNullableRune", TestNullableRune); + writer.WriteIntValue("testNullableSignedByte", TestNullableSignedByte); + writer.WriteStringValue("testNullableString", TestNullableString); + writer.WriteTimeValue("testNullableTimeOnly", TestNullableTimeOnly); + writer.WriteTimeSpanValue("testNullableTimeSpan", TestNullableTimeSpan); + writer.WriteStringValue("testNullableUnsignedInt128", TestNullableUnsignedInt128); + writer.WriteIntValue("testNullableUnsignedInt16", TestNullableUnsignedInt16); + writer.WriteIntValue("testNullableUnsignedInt32", TestNullableUnsignedInt32); + writer.WriteLongValue("testNullableUnsignedInt64", TestNullableUnsignedInt64); + writer.WriteStringValue("testNullableUri", TestNullableUri); + writer.WriteStringValue("testNullableVersion", TestNullableVersion); + writer.WriteStringValue("testRune", TestRune); + writer.WriteIntValue("testSignedByte", TestSignedByte); + writer.WriteStringValue("testString", TestString); + writer.WriteTimeValue("testTimeOnly", TestTimeOnly); + writer.WriteTimeSpanValue("testTimeSpan", TestTimeSpan); + writer.WriteStringValue("testUnsignedInt128", TestUnsignedInt128); + writer.WriteIntValue("testUnsignedInt16", TestUnsignedInt16); + writer.WriteIntValue("testUnsignedInt32", TestUnsignedInt32); + writer.WriteLongValue("testUnsignedInt64", TestUnsignedInt64); + writer.WriteStringValue("testUri", TestUri); + writer.WriteStringValue("testVersion", TestVersion); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/AttributesInResponse.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/AttributesInResponse.cs new file mode 100644 index 0000000000..a0dae399b0 --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/AttributesInResponse.cs @@ -0,0 +1,75 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions.Store; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class AttributesInResponse : IBackedModel, IParsable + #pragma warning restore CS1591 + { + /// Stores model information. + public IBackingStore BackingStore { get; private set; } + + /// The openapiDiscriminator property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceType? OpenapiDiscriminator + { + get { return BackingStore?.Get("openapi:discriminator"); } + set { BackingStore?.Set("openapi:discriminator", value); } + } + + /// + /// Instantiates a new and sets the default values. + /// + public AttributesInResponse() + { + BackingStore = BackingStoreFactorySingleton.Instance.CreateBackingStore(); + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.AttributesInResponse CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + var mappingValue = parseNode.GetChildNode("openapi:discriminator")?.GetStringValue(); + return mappingValue switch + { + "typeContainers" => new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.AttributesInTypeContainerResponse(), + _ => new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.AttributesInResponse(), + }; + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "openapi:discriminator", n => { OpenapiDiscriminator = n.GetEnumValue(); } }, + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteEnumValue("openapi:discriminator", OpenapiDiscriminator); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/AttributesInTypeContainerResponse.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/AttributesInTypeContainerResponse.cs new file mode 100644 index 0000000000..d90d8b0982 --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/AttributesInTypeContainerResponse.cs @@ -0,0 +1,609 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class AttributesInTypeContainerResponse : global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.AttributesInResponse, IParsable + #pragma warning restore CS1591 + { + /// The testBigInteger property + public string? TestBigInteger + { + get { return BackingStore?.Get("testBigInteger"); } + set { BackingStore?.Set("testBigInteger", value); } + } + + /// The testBoolean property + public bool? TestBoolean + { + get { return BackingStore?.Get("testBoolean"); } + set { BackingStore?.Set("testBoolean", value); } + } + + /// The testByte property + public int? TestByte + { + get { return BackingStore?.Get("testByte"); } + set { BackingStore?.Set("testByte", value); } + } + + /// The testChar property + public string? TestChar + { + get { return BackingStore?.Get("testChar"); } + set { BackingStore?.Set("testChar", value); } + } + + /// The testComplex property + public string? TestComplex + { + get { return BackingStore?.Get("testComplex"); } + set { BackingStore?.Set("testComplex", value); } + } + + /// The testDateOnly property + public Date? TestDateOnly + { + get { return BackingStore?.Get("testDateOnly"); } + set { BackingStore?.Set("testDateOnly", value); } + } + + /// The testDateTime property + public DateTimeOffset? TestDateTime + { + get { return BackingStore?.Get("testDateTime"); } + set { BackingStore?.Set("testDateTime", value); } + } + + /// The testDateTimeOffset property + public DateTimeOffset? TestDateTimeOffset + { + get { return BackingStore?.Get("testDateTimeOffset"); } + set { BackingStore?.Set("testDateTimeOffset", value); } + } + + /// The testDecimal property + public double? TestDecimal + { + get { return BackingStore?.Get("testDecimal"); } + set { BackingStore?.Set("testDecimal", value); } + } + + /// The testDouble property + public double? TestDouble + { + get { return BackingStore?.Get("testDouble"); } + set { BackingStore?.Set("testDouble", value); } + } + + /// The testEnum property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.DayOfWeekObject? TestEnum + { + get { return BackingStore?.Get("testEnum"); } + set { BackingStore?.Set("testEnum", value); } + } + + /// The testFloat property + public float? TestFloat + { + get { return BackingStore?.Get("testFloat"); } + set { BackingStore?.Set("testFloat", value); } + } + + /// The testGuid property + public Guid? TestGuid + { + get { return BackingStore?.Get("testGuid"); } + set { BackingStore?.Set("testGuid", value); } + } + + /// The testHalf property + public float? TestHalf + { + get { return BackingStore?.Get("testHalf"); } + set { BackingStore?.Set("testHalf", value); } + } + + /// The testInt128 property + public string? TestInt128 + { + get { return BackingStore?.Get("testInt128"); } + set { BackingStore?.Set("testInt128", value); } + } + + /// The testInt16 property + public int? TestInt16 + { + get { return BackingStore?.Get("testInt16"); } + set { BackingStore?.Set("testInt16", value); } + } + + /// The testInt32 property + public int? TestInt32 + { + get { return BackingStore?.Get("testInt32"); } + set { BackingStore?.Set("testInt32", value); } + } + + /// The testInt64 property + public long? TestInt64 + { + get { return BackingStore?.Get("testInt64"); } + set { BackingStore?.Set("testInt64", value); } + } + + /// The testIPAddress property + public string? TestIPAddress + { + get { return BackingStore?.Get("testIPAddress"); } + set { BackingStore?.Set("testIPAddress", value); } + } + + /// The testIPNetwork property + public string? TestIPNetwork + { + get { return BackingStore?.Get("testIPNetwork"); } + set { BackingStore?.Set("testIPNetwork", value); } + } + + /// The testNullableBigInteger property + public string? TestNullableBigInteger + { + get { return BackingStore?.Get("testNullableBigInteger"); } + set { BackingStore?.Set("testNullableBigInteger", value); } + } + + /// The testNullableBoolean property + public bool? TestNullableBoolean + { + get { return BackingStore?.Get("testNullableBoolean"); } + set { BackingStore?.Set("testNullableBoolean", value); } + } + + /// The testNullableByte property + public int? TestNullableByte + { + get { return BackingStore?.Get("testNullableByte"); } + set { BackingStore?.Set("testNullableByte", value); } + } + + /// The testNullableChar property + public string? TestNullableChar + { + get { return BackingStore?.Get("testNullableChar"); } + set { BackingStore?.Set("testNullableChar", value); } + } + + /// The testNullableComplex property + public string? TestNullableComplex + { + get { return BackingStore?.Get("testNullableComplex"); } + set { BackingStore?.Set("testNullableComplex", value); } + } + + /// The testNullableDateOnly property + public Date? TestNullableDateOnly + { + get { return BackingStore?.Get("testNullableDateOnly"); } + set { BackingStore?.Set("testNullableDateOnly", value); } + } + + /// The testNullableDateTime property + public DateTimeOffset? TestNullableDateTime + { + get { return BackingStore?.Get("testNullableDateTime"); } + set { BackingStore?.Set("testNullableDateTime", value); } + } + + /// The testNullableDateTimeOffset property + public DateTimeOffset? TestNullableDateTimeOffset + { + get { return BackingStore?.Get("testNullableDateTimeOffset"); } + set { BackingStore?.Set("testNullableDateTimeOffset", value); } + } + + /// The testNullableDecimal property + public double? TestNullableDecimal + { + get { return BackingStore?.Get("testNullableDecimal"); } + set { BackingStore?.Set("testNullableDecimal", value); } + } + + /// The testNullableDouble property + public double? TestNullableDouble + { + get { return BackingStore?.Get("testNullableDouble"); } + set { BackingStore?.Set("testNullableDouble", value); } + } + + /// The testNullableEnum property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.DayOfWeekObject? TestNullableEnum + { + get { return BackingStore?.Get("testNullableEnum"); } + set { BackingStore?.Set("testNullableEnum", value); } + } + + /// The testNullableFloat property + public float? TestNullableFloat + { + get { return BackingStore?.Get("testNullableFloat"); } + set { BackingStore?.Set("testNullableFloat", value); } + } + + /// The testNullableGuid property + public Guid? TestNullableGuid + { + get { return BackingStore?.Get("testNullableGuid"); } + set { BackingStore?.Set("testNullableGuid", value); } + } + + /// The testNullableHalf property + public float? TestNullableHalf + { + get { return BackingStore?.Get("testNullableHalf"); } + set { BackingStore?.Set("testNullableHalf", value); } + } + + /// The testNullableInt128 property + public string? TestNullableInt128 + { + get { return BackingStore?.Get("testNullableInt128"); } + set { BackingStore?.Set("testNullableInt128", value); } + } + + /// The testNullableInt16 property + public int? TestNullableInt16 + { + get { return BackingStore?.Get("testNullableInt16"); } + set { BackingStore?.Set("testNullableInt16", value); } + } + + /// The testNullableInt32 property + public int? TestNullableInt32 + { + get { return BackingStore?.Get("testNullableInt32"); } + set { BackingStore?.Set("testNullableInt32", value); } + } + + /// The testNullableInt64 property + public long? TestNullableInt64 + { + get { return BackingStore?.Get("testNullableInt64"); } + set { BackingStore?.Set("testNullableInt64", value); } + } + + /// The testNullableIPAddress property + public string? TestNullableIPAddress + { + get { return BackingStore?.Get("testNullableIPAddress"); } + set { BackingStore?.Set("testNullableIPAddress", value); } + } + + /// The testNullableIPNetwork property + public string? TestNullableIPNetwork + { + get { return BackingStore?.Get("testNullableIPNetwork"); } + set { BackingStore?.Set("testNullableIPNetwork", value); } + } + + /// The testNullableRune property + public string? TestNullableRune + { + get { return BackingStore?.Get("testNullableRune"); } + set { BackingStore?.Set("testNullableRune", value); } + } + + /// The testNullableSignedByte property + public int? TestNullableSignedByte + { + get { return BackingStore?.Get("testNullableSignedByte"); } + set { BackingStore?.Set("testNullableSignedByte", value); } + } + + /// The testNullableString property + public string? TestNullableString + { + get { return BackingStore?.Get("testNullableString"); } + set { BackingStore?.Set("testNullableString", value); } + } + + /// The testNullableTimeOnly property + public Time? TestNullableTimeOnly + { + get { return BackingStore?.Get("testNullableTimeOnly"); } + set { BackingStore?.Set("testNullableTimeOnly", value); } + } + + /// The testNullableTimeSpan property + public TimeSpan? TestNullableTimeSpan + { + get { return BackingStore?.Get("testNullableTimeSpan"); } + set { BackingStore?.Set("testNullableTimeSpan", value); } + } + + /// The testNullableUnsignedInt128 property + public string? TestNullableUnsignedInt128 + { + get { return BackingStore?.Get("testNullableUnsignedInt128"); } + set { BackingStore?.Set("testNullableUnsignedInt128", value); } + } + + /// The testNullableUnsignedInt16 property + public int? TestNullableUnsignedInt16 + { + get { return BackingStore?.Get("testNullableUnsignedInt16"); } + set { BackingStore?.Set("testNullableUnsignedInt16", value); } + } + + /// The testNullableUnsignedInt32 property + public int? TestNullableUnsignedInt32 + { + get { return BackingStore?.Get("testNullableUnsignedInt32"); } + set { BackingStore?.Set("testNullableUnsignedInt32", value); } + } + + /// The testNullableUnsignedInt64 property + public long? TestNullableUnsignedInt64 + { + get { return BackingStore?.Get("testNullableUnsignedInt64"); } + set { BackingStore?.Set("testNullableUnsignedInt64", value); } + } + + /// The testNullableUri property + public string? TestNullableUri + { + get { return BackingStore?.Get("testNullableUri"); } + set { BackingStore?.Set("testNullableUri", value); } + } + + /// The testNullableVersion property + public string? TestNullableVersion + { + get { return BackingStore?.Get("testNullableVersion"); } + set { BackingStore?.Set("testNullableVersion", value); } + } + + /// The testRune property + public string? TestRune + { + get { return BackingStore?.Get("testRune"); } + set { BackingStore?.Set("testRune", value); } + } + + /// The testSignedByte property + public int? TestSignedByte + { + get { return BackingStore?.Get("testSignedByte"); } + set { BackingStore?.Set("testSignedByte", value); } + } + + /// The testString property + public string? TestString + { + get { return BackingStore?.Get("testString"); } + set { BackingStore?.Set("testString", value); } + } + + /// The testTimeOnly property + public Time? TestTimeOnly + { + get { return BackingStore?.Get("testTimeOnly"); } + set { BackingStore?.Set("testTimeOnly", value); } + } + + /// The testTimeSpan property + public TimeSpan? TestTimeSpan + { + get { return BackingStore?.Get("testTimeSpan"); } + set { BackingStore?.Set("testTimeSpan", value); } + } + + /// The testUnsignedInt128 property + public string? TestUnsignedInt128 + { + get { return BackingStore?.Get("testUnsignedInt128"); } + set { BackingStore?.Set("testUnsignedInt128", value); } + } + + /// The testUnsignedInt16 property + public int? TestUnsignedInt16 + { + get { return BackingStore?.Get("testUnsignedInt16"); } + set { BackingStore?.Set("testUnsignedInt16", value); } + } + + /// The testUnsignedInt32 property + public int? TestUnsignedInt32 + { + get { return BackingStore?.Get("testUnsignedInt32"); } + set { BackingStore?.Set("testUnsignedInt32", value); } + } + + /// The testUnsignedInt64 property + public long? TestUnsignedInt64 + { + get { return BackingStore?.Get("testUnsignedInt64"); } + set { BackingStore?.Set("testUnsignedInt64", value); } + } + + /// The testUri property + public string? TestUri + { + get { return BackingStore?.Get("testUri"); } + set { BackingStore?.Set("testUri", value); } + } + + /// The testVersion property + public string? TestVersion + { + get { return BackingStore?.Get("testVersion"); } + set { BackingStore?.Set("testVersion", value); } + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.AttributesInTypeContainerResponse CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.AttributesInTypeContainerResponse(); + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public override IDictionary> GetFieldDeserializers() + { + return new Dictionary>(base.GetFieldDeserializers()) + { + { "testBigInteger", n => { TestBigInteger = n.GetStringValue(); } }, + { "testBoolean", n => { TestBoolean = n.GetBoolValue(); } }, + { "testByte", n => { TestByte = n.GetIntValue(); } }, + { "testChar", n => { TestChar = n.GetStringValue(); } }, + { "testComplex", n => { TestComplex = n.GetStringValue(); } }, + { "testDateOnly", n => { TestDateOnly = n.GetDateValue(); } }, + { "testDateTime", n => { TestDateTime = n.GetDateTimeOffsetValue(); } }, + { "testDateTimeOffset", n => { TestDateTimeOffset = n.GetDateTimeOffsetValue(); } }, + { "testDecimal", n => { TestDecimal = n.GetDoubleValue(); } }, + { "testDouble", n => { TestDouble = n.GetDoubleValue(); } }, + { "testEnum", n => { TestEnum = n.GetEnumValue(); } }, + { "testFloat", n => { TestFloat = n.GetFloatValue(); } }, + { "testGuid", n => { TestGuid = n.GetGuidValue(); } }, + { "testHalf", n => { TestHalf = n.GetFloatValue(); } }, + { "testIPAddress", n => { TestIPAddress = n.GetStringValue(); } }, + { "testIPNetwork", n => { TestIPNetwork = n.GetStringValue(); } }, + { "testInt128", n => { TestInt128 = n.GetStringValue(); } }, + { "testInt16", n => { TestInt16 = n.GetIntValue(); } }, + { "testInt32", n => { TestInt32 = n.GetIntValue(); } }, + { "testInt64", n => { TestInt64 = n.GetLongValue(); } }, + { "testNullableBigInteger", n => { TestNullableBigInteger = n.GetStringValue(); } }, + { "testNullableBoolean", n => { TestNullableBoolean = n.GetBoolValue(); } }, + { "testNullableByte", n => { TestNullableByte = n.GetIntValue(); } }, + { "testNullableChar", n => { TestNullableChar = n.GetStringValue(); } }, + { "testNullableComplex", n => { TestNullableComplex = n.GetStringValue(); } }, + { "testNullableDateOnly", n => { TestNullableDateOnly = n.GetDateValue(); } }, + { "testNullableDateTime", n => { TestNullableDateTime = n.GetDateTimeOffsetValue(); } }, + { "testNullableDateTimeOffset", n => { TestNullableDateTimeOffset = n.GetDateTimeOffsetValue(); } }, + { "testNullableDecimal", n => { TestNullableDecimal = n.GetDoubleValue(); } }, + { "testNullableDouble", n => { TestNullableDouble = n.GetDoubleValue(); } }, + { "testNullableEnum", n => { TestNullableEnum = n.GetEnumValue(); } }, + { "testNullableFloat", n => { TestNullableFloat = n.GetFloatValue(); } }, + { "testNullableGuid", n => { TestNullableGuid = n.GetGuidValue(); } }, + { "testNullableHalf", n => { TestNullableHalf = n.GetFloatValue(); } }, + { "testNullableIPAddress", n => { TestNullableIPAddress = n.GetStringValue(); } }, + { "testNullableIPNetwork", n => { TestNullableIPNetwork = n.GetStringValue(); } }, + { "testNullableInt128", n => { TestNullableInt128 = n.GetStringValue(); } }, + { "testNullableInt16", n => { TestNullableInt16 = n.GetIntValue(); } }, + { "testNullableInt32", n => { TestNullableInt32 = n.GetIntValue(); } }, + { "testNullableInt64", n => { TestNullableInt64 = n.GetLongValue(); } }, + { "testNullableRune", n => { TestNullableRune = n.GetStringValue(); } }, + { "testNullableSignedByte", n => { TestNullableSignedByte = n.GetIntValue(); } }, + { "testNullableString", n => { TestNullableString = n.GetStringValue(); } }, + { "testNullableTimeOnly", n => { TestNullableTimeOnly = n.GetTimeValue(); } }, + { "testNullableTimeSpan", n => { TestNullableTimeSpan = n.GetTimeSpanValue(); } }, + { "testNullableUnsignedInt128", n => { TestNullableUnsignedInt128 = n.GetStringValue(); } }, + { "testNullableUnsignedInt16", n => { TestNullableUnsignedInt16 = n.GetIntValue(); } }, + { "testNullableUnsignedInt32", n => { TestNullableUnsignedInt32 = n.GetIntValue(); } }, + { "testNullableUnsignedInt64", n => { TestNullableUnsignedInt64 = n.GetLongValue(); } }, + { "testNullableUri", n => { TestNullableUri = n.GetStringValue(); } }, + { "testNullableVersion", n => { TestNullableVersion = n.GetStringValue(); } }, + { "testRune", n => { TestRune = n.GetStringValue(); } }, + { "testSignedByte", n => { TestSignedByte = n.GetIntValue(); } }, + { "testString", n => { TestString = n.GetStringValue(); } }, + { "testTimeOnly", n => { TestTimeOnly = n.GetTimeValue(); } }, + { "testTimeSpan", n => { TestTimeSpan = n.GetTimeSpanValue(); } }, + { "testUnsignedInt128", n => { TestUnsignedInt128 = n.GetStringValue(); } }, + { "testUnsignedInt16", n => { TestUnsignedInt16 = n.GetIntValue(); } }, + { "testUnsignedInt32", n => { TestUnsignedInt32 = n.GetIntValue(); } }, + { "testUnsignedInt64", n => { TestUnsignedInt64 = n.GetLongValue(); } }, + { "testUri", n => { TestUri = n.GetStringValue(); } }, + { "testVersion", n => { TestVersion = n.GetStringValue(); } }, + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public override void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + base.Serialize(writer); + writer.WriteStringValue("testBigInteger", TestBigInteger); + writer.WriteBoolValue("testBoolean", TestBoolean); + writer.WriteIntValue("testByte", TestByte); + writer.WriteStringValue("testChar", TestChar); + writer.WriteStringValue("testComplex", TestComplex); + writer.WriteDateValue("testDateOnly", TestDateOnly); + writer.WriteDateTimeOffsetValue("testDateTime", TestDateTime); + writer.WriteDateTimeOffsetValue("testDateTimeOffset", TestDateTimeOffset); + writer.WriteDoubleValue("testDecimal", TestDecimal); + writer.WriteDoubleValue("testDouble", TestDouble); + writer.WriteEnumValue("testEnum", TestEnum); + writer.WriteFloatValue("testFloat", TestFloat); + writer.WriteGuidValue("testGuid", TestGuid); + writer.WriteFloatValue("testHalf", TestHalf); + writer.WriteStringValue("testInt128", TestInt128); + writer.WriteIntValue("testInt16", TestInt16); + writer.WriteIntValue("testInt32", TestInt32); + writer.WriteLongValue("testInt64", TestInt64); + writer.WriteStringValue("testIPAddress", TestIPAddress); + writer.WriteStringValue("testIPNetwork", TestIPNetwork); + writer.WriteStringValue("testNullableBigInteger", TestNullableBigInteger); + writer.WriteBoolValue("testNullableBoolean", TestNullableBoolean); + writer.WriteIntValue("testNullableByte", TestNullableByte); + writer.WriteStringValue("testNullableChar", TestNullableChar); + writer.WriteStringValue("testNullableComplex", TestNullableComplex); + writer.WriteDateValue("testNullableDateOnly", TestNullableDateOnly); + writer.WriteDateTimeOffsetValue("testNullableDateTime", TestNullableDateTime); + writer.WriteDateTimeOffsetValue("testNullableDateTimeOffset", TestNullableDateTimeOffset); + writer.WriteDoubleValue("testNullableDecimal", TestNullableDecimal); + writer.WriteDoubleValue("testNullableDouble", TestNullableDouble); + writer.WriteEnumValue("testNullableEnum", TestNullableEnum); + writer.WriteFloatValue("testNullableFloat", TestNullableFloat); + writer.WriteGuidValue("testNullableGuid", TestNullableGuid); + writer.WriteFloatValue("testNullableHalf", TestNullableHalf); + writer.WriteStringValue("testNullableInt128", TestNullableInt128); + writer.WriteIntValue("testNullableInt16", TestNullableInt16); + writer.WriteIntValue("testNullableInt32", TestNullableInt32); + writer.WriteLongValue("testNullableInt64", TestNullableInt64); + writer.WriteStringValue("testNullableIPAddress", TestNullableIPAddress); + writer.WriteStringValue("testNullableIPNetwork", TestNullableIPNetwork); + writer.WriteStringValue("testNullableRune", TestNullableRune); + writer.WriteIntValue("testNullableSignedByte", TestNullableSignedByte); + writer.WriteStringValue("testNullableString", TestNullableString); + writer.WriteTimeValue("testNullableTimeOnly", TestNullableTimeOnly); + writer.WriteTimeSpanValue("testNullableTimeSpan", TestNullableTimeSpan); + writer.WriteStringValue("testNullableUnsignedInt128", TestNullableUnsignedInt128); + writer.WriteIntValue("testNullableUnsignedInt16", TestNullableUnsignedInt16); + writer.WriteIntValue("testNullableUnsignedInt32", TestNullableUnsignedInt32); + writer.WriteLongValue("testNullableUnsignedInt64", TestNullableUnsignedInt64); + writer.WriteStringValue("testNullableUri", TestNullableUri); + writer.WriteStringValue("testNullableVersion", TestNullableVersion); + writer.WriteStringValue("testRune", TestRune); + writer.WriteIntValue("testSignedByte", TestSignedByte); + writer.WriteStringValue("testString", TestString); + writer.WriteTimeValue("testTimeOnly", TestTimeOnly); + writer.WriteTimeSpanValue("testTimeSpan", TestTimeSpan); + writer.WriteStringValue("testUnsignedInt128", TestUnsignedInt128); + writer.WriteIntValue("testUnsignedInt16", TestUnsignedInt16); + writer.WriteIntValue("testUnsignedInt32", TestUnsignedInt32); + writer.WriteLongValue("testUnsignedInt64", TestUnsignedInt64); + writer.WriteStringValue("testUri", TestUri); + writer.WriteStringValue("testVersion", TestVersion); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/AttributesInUpdateRequest.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/AttributesInUpdateRequest.cs new file mode 100644 index 0000000000..e222a46b0d --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/AttributesInUpdateRequest.cs @@ -0,0 +1,75 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions.Store; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class AttributesInUpdateRequest : IBackedModel, IParsable + #pragma warning restore CS1591 + { + /// Stores model information. + public IBackingStore BackingStore { get; private set; } + + /// The openapiDiscriminator property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceType? OpenapiDiscriminator + { + get { return BackingStore?.Get("openapi:discriminator"); } + set { BackingStore?.Set("openapi:discriminator", value); } + } + + /// + /// Instantiates a new and sets the default values. + /// + public AttributesInUpdateRequest() + { + BackingStore = BackingStoreFactorySingleton.Instance.CreateBackingStore(); + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.AttributesInUpdateRequest CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + var mappingValue = parseNode.GetChildNode("openapi:discriminator")?.GetStringValue(); + return mappingValue switch + { + "typeContainers" => new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.AttributesInUpdateTypeContainerRequest(), + _ => new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.AttributesInUpdateRequest(), + }; + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "openapi:discriminator", n => { OpenapiDiscriminator = n.GetEnumValue(); } }, + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteEnumValue("openapi:discriminator", OpenapiDiscriminator); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/AttributesInUpdateTypeContainerRequest.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/AttributesInUpdateTypeContainerRequest.cs new file mode 100644 index 0000000000..73349447fd --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/AttributesInUpdateTypeContainerRequest.cs @@ -0,0 +1,609 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class AttributesInUpdateTypeContainerRequest : global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.AttributesInUpdateRequest, IParsable + #pragma warning restore CS1591 + { + /// The testBigInteger property + public string? TestBigInteger + { + get { return BackingStore?.Get("testBigInteger"); } + set { BackingStore?.Set("testBigInteger", value); } + } + + /// The testBoolean property + public bool? TestBoolean + { + get { return BackingStore?.Get("testBoolean"); } + set { BackingStore?.Set("testBoolean", value); } + } + + /// The testByte property + public int? TestByte + { + get { return BackingStore?.Get("testByte"); } + set { BackingStore?.Set("testByte", value); } + } + + /// The testChar property + public string? TestChar + { + get { return BackingStore?.Get("testChar"); } + set { BackingStore?.Set("testChar", value); } + } + + /// The testComplex property + public string? TestComplex + { + get { return BackingStore?.Get("testComplex"); } + set { BackingStore?.Set("testComplex", value); } + } + + /// The testDateOnly property + public Date? TestDateOnly + { + get { return BackingStore?.Get("testDateOnly"); } + set { BackingStore?.Set("testDateOnly", value); } + } + + /// The testDateTime property + public DateTimeOffset? TestDateTime + { + get { return BackingStore?.Get("testDateTime"); } + set { BackingStore?.Set("testDateTime", value); } + } + + /// The testDateTimeOffset property + public DateTimeOffset? TestDateTimeOffset + { + get { return BackingStore?.Get("testDateTimeOffset"); } + set { BackingStore?.Set("testDateTimeOffset", value); } + } + + /// The testDecimal property + public double? TestDecimal + { + get { return BackingStore?.Get("testDecimal"); } + set { BackingStore?.Set("testDecimal", value); } + } + + /// The testDouble property + public double? TestDouble + { + get { return BackingStore?.Get("testDouble"); } + set { BackingStore?.Set("testDouble", value); } + } + + /// The testEnum property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.DayOfWeekObject? TestEnum + { + get { return BackingStore?.Get("testEnum"); } + set { BackingStore?.Set("testEnum", value); } + } + + /// The testFloat property + public float? TestFloat + { + get { return BackingStore?.Get("testFloat"); } + set { BackingStore?.Set("testFloat", value); } + } + + /// The testGuid property + public Guid? TestGuid + { + get { return BackingStore?.Get("testGuid"); } + set { BackingStore?.Set("testGuid", value); } + } + + /// The testHalf property + public float? TestHalf + { + get { return BackingStore?.Get("testHalf"); } + set { BackingStore?.Set("testHalf", value); } + } + + /// The testInt128 property + public string? TestInt128 + { + get { return BackingStore?.Get("testInt128"); } + set { BackingStore?.Set("testInt128", value); } + } + + /// The testInt16 property + public int? TestInt16 + { + get { return BackingStore?.Get("testInt16"); } + set { BackingStore?.Set("testInt16", value); } + } + + /// The testInt32 property + public int? TestInt32 + { + get { return BackingStore?.Get("testInt32"); } + set { BackingStore?.Set("testInt32", value); } + } + + /// The testInt64 property + public long? TestInt64 + { + get { return BackingStore?.Get("testInt64"); } + set { BackingStore?.Set("testInt64", value); } + } + + /// The testIPAddress property + public string? TestIPAddress + { + get { return BackingStore?.Get("testIPAddress"); } + set { BackingStore?.Set("testIPAddress", value); } + } + + /// The testIPNetwork property + public string? TestIPNetwork + { + get { return BackingStore?.Get("testIPNetwork"); } + set { BackingStore?.Set("testIPNetwork", value); } + } + + /// The testNullableBigInteger property + public string? TestNullableBigInteger + { + get { return BackingStore?.Get("testNullableBigInteger"); } + set { BackingStore?.Set("testNullableBigInteger", value); } + } + + /// The testNullableBoolean property + public bool? TestNullableBoolean + { + get { return BackingStore?.Get("testNullableBoolean"); } + set { BackingStore?.Set("testNullableBoolean", value); } + } + + /// The testNullableByte property + public int? TestNullableByte + { + get { return BackingStore?.Get("testNullableByte"); } + set { BackingStore?.Set("testNullableByte", value); } + } + + /// The testNullableChar property + public string? TestNullableChar + { + get { return BackingStore?.Get("testNullableChar"); } + set { BackingStore?.Set("testNullableChar", value); } + } + + /// The testNullableComplex property + public string? TestNullableComplex + { + get { return BackingStore?.Get("testNullableComplex"); } + set { BackingStore?.Set("testNullableComplex", value); } + } + + /// The testNullableDateOnly property + public Date? TestNullableDateOnly + { + get { return BackingStore?.Get("testNullableDateOnly"); } + set { BackingStore?.Set("testNullableDateOnly", value); } + } + + /// The testNullableDateTime property + public DateTimeOffset? TestNullableDateTime + { + get { return BackingStore?.Get("testNullableDateTime"); } + set { BackingStore?.Set("testNullableDateTime", value); } + } + + /// The testNullableDateTimeOffset property + public DateTimeOffset? TestNullableDateTimeOffset + { + get { return BackingStore?.Get("testNullableDateTimeOffset"); } + set { BackingStore?.Set("testNullableDateTimeOffset", value); } + } + + /// The testNullableDecimal property + public double? TestNullableDecimal + { + get { return BackingStore?.Get("testNullableDecimal"); } + set { BackingStore?.Set("testNullableDecimal", value); } + } + + /// The testNullableDouble property + public double? TestNullableDouble + { + get { return BackingStore?.Get("testNullableDouble"); } + set { BackingStore?.Set("testNullableDouble", value); } + } + + /// The testNullableEnum property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.DayOfWeekObject? TestNullableEnum + { + get { return BackingStore?.Get("testNullableEnum"); } + set { BackingStore?.Set("testNullableEnum", value); } + } + + /// The testNullableFloat property + public float? TestNullableFloat + { + get { return BackingStore?.Get("testNullableFloat"); } + set { BackingStore?.Set("testNullableFloat", value); } + } + + /// The testNullableGuid property + public Guid? TestNullableGuid + { + get { return BackingStore?.Get("testNullableGuid"); } + set { BackingStore?.Set("testNullableGuid", value); } + } + + /// The testNullableHalf property + public float? TestNullableHalf + { + get { return BackingStore?.Get("testNullableHalf"); } + set { BackingStore?.Set("testNullableHalf", value); } + } + + /// The testNullableInt128 property + public string? TestNullableInt128 + { + get { return BackingStore?.Get("testNullableInt128"); } + set { BackingStore?.Set("testNullableInt128", value); } + } + + /// The testNullableInt16 property + public int? TestNullableInt16 + { + get { return BackingStore?.Get("testNullableInt16"); } + set { BackingStore?.Set("testNullableInt16", value); } + } + + /// The testNullableInt32 property + public int? TestNullableInt32 + { + get { return BackingStore?.Get("testNullableInt32"); } + set { BackingStore?.Set("testNullableInt32", value); } + } + + /// The testNullableInt64 property + public long? TestNullableInt64 + { + get { return BackingStore?.Get("testNullableInt64"); } + set { BackingStore?.Set("testNullableInt64", value); } + } + + /// The testNullableIPAddress property + public string? TestNullableIPAddress + { + get { return BackingStore?.Get("testNullableIPAddress"); } + set { BackingStore?.Set("testNullableIPAddress", value); } + } + + /// The testNullableIPNetwork property + public string? TestNullableIPNetwork + { + get { return BackingStore?.Get("testNullableIPNetwork"); } + set { BackingStore?.Set("testNullableIPNetwork", value); } + } + + /// The testNullableRune property + public string? TestNullableRune + { + get { return BackingStore?.Get("testNullableRune"); } + set { BackingStore?.Set("testNullableRune", value); } + } + + /// The testNullableSignedByte property + public int? TestNullableSignedByte + { + get { return BackingStore?.Get("testNullableSignedByte"); } + set { BackingStore?.Set("testNullableSignedByte", value); } + } + + /// The testNullableString property + public string? TestNullableString + { + get { return BackingStore?.Get("testNullableString"); } + set { BackingStore?.Set("testNullableString", value); } + } + + /// The testNullableTimeOnly property + public Time? TestNullableTimeOnly + { + get { return BackingStore?.Get("testNullableTimeOnly"); } + set { BackingStore?.Set("testNullableTimeOnly", value); } + } + + /// The testNullableTimeSpan property + public TimeSpan? TestNullableTimeSpan + { + get { return BackingStore?.Get("testNullableTimeSpan"); } + set { BackingStore?.Set("testNullableTimeSpan", value); } + } + + /// The testNullableUnsignedInt128 property + public string? TestNullableUnsignedInt128 + { + get { return BackingStore?.Get("testNullableUnsignedInt128"); } + set { BackingStore?.Set("testNullableUnsignedInt128", value); } + } + + /// The testNullableUnsignedInt16 property + public int? TestNullableUnsignedInt16 + { + get { return BackingStore?.Get("testNullableUnsignedInt16"); } + set { BackingStore?.Set("testNullableUnsignedInt16", value); } + } + + /// The testNullableUnsignedInt32 property + public int? TestNullableUnsignedInt32 + { + get { return BackingStore?.Get("testNullableUnsignedInt32"); } + set { BackingStore?.Set("testNullableUnsignedInt32", value); } + } + + /// The testNullableUnsignedInt64 property + public long? TestNullableUnsignedInt64 + { + get { return BackingStore?.Get("testNullableUnsignedInt64"); } + set { BackingStore?.Set("testNullableUnsignedInt64", value); } + } + + /// The testNullableUri property + public string? TestNullableUri + { + get { return BackingStore?.Get("testNullableUri"); } + set { BackingStore?.Set("testNullableUri", value); } + } + + /// The testNullableVersion property + public string? TestNullableVersion + { + get { return BackingStore?.Get("testNullableVersion"); } + set { BackingStore?.Set("testNullableVersion", value); } + } + + /// The testRune property + public string? TestRune + { + get { return BackingStore?.Get("testRune"); } + set { BackingStore?.Set("testRune", value); } + } + + /// The testSignedByte property + public int? TestSignedByte + { + get { return BackingStore?.Get("testSignedByte"); } + set { BackingStore?.Set("testSignedByte", value); } + } + + /// The testString property + public string? TestString + { + get { return BackingStore?.Get("testString"); } + set { BackingStore?.Set("testString", value); } + } + + /// The testTimeOnly property + public Time? TestTimeOnly + { + get { return BackingStore?.Get("testTimeOnly"); } + set { BackingStore?.Set("testTimeOnly", value); } + } + + /// The testTimeSpan property + public TimeSpan? TestTimeSpan + { + get { return BackingStore?.Get("testTimeSpan"); } + set { BackingStore?.Set("testTimeSpan", value); } + } + + /// The testUnsignedInt128 property + public string? TestUnsignedInt128 + { + get { return BackingStore?.Get("testUnsignedInt128"); } + set { BackingStore?.Set("testUnsignedInt128", value); } + } + + /// The testUnsignedInt16 property + public int? TestUnsignedInt16 + { + get { return BackingStore?.Get("testUnsignedInt16"); } + set { BackingStore?.Set("testUnsignedInt16", value); } + } + + /// The testUnsignedInt32 property + public int? TestUnsignedInt32 + { + get { return BackingStore?.Get("testUnsignedInt32"); } + set { BackingStore?.Set("testUnsignedInt32", value); } + } + + /// The testUnsignedInt64 property + public long? TestUnsignedInt64 + { + get { return BackingStore?.Get("testUnsignedInt64"); } + set { BackingStore?.Set("testUnsignedInt64", value); } + } + + /// The testUri property + public string? TestUri + { + get { return BackingStore?.Get("testUri"); } + set { BackingStore?.Set("testUri", value); } + } + + /// The testVersion property + public string? TestVersion + { + get { return BackingStore?.Get("testVersion"); } + set { BackingStore?.Set("testVersion", value); } + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.AttributesInUpdateTypeContainerRequest CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.AttributesInUpdateTypeContainerRequest(); + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public override IDictionary> GetFieldDeserializers() + { + return new Dictionary>(base.GetFieldDeserializers()) + { + { "testBigInteger", n => { TestBigInteger = n.GetStringValue(); } }, + { "testBoolean", n => { TestBoolean = n.GetBoolValue(); } }, + { "testByte", n => { TestByte = n.GetIntValue(); } }, + { "testChar", n => { TestChar = n.GetStringValue(); } }, + { "testComplex", n => { TestComplex = n.GetStringValue(); } }, + { "testDateOnly", n => { TestDateOnly = n.GetDateValue(); } }, + { "testDateTime", n => { TestDateTime = n.GetDateTimeOffsetValue(); } }, + { "testDateTimeOffset", n => { TestDateTimeOffset = n.GetDateTimeOffsetValue(); } }, + { "testDecimal", n => { TestDecimal = n.GetDoubleValue(); } }, + { "testDouble", n => { TestDouble = n.GetDoubleValue(); } }, + { "testEnum", n => { TestEnum = n.GetEnumValue(); } }, + { "testFloat", n => { TestFloat = n.GetFloatValue(); } }, + { "testGuid", n => { TestGuid = n.GetGuidValue(); } }, + { "testHalf", n => { TestHalf = n.GetFloatValue(); } }, + { "testIPAddress", n => { TestIPAddress = n.GetStringValue(); } }, + { "testIPNetwork", n => { TestIPNetwork = n.GetStringValue(); } }, + { "testInt128", n => { TestInt128 = n.GetStringValue(); } }, + { "testInt16", n => { TestInt16 = n.GetIntValue(); } }, + { "testInt32", n => { TestInt32 = n.GetIntValue(); } }, + { "testInt64", n => { TestInt64 = n.GetLongValue(); } }, + { "testNullableBigInteger", n => { TestNullableBigInteger = n.GetStringValue(); } }, + { "testNullableBoolean", n => { TestNullableBoolean = n.GetBoolValue(); } }, + { "testNullableByte", n => { TestNullableByte = n.GetIntValue(); } }, + { "testNullableChar", n => { TestNullableChar = n.GetStringValue(); } }, + { "testNullableComplex", n => { TestNullableComplex = n.GetStringValue(); } }, + { "testNullableDateOnly", n => { TestNullableDateOnly = n.GetDateValue(); } }, + { "testNullableDateTime", n => { TestNullableDateTime = n.GetDateTimeOffsetValue(); } }, + { "testNullableDateTimeOffset", n => { TestNullableDateTimeOffset = n.GetDateTimeOffsetValue(); } }, + { "testNullableDecimal", n => { TestNullableDecimal = n.GetDoubleValue(); } }, + { "testNullableDouble", n => { TestNullableDouble = n.GetDoubleValue(); } }, + { "testNullableEnum", n => { TestNullableEnum = n.GetEnumValue(); } }, + { "testNullableFloat", n => { TestNullableFloat = n.GetFloatValue(); } }, + { "testNullableGuid", n => { TestNullableGuid = n.GetGuidValue(); } }, + { "testNullableHalf", n => { TestNullableHalf = n.GetFloatValue(); } }, + { "testNullableIPAddress", n => { TestNullableIPAddress = n.GetStringValue(); } }, + { "testNullableIPNetwork", n => { TestNullableIPNetwork = n.GetStringValue(); } }, + { "testNullableInt128", n => { TestNullableInt128 = n.GetStringValue(); } }, + { "testNullableInt16", n => { TestNullableInt16 = n.GetIntValue(); } }, + { "testNullableInt32", n => { TestNullableInt32 = n.GetIntValue(); } }, + { "testNullableInt64", n => { TestNullableInt64 = n.GetLongValue(); } }, + { "testNullableRune", n => { TestNullableRune = n.GetStringValue(); } }, + { "testNullableSignedByte", n => { TestNullableSignedByte = n.GetIntValue(); } }, + { "testNullableString", n => { TestNullableString = n.GetStringValue(); } }, + { "testNullableTimeOnly", n => { TestNullableTimeOnly = n.GetTimeValue(); } }, + { "testNullableTimeSpan", n => { TestNullableTimeSpan = n.GetTimeSpanValue(); } }, + { "testNullableUnsignedInt128", n => { TestNullableUnsignedInt128 = n.GetStringValue(); } }, + { "testNullableUnsignedInt16", n => { TestNullableUnsignedInt16 = n.GetIntValue(); } }, + { "testNullableUnsignedInt32", n => { TestNullableUnsignedInt32 = n.GetIntValue(); } }, + { "testNullableUnsignedInt64", n => { TestNullableUnsignedInt64 = n.GetLongValue(); } }, + { "testNullableUri", n => { TestNullableUri = n.GetStringValue(); } }, + { "testNullableVersion", n => { TestNullableVersion = n.GetStringValue(); } }, + { "testRune", n => { TestRune = n.GetStringValue(); } }, + { "testSignedByte", n => { TestSignedByte = n.GetIntValue(); } }, + { "testString", n => { TestString = n.GetStringValue(); } }, + { "testTimeOnly", n => { TestTimeOnly = n.GetTimeValue(); } }, + { "testTimeSpan", n => { TestTimeSpan = n.GetTimeSpanValue(); } }, + { "testUnsignedInt128", n => { TestUnsignedInt128 = n.GetStringValue(); } }, + { "testUnsignedInt16", n => { TestUnsignedInt16 = n.GetIntValue(); } }, + { "testUnsignedInt32", n => { TestUnsignedInt32 = n.GetIntValue(); } }, + { "testUnsignedInt64", n => { TestUnsignedInt64 = n.GetLongValue(); } }, + { "testUri", n => { TestUri = n.GetStringValue(); } }, + { "testVersion", n => { TestVersion = n.GetStringValue(); } }, + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public override void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + base.Serialize(writer); + writer.WriteStringValue("testBigInteger", TestBigInteger); + writer.WriteBoolValue("testBoolean", TestBoolean); + writer.WriteIntValue("testByte", TestByte); + writer.WriteStringValue("testChar", TestChar); + writer.WriteStringValue("testComplex", TestComplex); + writer.WriteDateValue("testDateOnly", TestDateOnly); + writer.WriteDateTimeOffsetValue("testDateTime", TestDateTime); + writer.WriteDateTimeOffsetValue("testDateTimeOffset", TestDateTimeOffset); + writer.WriteDoubleValue("testDecimal", TestDecimal); + writer.WriteDoubleValue("testDouble", TestDouble); + writer.WriteEnumValue("testEnum", TestEnum); + writer.WriteFloatValue("testFloat", TestFloat); + writer.WriteGuidValue("testGuid", TestGuid); + writer.WriteFloatValue("testHalf", TestHalf); + writer.WriteStringValue("testInt128", TestInt128); + writer.WriteIntValue("testInt16", TestInt16); + writer.WriteIntValue("testInt32", TestInt32); + writer.WriteLongValue("testInt64", TestInt64); + writer.WriteStringValue("testIPAddress", TestIPAddress); + writer.WriteStringValue("testIPNetwork", TestIPNetwork); + writer.WriteStringValue("testNullableBigInteger", TestNullableBigInteger); + writer.WriteBoolValue("testNullableBoolean", TestNullableBoolean); + writer.WriteIntValue("testNullableByte", TestNullableByte); + writer.WriteStringValue("testNullableChar", TestNullableChar); + writer.WriteStringValue("testNullableComplex", TestNullableComplex); + writer.WriteDateValue("testNullableDateOnly", TestNullableDateOnly); + writer.WriteDateTimeOffsetValue("testNullableDateTime", TestNullableDateTime); + writer.WriteDateTimeOffsetValue("testNullableDateTimeOffset", TestNullableDateTimeOffset); + writer.WriteDoubleValue("testNullableDecimal", TestNullableDecimal); + writer.WriteDoubleValue("testNullableDouble", TestNullableDouble); + writer.WriteEnumValue("testNullableEnum", TestNullableEnum); + writer.WriteFloatValue("testNullableFloat", TestNullableFloat); + writer.WriteGuidValue("testNullableGuid", TestNullableGuid); + writer.WriteFloatValue("testNullableHalf", TestNullableHalf); + writer.WriteStringValue("testNullableInt128", TestNullableInt128); + writer.WriteIntValue("testNullableInt16", TestNullableInt16); + writer.WriteIntValue("testNullableInt32", TestNullableInt32); + writer.WriteLongValue("testNullableInt64", TestNullableInt64); + writer.WriteStringValue("testNullableIPAddress", TestNullableIPAddress); + writer.WriteStringValue("testNullableIPNetwork", TestNullableIPNetwork); + writer.WriteStringValue("testNullableRune", TestNullableRune); + writer.WriteIntValue("testNullableSignedByte", TestNullableSignedByte); + writer.WriteStringValue("testNullableString", TestNullableString); + writer.WriteTimeValue("testNullableTimeOnly", TestNullableTimeOnly); + writer.WriteTimeSpanValue("testNullableTimeSpan", TestNullableTimeSpan); + writer.WriteStringValue("testNullableUnsignedInt128", TestNullableUnsignedInt128); + writer.WriteIntValue("testNullableUnsignedInt16", TestNullableUnsignedInt16); + writer.WriteIntValue("testNullableUnsignedInt32", TestNullableUnsignedInt32); + writer.WriteLongValue("testNullableUnsignedInt64", TestNullableUnsignedInt64); + writer.WriteStringValue("testNullableUri", TestNullableUri); + writer.WriteStringValue("testNullableVersion", TestNullableVersion); + writer.WriteStringValue("testRune", TestRune); + writer.WriteIntValue("testSignedByte", TestSignedByte); + writer.WriteStringValue("testString", TestString); + writer.WriteTimeValue("testTimeOnly", TestTimeOnly); + writer.WriteTimeSpanValue("testTimeSpan", TestTimeSpan); + writer.WriteStringValue("testUnsignedInt128", TestUnsignedInt128); + writer.WriteIntValue("testUnsignedInt16", TestUnsignedInt16); + writer.WriteIntValue("testUnsignedInt32", TestUnsignedInt32); + writer.WriteLongValue("testUnsignedInt64", TestUnsignedInt64); + writer.WriteStringValue("testUri", TestUri); + writer.WriteStringValue("testVersion", TestVersion); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/CreateTypeContainerRequestDocument.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/CreateTypeContainerRequestDocument.cs new file mode 100644 index 0000000000..2d17a207ae --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/CreateTypeContainerRequestDocument.cs @@ -0,0 +1,79 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions.Store; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class CreateTypeContainerRequestDocument : IBackedModel, IParsable + #pragma warning restore CS1591 + { + /// Stores model information. + public IBackingStore BackingStore { get; private set; } + + /// The data property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.DataInCreateTypeContainerRequest? Data + { + get { return BackingStore?.Get("data"); } + set { BackingStore?.Set("data", value); } + } + + /// The meta property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.Meta? Meta + { + get { return BackingStore?.Get("meta"); } + set { BackingStore?.Set("meta", value); } + } + + /// + /// Instantiates a new and sets the default values. + /// + public CreateTypeContainerRequestDocument() + { + BackingStore = BackingStoreFactorySingleton.Instance.CreateBackingStore(); + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.CreateTypeContainerRequestDocument CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.CreateTypeContainerRequestDocument(); + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "data", n => { Data = n.GetObjectValue(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.DataInCreateTypeContainerRequest.CreateFromDiscriminatorValue); } }, + { "meta", n => { Meta = n.GetObjectValue(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.Meta.CreateFromDiscriminatorValue); } }, + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteObjectValue("data", Data); + writer.WriteObjectValue("meta", Meta); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/DataInCreateTypeContainerRequest.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/DataInCreateTypeContainerRequest.cs new file mode 100644 index 0000000000..5026c57b3d --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/DataInCreateTypeContainerRequest.cs @@ -0,0 +1,59 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class DataInCreateTypeContainerRequest : global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceInCreateRequest, IParsable + #pragma warning restore CS1591 + { + /// The attributes property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.AttributesInCreateTypeContainerRequest? Attributes + { + get { return BackingStore?.Get("attributes"); } + set { BackingStore?.Set("attributes", value); } + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.DataInCreateTypeContainerRequest CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.DataInCreateTypeContainerRequest(); + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public override IDictionary> GetFieldDeserializers() + { + return new Dictionary>(base.GetFieldDeserializers()) + { + { "attributes", n => { Attributes = n.GetObjectValue(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.AttributesInCreateTypeContainerRequest.CreateFromDiscriminatorValue); } }, + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public override void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + base.Serialize(writer); + writer.WriteObjectValue("attributes", Attributes); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/DataInTypeContainerResponse.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/DataInTypeContainerResponse.cs new file mode 100644 index 0000000000..1b5c13662a --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/DataInTypeContainerResponse.cs @@ -0,0 +1,77 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class DataInTypeContainerResponse : global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceInResponse, IParsable + #pragma warning restore CS1591 + { + /// The attributes property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.AttributesInTypeContainerResponse? Attributes + { + get { return BackingStore?.Get("attributes"); } + set { BackingStore?.Set("attributes", value); } + } + + /// The id property + public string? Id + { + get { return BackingStore?.Get("id"); } + set { BackingStore?.Set("id", value); } + } + + /// The links property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceLinks? Links + { + get { return BackingStore?.Get("links"); } + set { BackingStore?.Set("links", value); } + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.DataInTypeContainerResponse CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.DataInTypeContainerResponse(); + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public override IDictionary> GetFieldDeserializers() + { + return new Dictionary>(base.GetFieldDeserializers()) + { + { "attributes", n => { Attributes = n.GetObjectValue(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.AttributesInTypeContainerResponse.CreateFromDiscriminatorValue); } }, + { "id", n => { Id = n.GetStringValue(); } }, + { "links", n => { Links = n.GetObjectValue(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceLinks.CreateFromDiscriminatorValue); } }, + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public override void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + base.Serialize(writer); + writer.WriteObjectValue("attributes", Attributes); + writer.WriteStringValue("id", Id); + writer.WriteObjectValue("links", Links); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/DataInUpdateTypeContainerRequest.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/DataInUpdateTypeContainerRequest.cs new file mode 100644 index 0000000000..4d79626a49 --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/DataInUpdateTypeContainerRequest.cs @@ -0,0 +1,68 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class DataInUpdateTypeContainerRequest : global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceInUpdateRequest, IParsable + #pragma warning restore CS1591 + { + /// The attributes property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.AttributesInUpdateTypeContainerRequest? Attributes + { + get { return BackingStore?.Get("attributes"); } + set { BackingStore?.Set("attributes", value); } + } + + /// The id property + public string? Id + { + get { return BackingStore?.Get("id"); } + set { BackingStore?.Set("id", value); } + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.DataInUpdateTypeContainerRequest CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.DataInUpdateTypeContainerRequest(); + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public override IDictionary> GetFieldDeserializers() + { + return new Dictionary>(base.GetFieldDeserializers()) + { + { "attributes", n => { Attributes = n.GetObjectValue(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.AttributesInUpdateTypeContainerRequest.CreateFromDiscriminatorValue); } }, + { "id", n => { Id = n.GetStringValue(); } }, + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public override void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + base.Serialize(writer); + writer.WriteObjectValue("attributes", Attributes); + writer.WriteStringValue("id", Id); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/DayOfWeekObject.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/DayOfWeekObject.cs new file mode 100644 index 0000000000..7fb6c56583 --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/DayOfWeekObject.cs @@ -0,0 +1,42 @@ +// +#nullable enable +#pragma warning disable CS8625 +using System.Runtime.Serialization; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public enum DayOfWeekObject + #pragma warning restore CS1591 + { + [EnumMember(Value = "Sunday")] + #pragma warning disable CS1591 + Sunday, + #pragma warning restore CS1591 + [EnumMember(Value = "Monday")] + #pragma warning disable CS1591 + Monday, + #pragma warning restore CS1591 + [EnumMember(Value = "Tuesday")] + #pragma warning disable CS1591 + Tuesday, + #pragma warning restore CS1591 + [EnumMember(Value = "Wednesday")] + #pragma warning disable CS1591 + Wednesday, + #pragma warning restore CS1591 + [EnumMember(Value = "Thursday")] + #pragma warning disable CS1591 + Thursday, + #pragma warning restore CS1591 + [EnumMember(Value = "Friday")] + #pragma warning disable CS1591 + Friday, + #pragma warning restore CS1591 + [EnumMember(Value = "Saturday")] + #pragma warning disable CS1591 + Saturday, + #pragma warning restore CS1591 + } +} diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ErrorLinks.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ErrorLinks.cs new file mode 100644 index 0000000000..8b8812d6cf --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ErrorLinks.cs @@ -0,0 +1,79 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions.Store; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class ErrorLinks : IBackedModel, IParsable + #pragma warning restore CS1591 + { + /// The about property + public string? About + { + get { return BackingStore?.Get("about"); } + set { BackingStore?.Set("about", value); } + } + + /// Stores model information. + public IBackingStore BackingStore { get; private set; } + + /// The type property + public string? Type + { + get { return BackingStore?.Get("type"); } + set { BackingStore?.Set("type", value); } + } + + /// + /// Instantiates a new and sets the default values. + /// + public ErrorLinks() + { + BackingStore = BackingStoreFactorySingleton.Instance.CreateBackingStore(); + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorLinks CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorLinks(); + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "about", n => { About = n.GetStringValue(); } }, + { "type", n => { Type = n.GetStringValue(); } }, + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("about", About); + writer.WriteStringValue("type", Type); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ErrorObject.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ErrorObject.cs new file mode 100644 index 0000000000..fbf1296814 --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ErrorObject.cs @@ -0,0 +1,133 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions.Store; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class ErrorObject : IBackedModel, IParsable + #pragma warning restore CS1591 + { + /// Stores model information. + public IBackingStore BackingStore { get; private set; } + + /// The code property + public string? Code + { + get { return BackingStore?.Get("code"); } + set { BackingStore?.Set("code", value); } + } + + /// The detail property + public string? Detail + { + get { return BackingStore?.Get("detail"); } + set { BackingStore?.Set("detail", value); } + } + + /// The id property + public string? Id + { + get { return BackingStore?.Get("id"); } + set { BackingStore?.Set("id", value); } + } + + /// The links property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorLinks? Links + { + get { return BackingStore?.Get("links"); } + set { BackingStore?.Set("links", value); } + } + + /// The meta property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.Meta? Meta + { + get { return BackingStore?.Get("meta"); } + set { BackingStore?.Set("meta", value); } + } + + /// The source property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorSource? Source + { + get { return BackingStore?.Get("source"); } + set { BackingStore?.Set("source", value); } + } + + /// The status property + public string? Status + { + get { return BackingStore?.Get("status"); } + set { BackingStore?.Set("status", value); } + } + + /// The title property + public string? Title + { + get { return BackingStore?.Get("title"); } + set { BackingStore?.Set("title", value); } + } + + /// + /// Instantiates a new and sets the default values. + /// + public ErrorObject() + { + BackingStore = BackingStoreFactorySingleton.Instance.CreateBackingStore(); + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorObject CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorObject(); + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "code", n => { Code = n.GetStringValue(); } }, + { "detail", n => { Detail = n.GetStringValue(); } }, + { "id", n => { Id = n.GetStringValue(); } }, + { "links", n => { Links = n.GetObjectValue(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorLinks.CreateFromDiscriminatorValue); } }, + { "meta", n => { Meta = n.GetObjectValue(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.Meta.CreateFromDiscriminatorValue); } }, + { "source", n => { Source = n.GetObjectValue(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorSource.CreateFromDiscriminatorValue); } }, + { "status", n => { Status = n.GetStringValue(); } }, + { "title", n => { Title = n.GetStringValue(); } }, + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("code", Code); + writer.WriteStringValue("detail", Detail); + writer.WriteStringValue("id", Id); + writer.WriteObjectValue("links", Links); + writer.WriteObjectValue("meta", Meta); + writer.WriteObjectValue("source", Source); + writer.WriteStringValue("status", Status); + writer.WriteStringValue("title", Title); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ErrorResponseDocument.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ErrorResponseDocument.cs new file mode 100644 index 0000000000..e979965e26 --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ErrorResponseDocument.cs @@ -0,0 +1,92 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions.Store; +using Microsoft.Kiota.Abstractions; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class ErrorResponseDocument : ApiException, IBackedModel, IParsable + #pragma warning restore CS1591 + { + /// Stores model information. + public IBackingStore BackingStore { get; private set; } + + /// The errors property + public List? Errors + { + get { return BackingStore?.Get?>("errors"); } + set { BackingStore?.Set("errors", value); } + } + + /// The links property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorTopLevelLinks? Links + { + get { return BackingStore?.Get("links"); } + set { BackingStore?.Set("links", value); } + } + + /// The primary error message. + public override string Message { get => base.Message; } + + /// The meta property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.Meta? Meta + { + get { return BackingStore?.Get("meta"); } + set { BackingStore?.Set("meta", value); } + } + + /// + /// Instantiates a new and sets the default values. + /// + public ErrorResponseDocument() + { + BackingStore = BackingStoreFactorySingleton.Instance.CreateBackingStore(); + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorResponseDocument CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorResponseDocument(); + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "errors", n => { Errors = n.GetCollectionOfObjectValues(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorObject.CreateFromDiscriminatorValue)?.AsList(); } }, + { "links", n => { Links = n.GetObjectValue(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorTopLevelLinks.CreateFromDiscriminatorValue); } }, + { "meta", n => { Meta = n.GetObjectValue(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.Meta.CreateFromDiscriminatorValue); } }, + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteCollectionOfObjectValues("errors", Errors); + writer.WriteObjectValue("links", Links); + writer.WriteObjectValue("meta", Meta); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ErrorSource.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ErrorSource.cs new file mode 100644 index 0000000000..5516df2c9a --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ErrorSource.cs @@ -0,0 +1,88 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions.Store; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class ErrorSource : IBackedModel, IParsable + #pragma warning restore CS1591 + { + /// Stores model information. + public IBackingStore BackingStore { get; private set; } + + /// The header property + public string? Header + { + get { return BackingStore?.Get("header"); } + set { BackingStore?.Set("header", value); } + } + + /// The parameter property + public string? Parameter + { + get { return BackingStore?.Get("parameter"); } + set { BackingStore?.Set("parameter", value); } + } + + /// The pointer property + public string? Pointer + { + get { return BackingStore?.Get("pointer"); } + set { BackingStore?.Set("pointer", value); } + } + + /// + /// Instantiates a new and sets the default values. + /// + public ErrorSource() + { + BackingStore = BackingStoreFactorySingleton.Instance.CreateBackingStore(); + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorSource CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorSource(); + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "header", n => { Header = n.GetStringValue(); } }, + { "parameter", n => { Parameter = n.GetStringValue(); } }, + { "pointer", n => { Pointer = n.GetStringValue(); } }, + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("header", Header); + writer.WriteStringValue("parameter", Parameter); + writer.WriteStringValue("pointer", Pointer); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ErrorTopLevelLinks.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ErrorTopLevelLinks.cs new file mode 100644 index 0000000000..4056951653 --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ErrorTopLevelLinks.cs @@ -0,0 +1,79 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions.Store; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class ErrorTopLevelLinks : IBackedModel, IParsable + #pragma warning restore CS1591 + { + /// Stores model information. + public IBackingStore BackingStore { get; private set; } + + /// The describedby property + public string? Describedby + { + get { return BackingStore?.Get("describedby"); } + set { BackingStore?.Set("describedby", value); } + } + + /// The self property + public string? Self + { + get { return BackingStore?.Get("self"); } + set { BackingStore?.Set("self", value); } + } + + /// + /// Instantiates a new and sets the default values. + /// + public ErrorTopLevelLinks() + { + BackingStore = BackingStoreFactorySingleton.Instance.CreateBackingStore(); + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorTopLevelLinks CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorTopLevelLinks(); + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "describedby", n => { Describedby = n.GetStringValue(); } }, + { "self", n => { Self = n.GetStringValue(); } }, + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("describedby", Describedby); + writer.WriteStringValue("self", Self); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/Meta.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/Meta.cs new file mode 100644 index 0000000000..12ad99a43a --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/Meta.cs @@ -0,0 +1,70 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions.Store; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class Meta : IAdditionalDataHolder, IBackedModel, IParsable + #pragma warning restore CS1591 + { + /// Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + public IDictionary AdditionalData + { + get { return BackingStore.Get>("AdditionalData") ?? new Dictionary(); } + set { BackingStore.Set("AdditionalData", value); } + } + + /// Stores model information. + public IBackingStore BackingStore { get; private set; } + + /// + /// Instantiates a new and sets the default values. + /// + public Meta() + { + BackingStore = BackingStoreFactorySingleton.Instance.CreateBackingStore(); + AdditionalData = new Dictionary(); + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.Meta CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.Meta(); + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteAdditionalData(AdditionalData); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/PrimaryTypeContainerResponseDocument.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/PrimaryTypeContainerResponseDocument.cs new file mode 100644 index 0000000000..02614ad081 --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/PrimaryTypeContainerResponseDocument.cs @@ -0,0 +1,97 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions.Store; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class PrimaryTypeContainerResponseDocument : IBackedModel, IParsable + #pragma warning restore CS1591 + { + /// Stores model information. + public IBackingStore BackingStore { get; private set; } + + /// The data property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.DataInTypeContainerResponse? Data + { + get { return BackingStore?.Get("data"); } + set { BackingStore?.Set("data", value); } + } + + /// The included property + public List? Included + { + get { return BackingStore?.Get?>("included"); } + set { BackingStore?.Set("included", value); } + } + + /// The links property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceTopLevelLinks? Links + { + get { return BackingStore?.Get("links"); } + set { BackingStore?.Set("links", value); } + } + + /// The meta property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.Meta? Meta + { + get { return BackingStore?.Get("meta"); } + set { BackingStore?.Set("meta", value); } + } + + /// + /// Instantiates a new and sets the default values. + /// + public PrimaryTypeContainerResponseDocument() + { + BackingStore = BackingStoreFactorySingleton.Instance.CreateBackingStore(); + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.PrimaryTypeContainerResponseDocument CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.PrimaryTypeContainerResponseDocument(); + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "data", n => { Data = n.GetObjectValue(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.DataInTypeContainerResponse.CreateFromDiscriminatorValue); } }, + { "included", n => { Included = n.GetCollectionOfObjectValues(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceInResponse.CreateFromDiscriminatorValue)?.AsList(); } }, + { "links", n => { Links = n.GetObjectValue(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceTopLevelLinks.CreateFromDiscriminatorValue); } }, + { "meta", n => { Meta = n.GetObjectValue(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.Meta.CreateFromDiscriminatorValue); } }, + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteObjectValue("data", Data); + writer.WriteCollectionOfObjectValues("included", Included); + writer.WriteObjectValue("links", Links); + writer.WriteObjectValue("meta", Meta); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ResourceCollectionTopLevelLinks.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ResourceCollectionTopLevelLinks.cs new file mode 100644 index 0000000000..473e39b5fa --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ResourceCollectionTopLevelLinks.cs @@ -0,0 +1,115 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions.Store; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class ResourceCollectionTopLevelLinks : IBackedModel, IParsable + #pragma warning restore CS1591 + { + /// Stores model information. + public IBackingStore BackingStore { get; private set; } + + /// The describedby property + public string? Describedby + { + get { return BackingStore?.Get("describedby"); } + set { BackingStore?.Set("describedby", value); } + } + + /// The first property + public string? First + { + get { return BackingStore?.Get("first"); } + set { BackingStore?.Set("first", value); } + } + + /// The last property + public string? Last + { + get { return BackingStore?.Get("last"); } + set { BackingStore?.Set("last", value); } + } + + /// The next property + public string? Next + { + get { return BackingStore?.Get("next"); } + set { BackingStore?.Set("next", value); } + } + + /// The prev property + public string? Prev + { + get { return BackingStore?.Get("prev"); } + set { BackingStore?.Set("prev", value); } + } + + /// The self property + public string? Self + { + get { return BackingStore?.Get("self"); } + set { BackingStore?.Set("self", value); } + } + + /// + /// Instantiates a new and sets the default values. + /// + public ResourceCollectionTopLevelLinks() + { + BackingStore = BackingStoreFactorySingleton.Instance.CreateBackingStore(); + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceCollectionTopLevelLinks CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceCollectionTopLevelLinks(); + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "describedby", n => { Describedby = n.GetStringValue(); } }, + { "first", n => { First = n.GetStringValue(); } }, + { "last", n => { Last = n.GetStringValue(); } }, + { "next", n => { Next = n.GetStringValue(); } }, + { "prev", n => { Prev = n.GetStringValue(); } }, + { "self", n => { Self = n.GetStringValue(); } }, + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("describedby", Describedby); + writer.WriteStringValue("first", First); + writer.WriteStringValue("last", Last); + writer.WriteStringValue("next", Next); + writer.WriteStringValue("prev", Prev); + writer.WriteStringValue("self", Self); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ResourceInCreateRequest.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ResourceInCreateRequest.cs new file mode 100644 index 0000000000..fc2d7e75db --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ResourceInCreateRequest.cs @@ -0,0 +1,84 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions.Store; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class ResourceInCreateRequest : IBackedModel, IParsable + #pragma warning restore CS1591 + { + /// Stores model information. + public IBackingStore BackingStore { get; private set; } + + /// The meta property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.Meta? Meta + { + get { return BackingStore?.Get("meta"); } + set { BackingStore?.Set("meta", value); } + } + + /// The type property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceType? Type + { + get { return BackingStore?.Get("type"); } + set { BackingStore?.Set("type", value); } + } + + /// + /// Instantiates a new and sets the default values. + /// + public ResourceInCreateRequest() + { + BackingStore = BackingStoreFactorySingleton.Instance.CreateBackingStore(); + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceInCreateRequest CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + var mappingValue = parseNode.GetChildNode("type")?.GetStringValue(); + return mappingValue switch + { + "typeContainers" => new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.DataInCreateTypeContainerRequest(), + _ => new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceInCreateRequest(), + }; + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "meta", n => { Meta = n.GetObjectValue(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.Meta.CreateFromDiscriminatorValue); } }, + { "type", n => { Type = n.GetEnumValue(); } }, + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteObjectValue("meta", Meta); + writer.WriteEnumValue("type", Type); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ResourceInResponse.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ResourceInResponse.cs new file mode 100644 index 0000000000..66b85a9d72 --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ResourceInResponse.cs @@ -0,0 +1,84 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions.Store; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class ResourceInResponse : IBackedModel, IParsable + #pragma warning restore CS1591 + { + /// Stores model information. + public IBackingStore BackingStore { get; private set; } + + /// The meta property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.Meta? Meta + { + get { return BackingStore?.Get("meta"); } + set { BackingStore?.Set("meta", value); } + } + + /// The type property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceType? Type + { + get { return BackingStore?.Get("type"); } + set { BackingStore?.Set("type", value); } + } + + /// + /// Instantiates a new and sets the default values. + /// + public ResourceInResponse() + { + BackingStore = BackingStoreFactorySingleton.Instance.CreateBackingStore(); + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceInResponse CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + var mappingValue = parseNode.GetChildNode("type")?.GetStringValue(); + return mappingValue switch + { + "typeContainers" => new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.DataInTypeContainerResponse(), + _ => new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceInResponse(), + }; + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "meta", n => { Meta = n.GetObjectValue(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.Meta.CreateFromDiscriminatorValue); } }, + { "type", n => { Type = n.GetEnumValue(); } }, + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteObjectValue("meta", Meta); + writer.WriteEnumValue("type", Type); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ResourceInUpdateRequest.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ResourceInUpdateRequest.cs new file mode 100644 index 0000000000..3f993cffa1 --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ResourceInUpdateRequest.cs @@ -0,0 +1,84 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions.Store; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class ResourceInUpdateRequest : IBackedModel, IParsable + #pragma warning restore CS1591 + { + /// Stores model information. + public IBackingStore BackingStore { get; private set; } + + /// The meta property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.Meta? Meta + { + get { return BackingStore?.Get("meta"); } + set { BackingStore?.Set("meta", value); } + } + + /// The type property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceType? Type + { + get { return BackingStore?.Get("type"); } + set { BackingStore?.Set("type", value); } + } + + /// + /// Instantiates a new and sets the default values. + /// + public ResourceInUpdateRequest() + { + BackingStore = BackingStoreFactorySingleton.Instance.CreateBackingStore(); + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceInUpdateRequest CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + var mappingValue = parseNode.GetChildNode("type")?.GetStringValue(); + return mappingValue switch + { + "typeContainers" => new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.DataInUpdateTypeContainerRequest(), + _ => new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceInUpdateRequest(), + }; + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "meta", n => { Meta = n.GetObjectValue(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.Meta.CreateFromDiscriminatorValue); } }, + { "type", n => { Type = n.GetEnumValue(); } }, + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteObjectValue("meta", Meta); + writer.WriteEnumValue("type", Type); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ResourceLinks.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ResourceLinks.cs new file mode 100644 index 0000000000..19e8f5a193 --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ResourceLinks.cs @@ -0,0 +1,70 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions.Store; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class ResourceLinks : IBackedModel, IParsable + #pragma warning restore CS1591 + { + /// Stores model information. + public IBackingStore BackingStore { get; private set; } + + /// The self property + public string? Self + { + get { return BackingStore?.Get("self"); } + set { BackingStore?.Set("self", value); } + } + + /// + /// Instantiates a new and sets the default values. + /// + public ResourceLinks() + { + BackingStore = BackingStoreFactorySingleton.Instance.CreateBackingStore(); + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceLinks CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceLinks(); + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "self", n => { Self = n.GetStringValue(); } }, + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("self", Self); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ResourceTopLevelLinks.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ResourceTopLevelLinks.cs new file mode 100644 index 0000000000..892d65e04b --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ResourceTopLevelLinks.cs @@ -0,0 +1,79 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions.Store; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class ResourceTopLevelLinks : IBackedModel, IParsable + #pragma warning restore CS1591 + { + /// Stores model information. + public IBackingStore BackingStore { get; private set; } + + /// The describedby property + public string? Describedby + { + get { return BackingStore?.Get("describedby"); } + set { BackingStore?.Set("describedby", value); } + } + + /// The self property + public string? Self + { + get { return BackingStore?.Get("self"); } + set { BackingStore?.Set("self", value); } + } + + /// + /// Instantiates a new and sets the default values. + /// + public ResourceTopLevelLinks() + { + BackingStore = BackingStoreFactorySingleton.Instance.CreateBackingStore(); + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceTopLevelLinks CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceTopLevelLinks(); + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "describedby", n => { Describedby = n.GetStringValue(); } }, + { "self", n => { Self = n.GetStringValue(); } }, + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteStringValue("describedby", Describedby); + writer.WriteStringValue("self", Self); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ResourceType.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ResourceType.cs new file mode 100644 index 0000000000..29215d537c --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/ResourceType.cs @@ -0,0 +1,18 @@ +// +#nullable enable +#pragma warning disable CS8625 +using System.Runtime.Serialization; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public enum ResourceType + #pragma warning restore CS1591 + { + [EnumMember(Value = "typeContainers")] + #pragma warning disable CS1591 + TypeContainers, + #pragma warning restore CS1591 + } +} diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/TypeContainerCollectionResponseDocument.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/TypeContainerCollectionResponseDocument.cs new file mode 100644 index 0000000000..0a57964118 --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/TypeContainerCollectionResponseDocument.cs @@ -0,0 +1,97 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions.Store; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class TypeContainerCollectionResponseDocument : IBackedModel, IParsable + #pragma warning restore CS1591 + { + /// Stores model information. + public IBackingStore BackingStore { get; private set; } + + /// The data property + public List? Data + { + get { return BackingStore?.Get?>("data"); } + set { BackingStore?.Set("data", value); } + } + + /// The included property + public List? Included + { + get { return BackingStore?.Get?>("included"); } + set { BackingStore?.Set("included", value); } + } + + /// The links property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceCollectionTopLevelLinks? Links + { + get { return BackingStore?.Get("links"); } + set { BackingStore?.Set("links", value); } + } + + /// The meta property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.Meta? Meta + { + get { return BackingStore?.Get("meta"); } + set { BackingStore?.Set("meta", value); } + } + + /// + /// Instantiates a new and sets the default values. + /// + public TypeContainerCollectionResponseDocument() + { + BackingStore = BackingStoreFactorySingleton.Instance.CreateBackingStore(); + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.TypeContainerCollectionResponseDocument CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.TypeContainerCollectionResponseDocument(); + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "data", n => { Data = n.GetCollectionOfObjectValues(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.DataInTypeContainerResponse.CreateFromDiscriminatorValue)?.AsList(); } }, + { "included", n => { Included = n.GetCollectionOfObjectValues(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceInResponse.CreateFromDiscriminatorValue)?.AsList(); } }, + { "links", n => { Links = n.GetObjectValue(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ResourceCollectionTopLevelLinks.CreateFromDiscriminatorValue); } }, + { "meta", n => { Meta = n.GetObjectValue(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.Meta.CreateFromDiscriminatorValue); } }, + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteCollectionOfObjectValues("data", Data); + writer.WriteCollectionOfObjectValues("included", Included); + writer.WriteObjectValue("links", Links); + writer.WriteObjectValue("meta", Meta); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/UpdateTypeContainerRequestDocument.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/UpdateTypeContainerRequestDocument.cs new file mode 100644 index 0000000000..f545be4f88 --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/Models/UpdateTypeContainerRequestDocument.cs @@ -0,0 +1,79 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions.Store; +using System.Collections.Generic; +using System.IO; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models +{ + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + #pragma warning disable CS1591 + public partial class UpdateTypeContainerRequestDocument : IBackedModel, IParsable + #pragma warning restore CS1591 + { + /// Stores model information. + public IBackingStore BackingStore { get; private set; } + + /// The data property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.DataInUpdateTypeContainerRequest? Data + { + get { return BackingStore?.Get("data"); } + set { BackingStore?.Set("data", value); } + } + + /// The meta property + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.Meta? Meta + { + get { return BackingStore?.Get("meta"); } + set { BackingStore?.Set("meta", value); } + } + + /// + /// Instantiates a new and sets the default values. + /// + public UpdateTypeContainerRequestDocument() + { + BackingStore = BackingStoreFactorySingleton.Instance.CreateBackingStore(); + } + + /// + /// Creates a new instance of the appropriate class based on discriminator value + /// + /// A + /// The parse node to use to read the discriminator value and create the object + public static global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.UpdateTypeContainerRequestDocument CreateFromDiscriminatorValue(IParseNode parseNode) + { + if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode)); + return new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.UpdateTypeContainerRequestDocument(); + } + + /// + /// The deserialization information for the current model + /// + /// A IDictionary<string, Action<IParseNode>> + public virtual IDictionary> GetFieldDeserializers() + { + return new Dictionary> + { + { "data", n => { Data = n.GetObjectValue(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.DataInUpdateTypeContainerRequest.CreateFromDiscriminatorValue); } }, + { "meta", n => { Meta = n.GetObjectValue(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.Meta.CreateFromDiscriminatorValue); } }, + }; + } + + /// + /// Serializes information the current object + /// + /// Serialization writer to use to serialize this model + public virtual void Serialize(ISerializationWriter writer) + { + if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer)); + writer.WriteObjectValue("data", Data); + writer.WriteObjectValue("meta", Meta); + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/TypeContainers/Item/TypeContainersItemRequestBuilder.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/TypeContainers/Item/TypeContainersItemRequestBuilder.cs new file mode 100644 index 0000000000..ab7c504bdc --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/TypeContainers/Item/TypeContainersItemRequestBuilder.cs @@ -0,0 +1,209 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Threading; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.TypeContainers.Item +{ + /// + /// Builds and executes requests for operations under \typeContainers\{id} + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class TypeContainersItemRequestBuilder : BaseRequestBuilder + { + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public TypeContainersItemRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/typeContainers/{id}{?query*}", pathParameters) + { + } + + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public TypeContainersItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/typeContainers/{id}{?query*}", rawUrl) + { + } + + /// + /// Deletes an existing typeContainer by its identifier. + /// + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 404 status code + public async Task DeleteAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { + var requestInfo = ToDeleteRequestInformation(requestConfiguration); + var errorMapping = new Dictionary> + { + { "404", global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorResponseDocument.CreateFromDiscriminatorValue }, + }; + await RequestAdapter.SendNoContentAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false); + } + + /// + /// Retrieves an individual typeContainer by its identifier. + /// + /// A + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code + /// When receiving a 404 status code + public async Task GetAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { + var requestInfo = ToGetRequestInformation(requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorResponseDocument.CreateFromDiscriminatorValue }, + { "404", global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorResponseDocument.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendAsync(requestInfo, global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.PrimaryTypeContainerResponseDocument.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false); + } + + /// + /// Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched. + /// + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + public async Task HeadAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { + var requestInfo = ToHeadRequestInformation(requestConfiguration); + await RequestAdapter.SendNoContentAsync(requestInfo, default, cancellationToken).ConfigureAwait(false); + } + + /// + /// Updates an existing typeContainer. + /// + /// A + /// The request body + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code + /// When receiving a 404 status code + /// When receiving a 409 status code + /// When receiving a 422 status code + public async Task PatchAsync(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.UpdateTypeContainerRequestDocument body, Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = ToPatchRequestInformation(body, requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorResponseDocument.CreateFromDiscriminatorValue }, + { "404", global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorResponseDocument.CreateFromDiscriminatorValue }, + { "409", global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorResponseDocument.CreateFromDiscriminatorValue }, + { "422", global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorResponseDocument.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendAsync(requestInfo, global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.PrimaryTypeContainerResponseDocument.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false); + } + + /// + /// Deletes an existing typeContainer by its identifier. + /// + /// A + /// Configuration for the request such as headers, query parameters, and middleware options. + public RequestInformation ToDeleteRequestInformation(Action>? requestConfiguration = default) + { + var requestInfo = new RequestInformation(Method.DELETE, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/vnd.api+json;ext=openapi"); + return requestInfo; + } + + /// + /// Retrieves an individual typeContainer by its identifier. + /// + /// A + /// Configuration for the request such as headers, query parameters, and middleware options. + public RequestInformation ToGetRequestInformation(Action>? requestConfiguration = default) + { + var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/vnd.api+json;ext=openapi"); + return requestInfo; + } + + /// + /// Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched. + /// + /// A + /// Configuration for the request such as headers, query parameters, and middleware options. + public RequestInformation ToHeadRequestInformation(Action>? requestConfiguration = default) + { + var requestInfo = new RequestInformation(Method.HEAD, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + return requestInfo; + } + + /// + /// Updates an existing typeContainer. + /// + /// A + /// The request body + /// Configuration for the request such as headers, query parameters, and middleware options. + public RequestInformation ToPatchRequestInformation(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.UpdateTypeContainerRequestDocument body, Action>? requestConfiguration = default) + { + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = new RequestInformation(Method.PATCH, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/vnd.api+json;ext=openapi"); + requestInfo.SetContentFromParsable(RequestAdapter, "application/vnd.api+json;ext=openapi", body); + return requestInfo; + } + + /// + /// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored. + /// + /// A + /// The raw URL to use for the request builder. + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.TypeContainers.Item.TypeContainersItemRequestBuilder WithUrl(string rawUrl) + { + return new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.TypeContainers.Item.TypeContainersItemRequestBuilder(rawUrl, RequestAdapter); + } + + /// + /// Retrieves an individual typeContainer by its identifier. + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class TypeContainersItemRequestBuilderGetQueryParameters + { + /// For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters. + [QueryParameter("query")] + public string? Query { get; set; } + } + + /// + /// Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched. + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class TypeContainersItemRequestBuilderHeadQueryParameters + { + /// For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters. + [QueryParameter("query")] + public string? Query { get; set; } + } + + /// + /// Updates an existing typeContainer. + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class TypeContainersItemRequestBuilderPatchQueryParameters + { + /// For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters. + [QueryParameter("query")] + public string? Query { get; set; } + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/TypeContainers/TypeContainersRequestBuilder.cs b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/TypeContainers/TypeContainersRequestBuilder.cs new file mode 100644 index 0000000000..633f065951 --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/AttributeTypes/GeneratedCode/TypeContainers/TypeContainersRequestBuilder.cs @@ -0,0 +1,194 @@ +// +#nullable enable +#pragma warning disable CS8625 +#pragma warning disable CS0618 +using Microsoft.Kiota.Abstractions.Extensions; +using Microsoft.Kiota.Abstractions.Serialization; +using Microsoft.Kiota.Abstractions; +using OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models; +using OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.TypeContainers.Item; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using System.Threading; +using System; +namespace OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.TypeContainers +{ + /// + /// Builds and executes requests for operations under \typeContainers + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class TypeContainersRequestBuilder : BaseRequestBuilder + { + /// Gets an item from the OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.typeContainers.item collection + /// The identifier of the typeContainer to retrieve. + /// A + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.TypeContainers.Item.TypeContainersItemRequestBuilder this[string position] + { + get + { + var urlTplParams = new Dictionary(PathParameters); + urlTplParams.Add("id", position); + return new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.TypeContainers.Item.TypeContainersItemRequestBuilder(urlTplParams, RequestAdapter); + } + } + + /// + /// Instantiates a new and sets the default values. + /// + /// Path parameters for the request + /// The request adapter to use to execute the requests. + public TypeContainersRequestBuilder(Dictionary pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/typeContainers{?query*}", pathParameters) + { + } + + /// + /// Instantiates a new and sets the default values. + /// + /// The raw URL to use for the request builder. + /// The request adapter to use to execute the requests. + public TypeContainersRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/typeContainers{?query*}", rawUrl) + { + } + + /// + /// Retrieves a collection of typeContainers. + /// + /// A + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code + public async Task GetAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { + var requestInfo = ToGetRequestInformation(requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorResponseDocument.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendAsync(requestInfo, global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.TypeContainerCollectionResponseDocument.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false); + } + + /// + /// Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched. + /// + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + public async Task HeadAsync(Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { + var requestInfo = ToHeadRequestInformation(requestConfiguration); + await RequestAdapter.SendNoContentAsync(requestInfo, default, cancellationToken).ConfigureAwait(false); + } + + /// + /// Creates a new typeContainer. + /// + /// A + /// The request body + /// Cancellation token to use when cancelling requests + /// Configuration for the request such as headers, query parameters, and middleware options. + /// When receiving a 400 status code + /// When receiving a 403 status code + /// When receiving a 404 status code + /// When receiving a 409 status code + /// When receiving a 422 status code + public async Task PostAsync(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.CreateTypeContainerRequestDocument body, Action>? requestConfiguration = default, CancellationToken cancellationToken = default) + { + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = ToPostRequestInformation(body, requestConfiguration); + var errorMapping = new Dictionary> + { + { "400", global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorResponseDocument.CreateFromDiscriminatorValue }, + { "403", global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorResponseDocument.CreateFromDiscriminatorValue }, + { "404", global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorResponseDocument.CreateFromDiscriminatorValue }, + { "409", global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorResponseDocument.CreateFromDiscriminatorValue }, + { "422", global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.ErrorResponseDocument.CreateFromDiscriminatorValue }, + }; + return await RequestAdapter.SendAsync(requestInfo, global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.PrimaryTypeContainerResponseDocument.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false); + } + + /// + /// Retrieves a collection of typeContainers. + /// + /// A + /// Configuration for the request such as headers, query parameters, and middleware options. + public RequestInformation ToGetRequestInformation(Action>? requestConfiguration = default) + { + var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/vnd.api+json;ext=openapi"); + return requestInfo; + } + + /// + /// Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched. + /// + /// A + /// Configuration for the request such as headers, query parameters, and middleware options. + public RequestInformation ToHeadRequestInformation(Action>? requestConfiguration = default) + { + var requestInfo = new RequestInformation(Method.HEAD, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + return requestInfo; + } + + /// + /// Creates a new typeContainer. + /// + /// A + /// The request body + /// Configuration for the request such as headers, query parameters, and middleware options. + public RequestInformation ToPostRequestInformation(global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.Models.CreateTypeContainerRequestDocument body, Action>? requestConfiguration = default) + { + if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body)); + var requestInfo = new RequestInformation(Method.POST, UrlTemplate, PathParameters); + requestInfo.Configure(requestConfiguration); + requestInfo.Headers.TryAdd("Accept", "application/vnd.api+json;ext=openapi"); + requestInfo.SetContentFromParsable(RequestAdapter, "application/vnd.api+json;ext=openapi", body); + return requestInfo; + } + + /// + /// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored. + /// + /// A + /// The raw URL to use for the request builder. + public global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.TypeContainers.TypeContainersRequestBuilder WithUrl(string rawUrl) + { + return new global::OpenApiKiotaEndToEndTests.AttributeTypes.GeneratedCode.TypeContainers.TypeContainersRequestBuilder(rawUrl, RequestAdapter); + } + + /// + /// Retrieves a collection of typeContainers. + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class TypeContainersRequestBuilderGetQueryParameters + { + /// For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters. + [QueryParameter("query")] + public string? Query { get; set; } + } + + /// + /// Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched. + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class TypeContainersRequestBuilderHeadQueryParameters + { + /// For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters. + [QueryParameter("query")] + public string? Query { get; set; } + } + + /// + /// Creates a new typeContainer. + /// + [global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")] + public partial class TypeContainersRequestBuilderPostQueryParameters + { + /// For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters. + [QueryParameter("query")] + public string? Query { get; set; } + } + } +} +#pragma warning restore CS0618 diff --git a/test/OpenApiKiotaEndToEndTests/ModelStateValidation/UtcDateTimeJsonConverter.cs b/test/OpenApiKiotaEndToEndTests/ModelStateValidation/UtcDateTimeJsonConverter.cs deleted file mode 100644 index d4d22fa27e..0000000000 --- a/test/OpenApiKiotaEndToEndTests/ModelStateValidation/UtcDateTimeJsonConverter.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace OpenApiKiotaEndToEndTests.ModelStateValidation; - -internal sealed class UtcDateTimeJsonConverter : JsonConverter -{ - public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - DateTimeOffset dateTimeOffset = DateTimeOffset.Parse(reader.GetString()!); - return dateTimeOffset.UtcDateTime; - } - - public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) - { - writer.WriteStringValue(value.ToUniversalTime().ToString("O")); - } -} diff --git a/test/OpenApiKiotaEndToEndTests/OpenApiKiotaEndToEndTests.csproj b/test/OpenApiKiotaEndToEndTests/OpenApiKiotaEndToEndTests.csproj index 06ee9925e8..4e5e8dded9 100644 --- a/test/OpenApiKiotaEndToEndTests/OpenApiKiotaEndToEndTests.csproj +++ b/test/OpenApiKiotaEndToEndTests/OpenApiKiotaEndToEndTests.csproj @@ -30,6 +30,13 @@ ./%(Name)/GeneratedCode $(JsonApiExtraArguments) + + AttributeTypes + $(MSBuildProjectName).%(Name).GeneratedCode + %(Name)Client + ./%(Name)/GeneratedCode + $(JsonApiExtraArguments) + ClientIdGenerationModes $(MSBuildProjectName).%(Name).GeneratedCode diff --git a/test/OpenApiKiotaEndToEndTests/TimeSpanAsXmlJsonConverter.cs b/test/OpenApiKiotaEndToEndTests/TimeSpanAsXmlJsonConverter.cs new file mode 100644 index 0000000000..c8c45bcedc --- /dev/null +++ b/test/OpenApiKiotaEndToEndTests/TimeSpanAsXmlJsonConverter.cs @@ -0,0 +1,8 @@ +using System.Xml; +using OpenApiTests; + +namespace OpenApiKiotaEndToEndTests; + +// Kiota requires ISO8601 syntax when "duration" format is used in OpenAPI. +internal sealed class TimeSpanAsXmlJsonConverter() + : ValueTypeJsonConverter(XmlConvert.ToTimeSpan, XmlConvert.ToString); diff --git a/test/OpenApiNSwagEndToEndTests/AttributeTypes/AttributeTypeTests.cs b/test/OpenApiNSwagEndToEndTests/AttributeTypes/AttributeTypeTests.cs new file mode 100644 index 0000000000..8b1561ace9 --- /dev/null +++ b/test/OpenApiNSwagEndToEndTests/AttributeTypes/AttributeTypeTests.cs @@ -0,0 +1,944 @@ +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Net; +using System.Reflection; +using FluentAssertions; +using Humanizer; +using JsonApiDotNetCore.Configuration; +using JsonApiDotNetCore.OpenApi.Client.NSwag; +using JsonApiDotNetCore.Resources; +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json.Linq; +using OpenApiNSwagEndToEndTests.AttributeTypes.GeneratedCode; +using OpenApiTests; +using OpenApiTests.AttributeTypes; +using TestBuildingBlocks; +using Xunit; +using Xunit.Abstractions; +using ClientDayOfWeek = OpenApiNSwagEndToEndTests.AttributeTypes.GeneratedCode.DayOfWeek; +using ServerDayOfWeek = System.DayOfWeek; + +namespace OpenApiNSwagEndToEndTests.AttributeTypes; + +public sealed class AttributeTypeTests : IClassFixture>, IDisposable +{ + private readonly IntegrationTestContext _testContext; + private readonly XUnitLogHttpMessageHandler _logHttpMessageHandler; + private readonly AttributeTypesFakers _fakers = new(); + + public AttributeTypeTests(IntegrationTestContext testContext, ITestOutputHelper testOutputHelper) + { + _testContext = testContext; + _logHttpMessageHandler = new XUnitLogHttpMessageHandler(testOutputHelper); + + testContext.UseController(); + + testContext.ConfigureServices(services => services.AddScoped(typeof(IResourceChangeTracker<>), typeof(NeverSameResourceChangeTracker<>))); + + var options = testContext.Factory.Services.GetRequiredService(); + options.SerializerOptions.Converters.Add(new UtcDateTimeJsonConverter()); + } + + [Fact] + public async Task Can_create_resource_with_all_attributes_set_to_valid_values() + { + // Arrange + TypeContainer newContainer = _fakers.TypeContainer.GenerateOne(); + + using HttpClient httpClient = _testContext.Factory.CreateDefaultClient(_logHttpMessageHandler); + AttributeTypesClient apiClient = new(httpClient); + + var requestBody = new CreateTypeContainerRequestDocument + { + Data = new DataInCreateTypeContainerRequest + { + Attributes = new AttributesInCreateTypeContainerRequest + { + TestBoolean = newContainer.TestBoolean, + TestNullableBoolean = newContainer.TestNullableBoolean, + TestByte = newContainer.TestByte, + TestNullableByte = newContainer.TestNullableByte, + TestSignedByte = newContainer.TestSignedByte, + TestNullableSignedByte = newContainer.TestNullableSignedByte, + TestInt16 = newContainer.TestInt16, + TestNullableInt16 = newContainer.TestNullableInt16, + TestUnsignedInt16 = newContainer.TestUnsignedInt16, + TestNullableUnsignedInt16 = newContainer.TestNullableUnsignedInt16, + TestInt32 = newContainer.TestInt32, + TestNullableInt32 = newContainer.TestNullableInt32, + TestUnsignedInt32 = checked((int)newContainer.TestUnsignedInt32), + TestNullableUnsignedInt32 = checked((int?)newContainer.TestNullableUnsignedInt32), + TestInt64 = newContainer.TestInt64, + TestNullableInt64 = newContainer.TestNullableInt64, + TestUnsignedInt64 = checked((long)newContainer.TestUnsignedInt64), + TestNullableUnsignedInt64 = checked((long?)newContainer.TestNullableUnsignedInt64), + TestInt128 = newContainer.TestInt128.ToString(CultureInfo.InvariantCulture), + TestNullableInt128 = newContainer.TestNullableInt128?.ToString(CultureInfo.InvariantCulture), + TestUnsignedInt128 = newContainer.TestUnsignedInt128.ToString(), + TestNullableUnsignedInt128 = newContainer.TestNullableUnsignedInt128?.ToString(), + TestBigInteger = newContainer.TestBigInteger.ToString(CultureInfo.InvariantCulture), + TestNullableBigInteger = newContainer.TestNullableBigInteger?.ToString(CultureInfo.InvariantCulture), + TestHalf = newContainer.TestHalf.AsFloat(), + TestNullableHalf = newContainer.TestNullableHalf?.AsFloat(), + TestFloat = newContainer.TestFloat, + TestNullableFloat = newContainer.TestNullableFloat, + TestDouble = newContainer.TestDouble, + TestNullableDouble = newContainer.TestNullableDouble, + TestDecimal = (double)newContainer.TestDecimal, + TestNullableDecimal = (double?)newContainer.TestNullableDecimal, + TestComplex = newContainer.TestComplex.ToString(CultureInfo.InvariantCulture), + TestNullableComplex = newContainer.TestNullableComplex?.ToString(CultureInfo.InvariantCulture), + TestChar = newContainer.TestChar.ToString(CultureInfo.InvariantCulture), + TestNullableChar = newContainer.TestNullableChar?.ToString(CultureInfo.InvariantCulture), + TestString = newContainer.TestString, + TestNullableString = newContainer.TestNullableString, + TestRune = newContainer.TestRune.ToString(), + TestNullableRune = newContainer.TestNullableRune?.ToString(), + TestDateTimeOffset = newContainer.TestDateTimeOffset, + TestNullableDateTimeOffset = newContainer.TestNullableDateTimeOffset, + TestDateTime = newContainer.TestDateTime, + TestNullableDateTime = newContainer.TestNullableDateTime, + TestDateOnly = newContainer.TestDateOnly.ToDateTime(default, DateTimeKind.Local), + TestNullableDateOnly = newContainer.TestNullableDateOnly?.ToDateTime(default, DateTimeKind.Local), + TestTimeOnly = newContainer.TestTimeOnly.ToTimeSpan(), + TestNullableTimeOnly = newContainer.TestNullableTimeOnly?.ToTimeSpan(), + TestTimeSpan = newContainer.TestTimeSpan, + TestNullableTimeSpan = newContainer.TestNullableTimeSpan, + TestEnum = MapEnum(newContainer.TestEnum), + TestNullableEnum = MapEnum(newContainer.TestNullableEnum), + TestGuid = newContainer.TestGuid, + TestNullableGuid = newContainer.TestNullableGuid, + TestUri = newContainer.TestUri, + TestNullableUri = newContainer.TestNullableUri, + TestIPAddress = newContainer.TestIPAddress.ToString(), + TestNullableIPAddress = newContainer.TestNullableIPAddress?.ToString(), + TestIPNetwork = newContainer.TestIPNetwork.ToString(), + TestNullableIPNetwork = newContainer.TestNullableIPNetwork?.ToString(), + TestVersion = newContainer.TestVersion.ToString(), + TestNullableVersion = newContainer.TestNullableVersion?.ToString() + } + } + }; + + // Act + PrimaryTypeContainerResponseDocument response = await apiClient.PostTypeContainerAsync(requestBody); + + // Assert + response.Should().NotBeNull(); + response.Data.Attributes.Should().NotBeNull(); + response.Data.Attributes.TestBoolean.Should().Be(newContainer.TestBoolean); + response.Data.Attributes.TestNullableBoolean.Should().Be(newContainer.TestNullableBoolean); + response.Data.Attributes.TestByte.Should().Be(newContainer.TestByte); + response.Data.Attributes.TestNullableByte.Should().Be(newContainer.TestNullableByte); + response.Data.Attributes.TestSignedByte.Should().Be(newContainer.TestSignedByte); + response.Data.Attributes.TestNullableSignedByte.Should().Be(newContainer.TestNullableSignedByte); + response.Data.Attributes.TestInt16.Should().Be(newContainer.TestInt16); + response.Data.Attributes.TestNullableInt16.Should().Be(newContainer.TestNullableInt16); + response.Data.Attributes.TestUnsignedInt16.Should().Be(newContainer.TestUnsignedInt16); + response.Data.Attributes.TestNullableUnsignedInt16.Should().Be(newContainer.TestNullableUnsignedInt16); + response.Data.Attributes.TestInt32.Should().Be(newContainer.TestInt32); + response.Data.Attributes.TestNullableInt32.Should().Be(newContainer.TestNullableInt32); + response.Data.Attributes.TestUnsignedInt32.Should().Be(checked((int)newContainer.TestUnsignedInt32)); + response.Data.Attributes.TestNullableUnsignedInt32.Should().Be(checked((int?)newContainer.TestNullableUnsignedInt32)); + response.Data.Attributes.TestInt64.Should().Be(newContainer.TestInt64); + response.Data.Attributes.TestNullableInt64.Should().Be(newContainer.TestNullableInt64); + response.Data.Attributes.TestUnsignedInt64.Should().Be(checked((long)newContainer.TestUnsignedInt64)); + response.Data.Attributes.TestNullableUnsignedInt64.Should().Be(checked((long?)newContainer.TestNullableUnsignedInt64)); + response.Data.Attributes.TestInt128.Should().Be(newContainer.TestInt128.ToString(CultureInfo.InvariantCulture)); + response.Data.Attributes.TestNullableInt128.Should().Be(newContainer.TestNullableInt128?.ToString(CultureInfo.InvariantCulture)); + response.Data.Attributes.TestUnsignedInt128.Should().Be(newContainer.TestUnsignedInt128.ToString(CultureInfo.InvariantCulture)); + response.Data.Attributes.TestNullableUnsignedInt128.Should().Be(newContainer.TestNullableUnsignedInt128?.ToString(CultureInfo.InvariantCulture)); + response.Data.Attributes.TestBigInteger.Should().Be(newContainer.TestBigInteger.ToString(CultureInfo.InvariantCulture)); + response.Data.Attributes.TestNullableBigInteger.Should().Be(newContainer.TestNullableBigInteger?.ToString(CultureInfo.InvariantCulture)); + response.Data.Attributes.TestHalf.Should().Be(newContainer.TestHalf.AsFloat()); + response.Data.Attributes.TestNullableHalf.Should().Be(newContainer.TestNullableHalf?.AsFloat()); + response.Data.Attributes.TestFloat.Should().Be(newContainer.TestFloat); + response.Data.Attributes.TestNullableFloat.Should().Be(newContainer.TestNullableFloat); + response.Data.Attributes.TestDouble.Should().Be(newContainer.TestDouble); + response.Data.Attributes.TestNullableDouble.Should().Be(newContainer.TestNullableDouble); + response.Data.Attributes.TestDecimal.Should().Be((double)newContainer.TestDecimal); + response.Data.Attributes.TestNullableDecimal.Should().Be((double?)newContainer.TestNullableDecimal); + response.Data.Attributes.TestComplex.Should().Be(newContainer.TestComplex.ToString(CultureInfo.InvariantCulture)); + response.Data.Attributes.TestNullableComplex.Should().Be(newContainer.TestNullableComplex?.ToString(CultureInfo.InvariantCulture)); + response.Data.Attributes.TestChar.Should().Be(newContainer.TestChar.ToString(CultureInfo.InvariantCulture)); + response.Data.Attributes.TestNullableChar.Should().Be(newContainer.TestNullableChar?.ToString(CultureInfo.InvariantCulture)); + response.Data.Attributes.TestString.Should().Be(newContainer.TestString); + response.Data.Attributes.TestNullableString.Should().Be(newContainer.TestNullableString); + response.Data.Attributes.TestRune.Should().Be(newContainer.TestRune.ToString()); + response.Data.Attributes.TestNullableRune.Should().Be(newContainer.TestNullableRune?.ToString()); + response.Data.Attributes.TestDateTimeOffset.Should().Be(newContainer.TestDateTimeOffset); + response.Data.Attributes.TestNullableDateTimeOffset.Should().Be(newContainer.TestNullableDateTimeOffset); + response.Data.Attributes.TestDateTime.Should().Be(newContainer.TestDateTime); + response.Data.Attributes.TestNullableDateTime.Should().Be(newContainer.TestNullableDateTime); + response.Data.Attributes.TestDateOnly.Should().Be(newContainer.TestDateOnly.ToDateTime(default, DateTimeKind.Local)); + response.Data.Attributes.TestNullableDateOnly.Should().Be(newContainer.TestNullableDateOnly?.ToDateTime(default, DateTimeKind.Local)); + response.Data.Attributes.TestTimeOnly.Should().Be(newContainer.TestTimeOnly.ToTimeSpan()); + response.Data.Attributes.TestNullableTimeOnly.Should().Be(newContainer.TestNullableTimeOnly?.ToTimeSpan()); + response.Data.Attributes.TestTimeSpan.Should().Be(newContainer.TestTimeSpan); + response.Data.Attributes.TestNullableTimeSpan.Should().Be(newContainer.TestNullableTimeSpan); + response.Data.Attributes.TestEnum.Should().Be(MapEnum(newContainer.TestEnum)); + response.Data.Attributes.TestNullableEnum.Should().Be(MapEnum(newContainer.TestNullableEnum)); + response.Data.Attributes.TestGuid.Should().Be(newContainer.TestGuid); + response.Data.Attributes.TestNullableGuid.Should().Be(newContainer.TestNullableGuid); + response.Data.Attributes.TestUri.Should().Be(newContainer.TestUri); + response.Data.Attributes.TestNullableUri.Should().Be(newContainer.TestNullableUri); + response.Data.Attributes.TestIPAddress.Should().Be(newContainer.TestIPAddress.ToString()); + response.Data.Attributes.TestNullableIPAddress.Should().Be(newContainer.TestNullableIPAddress?.ToString()); + response.Data.Attributes.TestIPNetwork.Should().Be(newContainer.TestIPNetwork.ToString()); + response.Data.Attributes.TestNullableIPNetwork.Should().Be(newContainer.TestNullableIPNetwork?.ToString()); + response.Data.Attributes.TestVersion.Should().Be(newContainer.TestVersion.ToString()); + response.Data.Attributes.TestNullableVersion.Should().Be(newContainer.TestNullableVersion?.ToString()); + + long newContainerId = long.Parse(response.Data.Id.Should().NotBeNull().And.Subject); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + TypeContainer containerInDatabase = await dbContext.TypeContainers.FirstWithIdAsync(newContainerId); + + containerInDatabase.TestBoolean.Should().Be(newContainer.TestBoolean); + containerInDatabase.TestNullableBoolean.Should().Be(newContainer.TestNullableBoolean); + containerInDatabase.TestByte.Should().Be(newContainer.TestByte); + containerInDatabase.TestNullableByte.Should().Be(newContainer.TestNullableByte); + containerInDatabase.TestSignedByte.Should().Be(newContainer.TestSignedByte); + containerInDatabase.TestNullableSignedByte.Should().Be(newContainer.TestNullableSignedByte); + containerInDatabase.TestInt16.Should().Be(newContainer.TestInt16); + containerInDatabase.TestNullableInt16.Should().Be(newContainer.TestNullableInt16); + containerInDatabase.TestUnsignedInt16.Should().Be(newContainer.TestUnsignedInt16); + containerInDatabase.TestNullableUnsignedInt16.Should().Be(newContainer.TestNullableUnsignedInt16); + containerInDatabase.TestInt32.Should().Be(newContainer.TestInt32); + containerInDatabase.TestNullableInt32.Should().Be(newContainer.TestNullableInt32); + containerInDatabase.TestUnsignedInt32.Should().Be(newContainer.TestUnsignedInt32); + containerInDatabase.TestNullableUnsignedInt32.Should().Be(newContainer.TestNullableUnsignedInt32); + containerInDatabase.TestInt64.Should().Be(newContainer.TestInt64); + containerInDatabase.TestNullableInt64.Should().Be(newContainer.TestNullableInt64); + containerInDatabase.TestUnsignedInt64.Should().Be(newContainer.TestUnsignedInt64); + containerInDatabase.TestNullableUnsignedInt64.Should().Be(newContainer.TestNullableUnsignedInt64); + containerInDatabase.TestInt128.Should().Be(newContainer.TestInt128); + containerInDatabase.TestNullableInt128.Should().Be(newContainer.TestNullableInt128); + containerInDatabase.TestUnsignedInt128.Should().Be(newContainer.TestUnsignedInt128); + containerInDatabase.TestNullableUnsignedInt128.Should().Be(newContainer.TestNullableUnsignedInt128); + containerInDatabase.TestBigInteger.Should().Be(newContainer.TestBigInteger); + containerInDatabase.TestNullableBigInteger.Should().Be(newContainer.TestNullableBigInteger); + containerInDatabase.TestHalf.Should().Be(newContainer.TestHalf); + containerInDatabase.TestNullableHalf.Should().Be(newContainer.TestNullableHalf); + containerInDatabase.TestFloat.Should().Be(newContainer.TestFloat); + containerInDatabase.TestNullableFloat.Should().Be(newContainer.TestNullableFloat); + containerInDatabase.TestDouble.Should().Be(newContainer.TestDouble); + containerInDatabase.TestNullableDouble.Should().Be(newContainer.TestNullableDouble); + containerInDatabase.TestDecimal.Should().Be(newContainer.TestDecimal); + containerInDatabase.TestNullableDecimal.Should().Be(newContainer.TestNullableDecimal); + containerInDatabase.TestComplex.Should().Be(newContainer.TestComplex); + containerInDatabase.TestNullableComplex.Should().Be(newContainer.TestNullableComplex); + containerInDatabase.TestChar.Should().Be(newContainer.TestChar); + containerInDatabase.TestNullableChar.Should().Be(newContainer.TestNullableChar); + containerInDatabase.TestString.Should().Be(newContainer.TestString); + containerInDatabase.TestNullableString.Should().Be(newContainer.TestNullableString); + containerInDatabase.TestRune.Should().Be(newContainer.TestRune); + containerInDatabase.TestNullableRune.Should().Be(newContainer.TestNullableRune); + containerInDatabase.TestDateTimeOffset.Should().Be(newContainer.TestDateTimeOffset); + containerInDatabase.TestNullableDateTimeOffset.Should().Be(newContainer.TestNullableDateTimeOffset); + containerInDatabase.TestDateTime.Should().Be(newContainer.TestDateTime); + containerInDatabase.TestNullableDateTime.Should().Be(newContainer.TestNullableDateTime); + containerInDatabase.TestDateOnly.Should().Be(newContainer.TestDateOnly); + containerInDatabase.TestNullableDateOnly.Should().Be(newContainer.TestNullableDateOnly); + containerInDatabase.TestTimeOnly.Should().Be(newContainer.TestTimeOnly); + containerInDatabase.TestNullableTimeOnly.Should().Be(newContainer.TestNullableTimeOnly); + containerInDatabase.TestTimeSpan.Should().Be(newContainer.TestTimeSpan); + containerInDatabase.TestNullableTimeSpan.Should().Be(newContainer.TestNullableTimeSpan); + containerInDatabase.TestEnum.Should().Be(newContainer.TestEnum); + containerInDatabase.TestNullableEnum.Should().Be(newContainer.TestNullableEnum); + containerInDatabase.TestGuid.Should().Be(newContainer.TestGuid); + containerInDatabase.TestNullableGuid.Should().Be(newContainer.TestNullableGuid); + containerInDatabase.TestUri.Should().Be(newContainer.TestUri); + containerInDatabase.TestNullableUri.Should().Be(newContainer.TestNullableUri); + containerInDatabase.TestIPAddress.Should().Be(newContainer.TestIPAddress); + containerInDatabase.TestNullableIPAddress.Should().Be(newContainer.TestNullableIPAddress); + containerInDatabase.TestIPNetwork.Should().Be(newContainer.TestIPNetwork); + containerInDatabase.TestNullableIPNetwork.Should().Be(newContainer.TestNullableIPNetwork); + containerInDatabase.TestVersion.Should().Be(newContainer.TestVersion); + containerInDatabase.TestNullableVersion.Should().Be(newContainer.TestNullableVersion); + }); + } + + [Fact] + public async Task Can_update_resource_with_nullable_attributes_set_to_null() + { + // Arrange + TypeContainer existingContainer = _fakers.TypeContainer.GenerateOne(); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + dbContext.TypeContainers.Add(existingContainer); + await dbContext.SaveChangesAsync(); + }); + + using HttpClient httpClient = _testContext.Factory.CreateDefaultClient(_logHttpMessageHandler); + AttributeTypesClient apiClient = new(httpClient); + + var requestBody = new UpdateTypeContainerRequestDocument + { + Data = new DataInUpdateTypeContainerRequest + { + Id = existingContainer.StringId!, + Attributes = new TrackChangesFor(apiClient) + { + Initializer = + { + TestNullableBoolean = null, + TestNullableByte = null, + TestNullableSignedByte = null, + TestNullableInt16 = null, + TestNullableUnsignedInt16 = null, + TestNullableInt32 = null, + TestNullableUnsignedInt32 = null, + TestNullableInt64 = null, + TestNullableUnsignedInt64 = null, + TestNullableInt128 = null, + TestNullableUnsignedInt128 = null, + TestNullableBigInteger = null, + TestNullableHalf = null, + TestNullableFloat = null, + TestNullableDouble = null, + TestNullableDecimal = null, + TestNullableComplex = null, + TestNullableChar = null, + TestNullableString = null, + TestNullableRune = null, + TestNullableDateTimeOffset = null, + TestNullableDateTime = null, + TestNullableDateOnly = null, + TestNullableTimeOnly = null, + TestNullableTimeSpan = null, + TestNullableEnum = null, + TestNullableGuid = null, + TestNullableUri = null, + TestNullableIPAddress = null, + TestNullableIPNetwork = null, + TestNullableVersion = null + } + }.Initializer + } + }; + + // Act + PrimaryTypeContainerResponseDocument response = await apiClient.PatchTypeContainerAsync(existingContainer.StringId!, requestBody); + + // Assert + response.Should().NotBeNull(); + response.Data.Attributes.Should().NotBeNull(); + response.Data.Attributes.TestNullableBoolean.Should().BeNull(); + response.Data.Attributes.TestNullableByte.Should().BeNull(); + response.Data.Attributes.TestNullableSignedByte.Should().BeNull(); + response.Data.Attributes.TestNullableInt16.Should().BeNull(); + response.Data.Attributes.TestNullableUnsignedInt16.Should().BeNull(); + response.Data.Attributes.TestNullableInt32.Should().BeNull(); + response.Data.Attributes.TestNullableUnsignedInt32.Should().BeNull(); + response.Data.Attributes.TestNullableInt64.Should().BeNull(); + response.Data.Attributes.TestNullableUnsignedInt64.Should().BeNull(); + response.Data.Attributes.TestNullableInt128.Should().BeNull(); + response.Data.Attributes.TestNullableUnsignedInt128.Should().BeNull(); + response.Data.Attributes.TestNullableBigInteger.Should().BeNull(); + response.Data.Attributes.TestNullableHalf.Should().BeNull(); + response.Data.Attributes.TestNullableFloat.Should().BeNull(); + response.Data.Attributes.TestNullableDouble.Should().BeNull(); + response.Data.Attributes.TestNullableDecimal.Should().BeNull(); + response.Data.Attributes.TestNullableComplex.Should().BeNull(); + response.Data.Attributes.TestNullableChar.Should().BeNull(); + response.Data.Attributes.TestNullableString.Should().BeNull(); + response.Data.Attributes.TestNullableRune.Should().BeNull(); + response.Data.Attributes.TestNullableDateTimeOffset.Should().BeNull(); + response.Data.Attributes.TestNullableDateTime.Should().BeNull(); + response.Data.Attributes.TestNullableDateOnly.Should().BeNull(); + response.Data.Attributes.TestNullableTimeOnly.Should().BeNull(); + response.Data.Attributes.TestNullableTimeSpan.Should().BeNull(); + response.Data.Attributes.TestNullableEnum.Should().BeNull(); + response.Data.Attributes.TestNullableGuid.Should().BeNull(); + response.Data.Attributes.TestNullableUri.Should().BeNull(); + response.Data.Attributes.TestNullableIPAddress.Should().BeNull(); + response.Data.Attributes.TestNullableIPNetwork.Should().BeNull(); + response.Data.Attributes.TestNullableVersion.Should().BeNull(); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + TypeContainer containerInDatabase = await dbContext.TypeContainers.FirstWithIdAsync(existingContainer.Id); + + containerInDatabase.TestNullableBoolean.Should().BeNull(); + containerInDatabase.TestNullableByte.Should().BeNull(); + containerInDatabase.TestNullableSignedByte.Should().BeNull(); + containerInDatabase.TestNullableInt16.Should().BeNull(); + containerInDatabase.TestNullableUnsignedInt16.Should().BeNull(); + containerInDatabase.TestNullableInt32.Should().BeNull(); + containerInDatabase.TestNullableUnsignedInt32.Should().BeNull(); + containerInDatabase.TestNullableInt64.Should().BeNull(); + containerInDatabase.TestNullableUnsignedInt64.Should().BeNull(); + containerInDatabase.TestNullableInt128.Should().BeNull(); + containerInDatabase.TestNullableUnsignedInt128.Should().BeNull(); + containerInDatabase.TestNullableBigInteger.Should().BeNull(); + containerInDatabase.TestNullableHalf.Should().BeNull(); + containerInDatabase.TestNullableFloat.Should().BeNull(); + containerInDatabase.TestNullableDouble.Should().BeNull(); + containerInDatabase.TestNullableDecimal.Should().BeNull(); + containerInDatabase.TestNullableComplex.Should().BeNull(); + containerInDatabase.TestNullableChar.Should().BeNull(); + containerInDatabase.TestNullableString.Should().BeNull(); + containerInDatabase.TestNullableRune.Should().BeNull(); + containerInDatabase.TestNullableDateTimeOffset.Should().BeNull(); + containerInDatabase.TestNullableDateTime.Should().BeNull(); + containerInDatabase.TestNullableDateOnly.Should().BeNull(); + containerInDatabase.TestNullableTimeOnly.Should().BeNull(); + containerInDatabase.TestNullableTimeSpan.Should().BeNull(); + containerInDatabase.TestNullableEnum.Should().BeNull(); + containerInDatabase.TestNullableGuid.Should().BeNull(); + containerInDatabase.TestNullableUri.Should().BeNull(); + containerInDatabase.TestNullableIPAddress.Should().BeNull(); + containerInDatabase.TestNullableIPNetwork.Should().BeNull(); + containerInDatabase.TestNullableVersion.Should().BeNull(); + }); + } + + [Theory] + [InlineData(nameof(TypeContainer.TestBoolean), false)] + [InlineData(nameof(TypeContainer.TestByte), false)] + [InlineData(nameof(TypeContainer.TestSignedByte), false)] + [InlineData(nameof(TypeContainer.TestInt16), false)] + [InlineData(nameof(TypeContainer.TestUnsignedInt16), false)] + [InlineData(nameof(TypeContainer.TestInt32), false)] + [InlineData(nameof(TypeContainer.TestUnsignedInt32), false)] + [InlineData(nameof(TypeContainer.TestInt64), false)] + [InlineData(nameof(TypeContainer.TestUnsignedInt64), false)] + [InlineData(nameof(TypeContainer.TestInt128), false)] + [InlineData(nameof(TypeContainer.TestUnsignedInt128), false)] + [InlineData(nameof(TypeContainer.TestBigInteger), false)] + [InlineData(nameof(TypeContainer.TestHalf), false)] + [InlineData(nameof(TypeContainer.TestFloat), false)] + [InlineData(nameof(TypeContainer.TestDouble), false)] + [InlineData(nameof(TypeContainer.TestDecimal), false)] + [InlineData(nameof(TypeContainer.TestComplex), false)] + [InlineData(nameof(TypeContainer.TestChar), false)] + [InlineData(nameof(TypeContainer.TestString), true)] + [InlineData(nameof(TypeContainer.TestRune), false)] + [InlineData(nameof(TypeContainer.TestDateTimeOffset), false)] + [InlineData(nameof(TypeContainer.TestDateTime), false)] + [InlineData(nameof(TypeContainer.TestDateOnly), false)] + [InlineData(nameof(TypeContainer.TestTimeOnly), false)] + [InlineData(nameof(TypeContainer.TestTimeSpan), false)] + [InlineData(nameof(TypeContainer.TestEnum), false)] + [InlineData(nameof(TypeContainer.TestGuid), false)] + [InlineData(nameof(TypeContainer.TestUri), true)] + [InlineData(nameof(TypeContainer.TestIPAddress), true)] + [InlineData(nameof(TypeContainer.TestIPNetwork), false)] + [InlineData(nameof(TypeContainer.TestVersion), true)] + public async Task Cannot_update_resource_with_attribute_set_to_null(string propertyName, bool failAtModelValidation) + { + // Arrange + TypeContainer existingContainer = _fakers.TypeContainer.GenerateOne(); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + dbContext.TypeContainers.Add(existingContainer); + await dbContext.SaveChangesAsync(); + }); + + using HttpClient httpClient = _testContext.Factory.CreateDefaultClient(_logHttpMessageHandler); + AttributeTypesClient apiClient = new(httpClient); + + var requestBody = new UpdateTypeContainerRequestDocument + { + Data = new DataInUpdateTypeContainerRequest + { + Id = existingContainer.StringId!, + Attributes = new AttributesInUpdateTypeContainerRequest() + } + }; + + SetAttributeValueInUpdateRequestToNull(requestBody.Data.Attributes, propertyName, apiClient); + + // Act + Func action = async () => await apiClient.PatchTypeContainerAsync(existingContainer.StringId!, requestBody); + + // Assert + ApiException exception = (await action.Should().ThrowExactlyAsync>()).Which; + exception.StatusCode.Should().Be((int)HttpStatusCode.UnprocessableEntity); + exception.Message.Should().Be("HTTP 422: Validation of the request body failed."); + exception.Result.Errors.Should().HaveCount(1); + + ErrorObject error = exception.Result.Errors.ElementAt(0); + error.Status.Should().Be("422"); + + if (failAtModelValidation) + { + error.Title.Should().Be("Input validation failed."); + error.Detail.Should().Be($"The {propertyName} field is required."); + } + else + { + error.Title.Should().Be("Failed to deserialize request body: Incompatible attribute value found."); + error.Detail.Should().Be(GetExpectedConverterErrorMessage(propertyName, null)); + } + + error.Source.Should().NotBeNull(); + error.Source.Pointer.Should().Be($"/data/attributes/{propertyName.Camelize()}"); + } + + [Theory] + [InlineData(nameof(TypeContainer.TestInt128), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableInt128), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestUnsignedInt128), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt128), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestBigInteger), "The value could not be parsed.")] + [InlineData(nameof(TypeContainer.TestNullableBigInteger), "The value could not be parsed.")] + [InlineData(nameof(TypeContainer.TestComplex), "Arithmetic operation resulted in an overflow.")] + [InlineData(nameof(TypeContainer.TestNullableComplex), "Arithmetic operation resulted in an overflow.")] + [InlineData(nameof(TypeContainer.TestIPAddress), "An invalid IP address was specified.")] + [InlineData(nameof(TypeContainer.TestNullableIPAddress), "An invalid IP address was specified.")] + [InlineData(nameof(TypeContainer.TestIPNetwork), "An invalid IP network was specified.")] + [InlineData(nameof(TypeContainer.TestNullableIPNetwork), "An invalid IP network was specified.")] + [InlineData(nameof(TypeContainer.TestVersion), "The JSON value is not in a supported Version format.")] + [InlineData(nameof(TypeContainer.TestNullableVersion), "The JSON value is not in a supported Version format.")] + public async Task Cannot_update_resource_with_attribute_set_to_invalid_value(string propertyName, string innerParseError) + { + // Arrange + TypeContainer existingContainer = _fakers.TypeContainer.GenerateOne(); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + dbContext.TypeContainers.Add(existingContainer); + await dbContext.SaveChangesAsync(); + }); + + using HttpClient httpClient = _testContext.Factory.CreateDefaultClient(_logHttpMessageHandler); + AttributeTypesClient apiClient = new(httpClient); + + var requestBody = new UpdateTypeContainerRequestDocument + { + Data = new DataInUpdateTypeContainerRequest + { + Id = existingContainer.StringId!, + Attributes = new AttributesInUpdateTypeContainerRequest() + } + }; + + SetAttributeValueInUpdateRequestToInvalid(requestBody.Data.Attributes, propertyName, apiClient); + + // Act + Func action = async () => await apiClient.PatchTypeContainerAsync(existingContainer.StringId!, requestBody); + + // Assert + ApiException exception = (await action.Should().ThrowExactlyAsync>()).Which; + exception.StatusCode.Should().Be((int)HttpStatusCode.UnprocessableEntity); + exception.Message.Should().Be("HTTP 422: Validation of the request body failed."); + exception.Result.Errors.Should().HaveCount(1); + + ErrorObject error = exception.Result.Errors.ElementAt(0); + error.Status.Should().Be("422"); + error.Title.Should().Be("Failed to deserialize request body: Incompatible attribute value found."); + error.Detail.Should().Be(GetExpectedConverterErrorMessage(propertyName, "invalid")); + error.Source.Should().NotBeNull(); + error.Source.Pointer.Should().Be($"/data/attributes/{propertyName.Camelize()}"); + error.Meta.Should().ContainKey("stackTrace").WhoseValue.Should().BeOfType().Which.ToString().Should().Contain(innerParseError); + } + + [Theory] + [InlineData(nameof(TypeContainer.TestBoolean))] + [InlineData(nameof(TypeContainer.TestNullableBoolean))] + [InlineData(nameof(TypeContainer.TestByte))] + [InlineData(nameof(TypeContainer.TestNullableByte))] + [InlineData(nameof(TypeContainer.TestSignedByte))] + [InlineData(nameof(TypeContainer.TestNullableSignedByte))] + [InlineData(nameof(TypeContainer.TestInt16))] + [InlineData(nameof(TypeContainer.TestNullableInt16))] + [InlineData(nameof(TypeContainer.TestUnsignedInt16))] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt16))] + [InlineData(nameof(TypeContainer.TestInt32))] + [InlineData(nameof(TypeContainer.TestNullableInt32))] + [InlineData(nameof(TypeContainer.TestUnsignedInt32))] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt32))] + [InlineData(nameof(TypeContainer.TestInt64))] + [InlineData(nameof(TypeContainer.TestNullableInt64))] + [InlineData(nameof(TypeContainer.TestUnsignedInt64))] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt64))] + [InlineData(nameof(TypeContainer.TestInt128))] + [InlineData(nameof(TypeContainer.TestNullableInt128))] + [InlineData(nameof(TypeContainer.TestUnsignedInt128))] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt128))] + [InlineData(nameof(TypeContainer.TestBigInteger))] + [InlineData(nameof(TypeContainer.TestNullableBigInteger))] + [InlineData(nameof(TypeContainer.TestHalf))] + [InlineData(nameof(TypeContainer.TestNullableHalf))] + [InlineData(nameof(TypeContainer.TestFloat))] + [InlineData(nameof(TypeContainer.TestNullableFloat))] + [InlineData(nameof(TypeContainer.TestDouble))] + [InlineData(nameof(TypeContainer.TestNullableDouble))] + [InlineData(nameof(TypeContainer.TestDecimal))] + [InlineData(nameof(TypeContainer.TestNullableDecimal))] + [InlineData(nameof(TypeContainer.TestComplex))] + [InlineData(nameof(TypeContainer.TestNullableComplex))] + [InlineData(nameof(TypeContainer.TestChar))] + [InlineData(nameof(TypeContainer.TestNullableChar))] + [InlineData(nameof(TypeContainer.TestString))] + [InlineData(nameof(TypeContainer.TestNullableString))] + [InlineData(nameof(TypeContainer.TestRune))] + [InlineData(nameof(TypeContainer.TestNullableRune))] + [InlineData(nameof(TypeContainer.TestDateTimeOffset))] + [InlineData(nameof(TypeContainer.TestNullableDateTimeOffset))] + [InlineData(nameof(TypeContainer.TestDateTime))] + [InlineData(nameof(TypeContainer.TestNullableDateTime))] + [InlineData(nameof(TypeContainer.TestDateOnly))] + [InlineData(nameof(TypeContainer.TestNullableDateOnly))] + [InlineData(nameof(TypeContainer.TestTimeOnly))] + [InlineData(nameof(TypeContainer.TestNullableTimeOnly))] + [InlineData(nameof(TypeContainer.TestTimeSpan))] + [InlineData(nameof(TypeContainer.TestNullableTimeSpan))] + [InlineData(nameof(TypeContainer.TestEnum))] + [InlineData(nameof(TypeContainer.TestNullableEnum))] + [InlineData(nameof(TypeContainer.TestGuid))] + [InlineData(nameof(TypeContainer.TestNullableGuid))] + [InlineData(nameof(TypeContainer.TestUri))] + [InlineData(nameof(TypeContainer.TestNullableUri))] + [InlineData(nameof(TypeContainer.TestIPAddress))] + [InlineData(nameof(TypeContainer.TestNullableIPAddress))] + [InlineData(nameof(TypeContainer.TestIPNetwork))] + [InlineData(nameof(TypeContainer.TestNullableIPNetwork))] + [InlineData(nameof(TypeContainer.TestVersion))] + [InlineData(nameof(TypeContainer.TestNullableVersion))] + public async Task Can_filter_with_valid_value(string propertyName) + { + // Arrange + TypeContainer existingContainer = _fakers.TypeContainer.GenerateOne(); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + await dbContext.ClearTableAsync(); + dbContext.TypeContainers.Add(existingContainer); + await dbContext.SaveChangesAsync(); + }); + + using HttpClient httpClient = _testContext.Factory.CreateDefaultClient(_logHttpMessageHandler); + AttributeTypesClient apiClient = new(httpClient); + + string filterValue = GetFilterValue(existingContainer, propertyName); + + var queryString = new Dictionary + { + ["filter"] = $"equals({propertyName.Camelize()},'{filterValue}')" + }; + + // Act + TypeContainerCollectionResponseDocument response = await apiClient.GetTypeContainerCollectionAsync(queryString); + + // Assert + response.Data.Should().HaveCount(1); + response.Data.ElementAt(0).Id.Should().Be(existingContainer.StringId); + } + + [Theory] + [InlineData(nameof(TypeContainer.TestNullableBoolean))] + [InlineData(nameof(TypeContainer.TestNullableByte))] + [InlineData(nameof(TypeContainer.TestNullableSignedByte))] + [InlineData(nameof(TypeContainer.TestNullableInt16))] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt16))] + [InlineData(nameof(TypeContainer.TestNullableInt32))] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt32))] + [InlineData(nameof(TypeContainer.TestNullableInt64))] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt64))] + [InlineData(nameof(TypeContainer.TestNullableInt128))] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt128))] + [InlineData(nameof(TypeContainer.TestNullableBigInteger))] + [InlineData(nameof(TypeContainer.TestNullableHalf))] + [InlineData(nameof(TypeContainer.TestNullableFloat))] + [InlineData(nameof(TypeContainer.TestNullableDouble))] + [InlineData(nameof(TypeContainer.TestNullableDecimal))] + [InlineData(nameof(TypeContainer.TestNullableComplex))] + [InlineData(nameof(TypeContainer.TestNullableChar))] + [InlineData(nameof(TypeContainer.TestNullableString))] + [InlineData(nameof(TypeContainer.TestNullableRune))] + [InlineData(nameof(TypeContainer.TestNullableDateTimeOffset))] + [InlineData(nameof(TypeContainer.TestNullableDateTime))] + [InlineData(nameof(TypeContainer.TestNullableDateOnly))] + [InlineData(nameof(TypeContainer.TestNullableTimeOnly))] + [InlineData(nameof(TypeContainer.TestNullableTimeSpan))] + [InlineData(nameof(TypeContainer.TestNullableEnum))] + [InlineData(nameof(TypeContainer.TestNullableGuid))] + [InlineData(nameof(TypeContainer.TestNullableUri))] + [InlineData(nameof(TypeContainer.TestNullableIPAddress))] + [InlineData(nameof(TypeContainer.TestNullableIPNetwork))] + [InlineData(nameof(TypeContainer.TestNullableVersion))] + public async Task Can_filter_with_null_value(string propertyName) + { + // Arrange + TypeContainer existingContainer = _fakers.TypeContainer.GenerateOne(); + SetResourcePropertyValueToNull(existingContainer, propertyName); + + await _testContext.RunOnDatabaseAsync(async dbContext => + { + await dbContext.ClearTableAsync(); + dbContext.TypeContainers.Add(existingContainer); + await dbContext.SaveChangesAsync(); + }); + + using HttpClient httpClient = _testContext.Factory.CreateDefaultClient(_logHttpMessageHandler); + AttributeTypesClient apiClient = new(httpClient); + + var queryString = new Dictionary + { + ["filter"] = $"equals({propertyName.Camelize()},null)" + }; + + // Act + TypeContainerCollectionResponseDocument response = await apiClient.GetTypeContainerCollectionAsync(queryString); + + // Assert + response.Data.Should().HaveCount(1); + response.Data.ElementAt(0).Id.Should().Be(existingContainer.StringId); + } + + [Theory] + [InlineData(nameof(TypeContainer.TestBoolean))] + [InlineData(nameof(TypeContainer.TestByte))] + [InlineData(nameof(TypeContainer.TestSignedByte))] + [InlineData(nameof(TypeContainer.TestInt16))] + [InlineData(nameof(TypeContainer.TestUnsignedInt16))] + [InlineData(nameof(TypeContainer.TestInt32))] + [InlineData(nameof(TypeContainer.TestUnsignedInt32))] + [InlineData(nameof(TypeContainer.TestInt64))] + [InlineData(nameof(TypeContainer.TestUnsignedInt64))] + [InlineData(nameof(TypeContainer.TestInt128))] + [InlineData(nameof(TypeContainer.TestUnsignedInt128))] + [InlineData(nameof(TypeContainer.TestBigInteger))] + [InlineData(nameof(TypeContainer.TestHalf))] + [InlineData(nameof(TypeContainer.TestFloat))] + [InlineData(nameof(TypeContainer.TestDouble))] + [InlineData(nameof(TypeContainer.TestDecimal))] + [InlineData(nameof(TypeContainer.TestComplex))] + [InlineData(nameof(TypeContainer.TestChar))] + [InlineData(nameof(TypeContainer.TestRune))] + [InlineData(nameof(TypeContainer.TestDateTimeOffset))] + [InlineData(nameof(TypeContainer.TestDateTime))] + [InlineData(nameof(TypeContainer.TestDateOnly))] + [InlineData(nameof(TypeContainer.TestTimeOnly))] + [InlineData(nameof(TypeContainer.TestTimeSpan))] + [InlineData(nameof(TypeContainer.TestEnum))] + [InlineData(nameof(TypeContainer.TestGuid))] + [InlineData(nameof(TypeContainer.TestIPNetwork))] + public async Task Cannot_filter_with_null_value(string propertyName) + { + // Arrange + using HttpClient httpClient = _testContext.Factory.CreateDefaultClient(_logHttpMessageHandler); + AttributeTypesClient apiClient = new(httpClient); + + var queryString = new Dictionary + { + ["filter"] = $"equals({propertyName.Camelize()},null)" + }; + + // Act + Func action = async () => await apiClient.GetTypeContainerCollectionAsync(queryString); + + // Assert + ApiException exception = (await action.Should().ThrowExactlyAsync>()).Which; + exception.StatusCode.Should().Be((int)HttpStatusCode.BadRequest); + exception.Message.Should().Be("HTTP 400: The query string is invalid."); + exception.Result.Errors.Should().HaveCount(1); + + ErrorObject error = exception.Result.Errors.ElementAt(0); + error.Status.Should().Be("400"); + error.Title.Should().Be("The specified filter is invalid."); + error.Detail.Should().StartWith("Function, field name or value between quotes expected. Failed at position"); + error.Source.Should().NotBeNull(); + error.Source.Parameter.Should().Be("filter"); + } + + [Theory] + [InlineData(nameof(TypeContainer.TestBoolean), "String 'invalid' was not recognized as a valid Boolean.")] + [InlineData(nameof(TypeContainer.TestNullableBoolean), "String 'invalid' was not recognized as a valid Boolean.")] + [InlineData(nameof(TypeContainer.TestByte), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableByte), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestSignedByte), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableSignedByte), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestInt16), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableInt16), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestUnsignedInt16), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt16), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestInt32), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableInt32), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestUnsignedInt32), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt32), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestInt64), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableInt64), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestUnsignedInt64), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt64), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestInt128), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableInt128), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestUnsignedInt128), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableUnsignedInt128), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestBigInteger), "The value could not be parsed.")] + [InlineData(nameof(TypeContainer.TestNullableBigInteger), "The value could not be parsed.")] + [InlineData(nameof(TypeContainer.TestHalf), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableHalf), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestFloat), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableFloat), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestDouble), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableDouble), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestDecimal), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestNullableDecimal), "The input string 'invalid' was not in a correct format.")] + [InlineData(nameof(TypeContainer.TestComplex), "Arithmetic operation resulted in an overflow.")] + [InlineData(nameof(TypeContainer.TestNullableComplex), "Arithmetic operation resulted in an overflow.")] + [InlineData(nameof(TypeContainer.TestChar), "String must be exactly one character long.")] + [InlineData(nameof(TypeContainer.TestNullableChar), "String must be exactly one character long.")] + [InlineData(nameof(TypeContainer.TestDateTimeOffset), "The string 'invalid' was not recognized as a valid DateTime.")] + [InlineData(nameof(TypeContainer.TestNullableDateTimeOffset), "The string 'invalid' was not recognized as a valid DateTime.")] + [InlineData(nameof(TypeContainer.TestDateTime), "The string 'invalid' was not recognized as a valid DateTime.")] + [InlineData(nameof(TypeContainer.TestNullableDateTime), "The string 'invalid' was not recognized as a valid DateTime.")] + [InlineData(nameof(TypeContainer.TestDateOnly), "String 'invalid' was not recognized as a valid DateOnly.")] + [InlineData(nameof(TypeContainer.TestNullableDateOnly), "String 'invalid' was not recognized as a valid DateOnly.")] + [InlineData(nameof(TypeContainer.TestTimeOnly), "String 'invalid' was not recognized as a valid TimeOnly.")] + [InlineData(nameof(TypeContainer.TestNullableTimeOnly), "String 'invalid' was not recognized as a valid TimeOnly.")] + [InlineData(nameof(TypeContainer.TestTimeSpan), "String 'invalid' was not recognized as a valid TimeSpan.")] + [InlineData(nameof(TypeContainer.TestNullableTimeSpan), "String 'invalid' was not recognized as a valid TimeSpan.")] + [InlineData(nameof(TypeContainer.TestEnum), "Requested value 'invalid' was not found.")] + [InlineData(nameof(TypeContainer.TestNullableEnum), "Requested value 'invalid' was not found.")] + [InlineData(nameof(TypeContainer.TestGuid), "Unrecognized Guid format.")] + [InlineData(nameof(TypeContainer.TestNullableGuid), "Unrecognized Guid format.")] + [InlineData(nameof(TypeContainer.TestUri), "Invalid URI: The format of the URI could not be determined.")] + [InlineData(nameof(TypeContainer.TestNullableUri), "Invalid URI: The format of the URI could not be determined.")] + [InlineData(nameof(TypeContainer.TestIPAddress), "An invalid IP address was specified.")] + [InlineData(nameof(TypeContainer.TestNullableIPAddress), "An invalid IP address was specified.")] + [InlineData(nameof(TypeContainer.TestIPNetwork), "An invalid IP network was specified.")] + [InlineData(nameof(TypeContainer.TestNullableIPNetwork), "An invalid IP network was specified.")] + [InlineData(nameof(TypeContainer.TestVersion), "Version string portion was too short or too long.")] + [InlineData(nameof(TypeContainer.TestNullableVersion), "Version string portion was too short or too long.")] + public async Task Cannot_filter_with_invalid_value(string propertyName, string innerParseError) + { + // Arrange + using HttpClient httpClient = _testContext.Factory.CreateDefaultClient(_logHttpMessageHandler); + AttributeTypesClient apiClient = new(httpClient); + + var queryString = new Dictionary + { + ["filter"] = $"equals({propertyName.Camelize()},'invalid')" + }; + + // Act + Func action = async () => await apiClient.GetTypeContainerCollectionAsync(queryString); + + // Assert + ApiException exception = (await action.Should().ThrowExactlyAsync>()).Which; + exception.StatusCode.Should().Be((int)HttpStatusCode.BadRequest); + exception.Message.Should().Be("HTTP 400: The query string is invalid."); + exception.Result.Errors.Should().HaveCount(1); + + ErrorObject error = exception.Result.Errors.ElementAt(0); + error.Status.Should().Be("400"); + error.Title.Should().Be("The specified filter is invalid."); + error.Detail.Should().StartWith($"{GetExpectedQueryStringErrorMessage(propertyName, "invalid")} Failed at position"); + error.Source.Should().NotBeNull(); + error.Source.Parameter.Should().Be("filter"); + error.Meta.Should().ContainKey("stackTrace").WhoseValue.Should().BeOfType().Which.ToString().Should().Contain(innerParseError); + } + + private static void SetAttributeValueInUpdateRequestToNull(AttributesInUpdateTypeContainerRequest attributes, string propertyName, JsonApiClient apiClient) + { + MethodInfo? propertySetter = typeof(AttributesInUpdateTypeContainerRequest).GetProperty(propertyName)?.SetMethod; + + if (propertySetter == null) + { + throw new InvalidOperationException($"Unknown property '{propertyName}'."); + } + + propertySetter.Invoke(attributes, [null]); + apiClient.MarkAsTracked(attributes, propertyName); + } + + private static void SetAttributeValueInUpdateRequestToInvalid(AttributesInUpdateTypeContainerRequest attributes, string propertyName, + JsonApiClient apiClient) + { + MethodInfo? propertySetter = typeof(AttributesInUpdateTypeContainerRequest).GetProperty(propertyName)?.SetMethod; + + if (propertySetter == null) + { + throw new InvalidOperationException($"Unknown property '{propertyName}'."); + } + + propertySetter.Invoke(attributes, ["invalid"]); + apiClient.MarkAsTracked(attributes, propertyName); + } + + private static void SetResourcePropertyValueToNull(TypeContainer container, string propertyName) + { + PropertyInfo? property = typeof(TypeContainer).GetProperty(propertyName); + + if (property?.SetMethod == null) + { + throw new InvalidOperationException($"Unknown property '{propertyName}'."); + } + + object? typedValue = RuntimeTypeConverter.GetDefaultValue(property.PropertyType); + property.SetMethod.Invoke(container, [typedValue]); + } + + private static string GetFilterValue(TypeContainer container, string propertyName) + { + PropertyInfo? property = typeof(TypeContainer).GetProperty(propertyName); + + if (property?.GetMethod == null) + { + throw new InvalidOperationException($"Unknown property '{propertyName}'."); + } + + object? typedValue = property.GetMethod.Invoke(container, []); + + if (typedValue == null) + { + throw new InvalidOperationException($"Property '{propertyName}' is null."); + } + + Func? converter = TypeConverterRegistry.Instance.FindToStringConverter(property.PropertyType); + return converter != null ? converter(typedValue) : (string)RuntimeTypeConverter.ConvertType(typedValue, typeof(string))!; + } + + private static string GetExpectedConverterErrorMessage(string propertyName, string? actualValue) + { + PropertyInfo? property = typeof(TypeContainer).GetProperty(propertyName); + + if (property == null) + { + throw new InvalidOperationException($"Unknown property '{propertyName}'."); + } + + string propertyType = RuntimeTypeConverter.GetFriendlyTypeName(property.PropertyType); + string jsonType = actualValue == null ? "Null" : "String"; + return $"Failed to convert attribute '{propertyName.Camelize()}' with value '{actualValue}' of type '{jsonType}' to type '{propertyType}'."; + } + + private static string GetExpectedQueryStringErrorMessage(string propertyName, string actualValue) + { + PropertyInfo? property = typeof(TypeContainer).GetProperty(propertyName); + + if (property == null) + { + throw new InvalidOperationException($"Unknown property '{propertyName}'."); + } + + string propertyType = RuntimeTypeConverter.GetFriendlyTypeName(property.PropertyType); + return $"Failed to convert '{actualValue}' of type 'String' to type '{propertyType}'."; + } + + [return: NotNullIfNotNull(nameof(fromEnum))] + private static TToEnum? MapEnum(TFromEnum? fromEnum) + where TFromEnum : struct, Enum + where TToEnum : struct, Enum + { + if (fromEnum == null) + { + return default(TToEnum); + } + + string stringValue = fromEnum.Value.ToString("G"); + return Enum.Parse(stringValue, false); + } + + public void Dispose() + { + _logHttpMessageHandler.Dispose(); + } +} diff --git a/test/OpenApiNSwagEndToEndTests/ModelStateValidation/UtcDateTimeJsonConverter.cs b/test/OpenApiNSwagEndToEndTests/ModelStateValidation/UtcDateTimeJsonConverter.cs deleted file mode 100644 index c0c1d04ffb..0000000000 --- a/test/OpenApiNSwagEndToEndTests/ModelStateValidation/UtcDateTimeJsonConverter.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace OpenApiNSwagEndToEndTests.ModelStateValidation; - -internal sealed class UtcDateTimeJsonConverter : JsonConverter -{ - public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - DateTimeOffset dateTimeOffset = DateTimeOffset.Parse(reader.GetString()!); - return dateTimeOffset.UtcDateTime; - } - - public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) - { - writer.WriteStringValue(value.ToUniversalTime().ToString("O")); - } -} diff --git a/test/OpenApiNSwagEndToEndTests/OpenApiNSwagEndToEndTests.csproj b/test/OpenApiNSwagEndToEndTests/OpenApiNSwagEndToEndTests.csproj index debd635876..0c716f4be5 100644 --- a/test/OpenApiNSwagEndToEndTests/OpenApiNSwagEndToEndTests.csproj +++ b/test/OpenApiNSwagEndToEndTests/OpenApiNSwagEndToEndTests.csproj @@ -28,14 +28,20 @@ - - ClientIdGenerationModes + + AtomicOperations $(MSBuildProjectName).%(Name).GeneratedCode %(Name)Client %(ClassName).cs - - ModelStateValidation + + AttributeTypes + $(MSBuildProjectName).%(Name).GeneratedCode + %(Name)Client + %(ClassName).cs + + + ClientIdGenerationModes $(MSBuildProjectName).%(Name).GeneratedCode %(Name)Client %(ClassName).cs @@ -53,32 +59,32 @@ %(Name)Client %(ClassName).cs - - QueryStrings + + Links $(MSBuildProjectName).%(Name).GeneratedCode %(Name)Client %(ClassName).cs - - RestrictedControllers + + MixedControllers $(MSBuildProjectName).%(Name).GeneratedCode %(Name)Client %(ClassName).cs - - Links + + ModelStateValidation $(MSBuildProjectName).%(Name).GeneratedCode %(Name)Client %(ClassName).cs - - MixedControllers + + QueryStrings $(MSBuildProjectName).%(Name).GeneratedCode %(Name)Client %(ClassName).cs - - AtomicOperations + + NoOperationsInheritance $(MSBuildProjectName).%(Name).GeneratedCode %(Name)Client %(ClassName).cs @@ -89,20 +95,20 @@ %(Name)Client %(ClassName).cs - - SubsetOfVariousInheritance + + SubsetOfOperationsInheritance $(MSBuildProjectName).%(Name).GeneratedCode %(Name)Client %(ClassName).cs - - SubsetOfOperationsInheritance + + SubsetOfVariousInheritance $(MSBuildProjectName).%(Name).GeneratedCode %(Name)Client %(ClassName).cs - - NoOperationsInheritance + + RestrictedControllers $(MSBuildProjectName).%(Name).GeneratedCode %(Name)Client %(ClassName).cs diff --git a/test/OpenApiTests/AttributeTypes/AttributeTypeTests.cs b/test/OpenApiTests/AttributeTypes/AttributeTypeTests.cs new file mode 100644 index 0000000000..68a232562d --- /dev/null +++ b/test/OpenApiTests/AttributeTypes/AttributeTypeTests.cs @@ -0,0 +1,324 @@ +using System.Text.Json; +using TestBuildingBlocks; +using Xunit; +using Xunit.Abstractions; + +namespace OpenApiTests.AttributeTypes; + +public sealed class AttributeTypeTests : IClassFixture> +{ + public static readonly TheoryData SchemaNames = + [ + "attributesInCreateTypeContainerRequest", + "attributesInUpdateTypeContainerRequest", + "attributesInTypeContainerResponse" + ]; + + private readonly OpenApiTestContext _testContext; + + public AttributeTypeTests(OpenApiTestContext testContext, ITestOutputHelper testOutputHelper) + { + _testContext = testContext; + + testContext.UseController(); + + testContext.SetTestOutputHelper(testOutputHelper); + testContext.SwaggerDocumentOutputDirectory = $"{GetType().Namespace!.Replace('.', '/')}/GeneratedSwagger"; + } + + [Theory] + [MemberData(nameof(SchemaNames))] + public async Task Types_produce_expected_schemas(string modelName) + { + // Act + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); + + // Assert + document.Should().ContainPath($"components.schemas.{modelName}.allOf[1].properties").Should().BeJson(""" + { + "testBoolean": { + "type": "boolean" + }, + "testNullableBoolean": { + "type": "boolean", + "nullable": true + }, + "testByte": { + "type": "integer", + "format": "int32" + }, + "testNullableByte": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "testSignedByte": { + "type": "integer", + "format": "int32" + }, + "testNullableSignedByte": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "testInt16": { + "type": "integer", + "format": "int32" + }, + "testNullableInt16": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "testUnsignedInt16": { + "type": "integer", + "format": "int32" + }, + "testNullableUnsignedInt16": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "testInt32": { + "type": "integer", + "format": "int32" + }, + "testNullableInt32": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "testUnsignedInt32": { + "type": "integer", + "format": "int32" + }, + "testNullableUnsignedInt32": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "testInt64": { + "type": "integer", + "format": "int64" + }, + "testNullableInt64": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "testUnsignedInt64": { + "type": "integer", + "format": "int64" + }, + "testNullableUnsignedInt64": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "testInt128": { + "type": "string" + }, + "testNullableInt128": { + "type": "string", + "nullable": true + }, + "testUnsignedInt128": { + "type": "string" + }, + "testNullableUnsignedInt128": { + "type": "string", + "nullable": true + }, + "testBigInteger": { + "type": "string" + }, + "testNullableBigInteger": { + "type": "string", + "nullable": true + }, + "testHalf": { + "type": "number", + "format": "float" + }, + "testNullableHalf": { + "type": "number", + "format": "float", + "nullable": true + }, + "testFloat": { + "type": "number", + "format": "float" + }, + "testNullableFloat": { + "type": "number", + "format": "float", + "nullable": true + }, + "testDouble": { + "type": "number", + "format": "double" + }, + "testNullableDouble": { + "type": "number", + "format": "double", + "nullable": true + }, + "testDecimal": { + "type": "number", + "format": "double" + }, + "testNullableDecimal": { + "type": "number", + "format": "double", + "nullable": true + }, + "testComplex": { + "type": "string" + }, + "testNullableComplex": { + "type": "string", + "nullable": true + }, + "testChar": { + "type": "string" + }, + "testNullableChar": { + "type": "string", + "nullable": true + }, + "testString": { + "type": "string" + }, + "testNullableString": { + "type": "string", + "nullable": true + }, + "testRune": { + "maxLength": 4, + "type": "string" + }, + "testNullableRune": { + "maxLength": 4, + "type": "string", + "nullable": true + }, + "testDateTimeOffset": { + "type": "string", + "format": "date-time" + }, + "testNullableDateTimeOffset": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "testDateTime": { + "type": "string", + "format": "date-time" + }, + "testNullableDateTime": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "testDateOnly": { + "type": "string", + "format": "date" + }, + "testNullableDateOnly": { + "type": "string", + "format": "date", + "nullable": true + }, + "testTimeOnly": { + "type": "string", + "format": "time" + }, + "testNullableTimeOnly": { + "type": "string", + "format": "time", + "nullable": true + }, + "testTimeSpan": { + "type": "string", + "format": "duration" + }, + "testNullableTimeSpan": { + "type": "string", + "format": "duration", + "nullable": true + }, + "testEnum": { + "allOf": [ + { + "$ref": "#/components/schemas/dayOfWeek" + } + ] + }, + "testNullableEnum": { + "allOf": [ + { + "$ref": "#/components/schemas/dayOfWeek" + } + ], + "nullable": true + }, + "testGuid": { + "type": "string", + "format": "uuid" + }, + "testNullableGuid": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "testUri": { + "type": "string", + "format": "uri" + }, + "testNullableUri": { + "type": "string", + "format": "uri", + "nullable": true + }, + "testIPAddress": { + "type": "string", + "format": "ipv4" + }, + "testNullableIPAddress": { + "type": "string", + "format": "ipv4", + "nullable": true + }, + "testIPNetwork": { + "type": "string" + }, + "testNullableIPNetwork": { + "type": "string", + "nullable": true + }, + "testVersion": { + "type": "string" + }, + "testNullableVersion": { + "type": "string", + "nullable": true + } + } + """); + + document.Should().ContainPath("components.schemas.dayOfWeek").Should().BeJson(""" + { + "enum": [ + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday" + ], + "type": "string" + } + """); + } +} diff --git a/test/OpenApiTests/AttributeTypes/AttributeTypesDbContext.cs b/test/OpenApiTests/AttributeTypes/AttributeTypesDbContext.cs new file mode 100644 index 0000000000..5d28701a44 --- /dev/null +++ b/test/OpenApiTests/AttributeTypes/AttributeTypesDbContext.cs @@ -0,0 +1,63 @@ +using System.Net; +using System.Numerics; +using System.Text; +using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using TestBuildingBlocks; + +// @formatter:wrap_chained_method_calls chop_always + +namespace OpenApiTests.AttributeTypes; + +[UsedImplicitly(ImplicitUseTargetFlags.Members)] +public sealed class AttributeTypesDbContext(DbContextOptions options) + : TestableDbContext(options) +{ + public DbSet TypeContainers => Set(); + + protected override void ConfigureConventions(ModelConfigurationBuilder builder) + { + builder.Properties() + .HaveConversion(); + + builder.Properties() + .HaveConversion(); + + builder.Properties() + .HaveConversion(); + + builder.Properties() + .HaveConversion(); + + builder.Properties() + .HaveConversion(); + + builder.Properties() + .HaveConversion(); + + builder.Properties() + .HaveConversion(); + } + + private sealed class Int128Converter() + : ValueConverter(value => TypeConverterRegistry.Int128ToString(value), value => TypeConverterRegistry.Int128FromString(value)); + + private sealed class UInt128Converter() + : ValueConverter(value => TypeConverterRegistry.UInt128ToString(value), value => TypeConverterRegistry.UInt128FromString(value)); + + private sealed class HalfConverter() + : ValueConverter(value => TypeConverterRegistry.HalfToFloat(value), value => TypeConverterRegistry.HalfFromFloat(value)); + + private sealed class ComplexConverter() + : ValueConverter(value => TypeConverterRegistry.ComplexToString(value), value => TypeConverterRegistry.ComplexFromString(value)); + + private sealed class RuneConverter() + : ValueConverter(value => TypeConverterRegistry.RuneToString(value), value => TypeConverterRegistry.RuneFromString(value)); + + private sealed class IPNetworkConverter() + : ValueConverter(value => TypeConverterRegistry.IPNetworkToString(value), value => TypeConverterRegistry.IPNetworkFromString(value)); + + private sealed class VersionConverter() + : ValueConverter(value => TypeConverterRegistry.VersionToString(value), value => TypeConverterRegistry.VersionFromString(value)); +} diff --git a/test/OpenApiTests/AttributeTypes/AttributeTypesFakers.cs b/test/OpenApiTests/AttributeTypes/AttributeTypesFakers.cs new file mode 100644 index 0000000000..922061e80a --- /dev/null +++ b/test/OpenApiTests/AttributeTypes/AttributeTypesFakers.cs @@ -0,0 +1,107 @@ +using System.Buffers.Binary; +using System.Globalization; +using System.Net; +using System.Numerics; +using System.Text; +using Bogus; +using JetBrains.Annotations; +using TestBuildingBlocks; + +// @formatter:wrap_chained_method_calls chop_if_long +// @formatter:wrap_before_first_method_call true + +namespace OpenApiTests.AttributeTypes; + +[UsedImplicitly(ImplicitUseTargetFlags.Members)] +public sealed class AttributeTypesFakers +{ + private readonly Lazy> _lazyTypeContainerFaker = new(() => new Faker() + .MakeDeterministic() + .RuleFor(container => container.TestBoolean, faker => faker.Random.Bool()) + .RuleFor(container => container.TestNullableBoolean, faker => faker.Random.Bool()) + .RuleFor(container => container.TestByte, faker => faker.Random.Byte()) + .RuleFor(container => container.TestNullableByte, faker => faker.Random.Byte()) + .RuleFor(container => container.TestSignedByte, faker => faker.Random.SByte()) + .RuleFor(container => container.TestNullableSignedByte, faker => faker.Random.SByte()) + .RuleFor(container => container.TestInt16, faker => faker.Random.Short()) + .RuleFor(container => container.TestNullableInt16, faker => faker.Random.Short()) + .RuleFor(container => container.TestUnsignedInt16, faker => faker.Random.UShort()) + .RuleFor(container => container.TestNullableUnsignedInt16, faker => faker.Random.UShort()) + .RuleFor(container => container.TestInt32, faker => faker.Random.Int()) + .RuleFor(container => container.TestNullableInt32, faker => faker.Random.Int()) + .RuleFor(container => container.TestUnsignedInt32, faker => faker.Random.UInt(0, int.MaxValue)) + .RuleFor(container => container.TestNullableUnsignedInt32, faker => faker.Random.UInt(0, int.MaxValue)) + .RuleFor(container => container.TestInt64, faker => faker.Random.Long()) + .RuleFor(container => container.TestNullableInt64, faker => faker.Random.Long()) + .RuleFor(container => container.TestUnsignedInt64, faker => faker.Random.ULong(0, long.MaxValue)) + .RuleFor(container => container.TestNullableUnsignedInt64, faker => faker.Random.ULong(0, long.MaxValue)) + .RuleFor(container => container.TestInt128, faker => faker.Random.ULong()) + .RuleFor(container => container.TestNullableInt128, faker => faker.Random.ULong()) + .RuleFor(container => container.TestUnsignedInt128, faker => faker.Random.ULong()) + .RuleFor(container => container.TestNullableUnsignedInt128, faker => faker.Random.ULong()) + .RuleFor(container => container.TestBigInteger, faker => faker.Random.ULong()) + .RuleFor(container => container.TestNullableBigInteger, faker => faker.Random.ULong()) + .RuleFor(container => container.TestHalf, faker => (Half)faker.Random.Float()) + .RuleFor(container => container.TestNullableHalf, faker => (Half)faker.Random.Float()) + .RuleFor(container => container.TestFloat, faker => faker.Random.Float()) + .RuleFor(container => container.TestNullableFloat, faker => faker.Random.Float()) + .RuleFor(container => container.TestDouble, faker => faker.Random.Double()) + .RuleFor(container => container.TestNullableDouble, faker => faker.Random.Double()) + .RuleFor(container => container.TestDecimal, faker => faker.Random.Decimal()) + .RuleFor(container => container.TestNullableDecimal, faker => faker.Random.Decimal()) + .RuleFor(container => container.TestComplex, GetRandomComplex) + .RuleFor(container => container.TestNullableComplex, faker => GetRandomComplex(faker)) + .RuleFor(container => container.TestChar, faker => faker.Lorem.Letter()[0]) + .RuleFor(container => container.TestNullableChar, faker => faker.Lorem.Letter()[0]) + .RuleFor(container => container.TestString, faker => faker.Random.String2(faker.Random.Int(5, 50))) + .RuleFor(container => container.TestNullableString, faker => faker.Random.String2(faker.Random.Int(5, 50))) + .RuleFor(container => container.TestRune, faker => new Rune(faker.Random.Utf16String(1, 1)[0])) + .RuleFor(container => container.TestNullableRune, faker => new Rune(faker.Random.Utf16String(1, 1)[0])) + .RuleFor(container => container.TestDateTimeOffset, faker => faker.Date.PastOffset().ToUniversalTime().TruncateToWholeMilliseconds()) + .RuleFor(container => container.TestNullableDateTimeOffset, faker => faker.Date.PastOffset().ToUniversalTime().TruncateToWholeMilliseconds()) + .RuleFor(container => container.TestDateTime, faker => faker.Date.Past().ToUniversalTime().TruncateToWholeMilliseconds()) + .RuleFor(container => container.TestNullableDateTime, faker => faker.Date.Past().ToUniversalTime().TruncateToWholeMilliseconds()) + .RuleFor(container => container.TestDateOnly, faker => faker.Date.PastDateOnly()) + .RuleFor(container => container.TestNullableDateOnly, faker => faker.Date.PastDateOnly()) + .RuleFor(container => container.TestTimeOnly, faker => faker.Date.RecentTimeOnly().TruncateToWholeMilliseconds()) + .RuleFor(container => container.TestNullableTimeOnly, faker => faker.Date.RecentTimeOnly().TruncateToWholeMilliseconds()) + .RuleFor(container => container.TestTimeSpan, faker => faker.Date.Timespan().TruncateToWholeMilliseconds()) + .RuleFor(container => container.TestNullableTimeSpan, faker => faker.Date.Timespan().TruncateToWholeMilliseconds()) + .RuleFor(container => container.TestEnum, faker => faker.PickRandom()) + .RuleFor(container => container.TestNullableEnum, faker => faker.PickRandom()) + .RuleFor(container => container.TestGuid, faker => faker.Random.Guid()) + .RuleFor(container => container.TestNullableGuid, faker => faker.Random.Guid()) + .RuleFor(container => container.TestUri, faker => new Uri(faker.Internet.UrlWithPath())) + .RuleFor(container => container.TestNullableUri, faker => new Uri(faker.Internet.UrlWithPath())) + .RuleFor(container => container.TestIPAddress, faker => faker.Internet.IpAddress()) + .RuleFor(container => container.TestNullableIPAddress, faker => faker.Internet.IpAddress()) + .RuleFor(container => container.TestIPNetwork, faker => CreateNetworkMask(faker.Internet.IpAddress(), faker.Random.Int(0, 32))) + .RuleFor(container => container.TestNullableIPNetwork, faker => CreateNetworkMask(faker.Internet.IpAddress(), faker.Random.Int(0, 32))) + .RuleFor(container => container.TestVersion, faker => faker.System.Version()) + .RuleFor(container => container.TestNullableVersion, faker => faker.System.Version())); + + public Faker TypeContainer => _lazyTypeContainerFaker.Value; + + private static Complex GetRandomComplex(Faker faker) + { + string realValue = faker.Random.Double().ToString(CultureInfo.InvariantCulture); + string imaginaryValue = faker.Random.Double().ToString(CultureInfo.InvariantCulture); + return Complex.Parse($"<{realValue}; {imaginaryValue}>", CultureInfo.InvariantCulture); + } + + private static IPNetwork CreateNetworkMask(IPAddress ipAddress, int prefixLength) + { + byte[] ipAddressBytes = ipAddress.GetAddressBytes(); + uint ipAddressValue = BitConverter.ToUInt32(ipAddressBytes); + + uint networkMask = (uint)((long)uint.MaxValue << (32 - prefixLength)); + + if (BitConverter.IsLittleEndian) + { + networkMask = BinaryPrimitives.ReverseEndianness(networkMask); + } + + uint networkAddressValue = ipAddressValue & networkMask; + return new IPNetwork(new IPAddress(networkAddressValue), prefixLength); + } +} diff --git a/test/OpenApiTests/AttributeTypes/AttributeTypesStartup.cs b/test/OpenApiTests/AttributeTypes/AttributeTypesStartup.cs new file mode 100644 index 0000000000..c71515104e --- /dev/null +++ b/test/OpenApiTests/AttributeTypes/AttributeTypesStartup.cs @@ -0,0 +1,113 @@ +using System.Net; +using System.Numerics; +using System.Text; +using System.Text.Json.Serialization; +using JetBrains.Annotations; +using JsonApiDotNetCore.Configuration; +using JsonApiDotNetCore.Queries.Parsing; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; + +namespace OpenApiTests.AttributeTypes; + +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] +public sealed class AttributeTypesStartup : OpenApiStartup +{ + public override void ConfigureServices(IServiceCollection services) + { + services.AddTransient(); + + base.ConfigureServices(services); + } + + protected override void ConfigureJsonApiOptions(JsonApiOptions options) + { + base.ConfigureJsonApiOptions(options); + + options.SerializerOptions.Converters.Add(new Int128JsonConverter()); + options.SerializerOptions.Converters.Add(new UInt128JsonConverter()); + options.SerializerOptions.Converters.Add(new BigIntegerJsonConverter()); + options.SerializerOptions.Converters.Add(new ComplexJsonConverter()); + options.SerializerOptions.Converters.Add(new RuneJsonConverter()); + options.SerializerOptions.Converters.Add(new JsonStringEnumConverter()); + options.SerializerOptions.Converters.Add(new IPAddressJsonConverter()); + options.SerializerOptions.Converters.Add(new IPNetworkJsonConverter()); + } + + protected override void ConfigureSwaggerGenOptions(SwaggerGenOptions options) + { + base.ConfigureSwaggerGenOptions(options); + + options.MapType(() => new OpenApiSchema + { + Type = "string" + }); + + options.MapType(() => new OpenApiSchema + { + Type = "string" + }); + + options.MapType(() => new OpenApiSchema + { + Type = "string" + }); + + options.MapType(() => new OpenApiSchema + { + Type = "number", + Format = "float" + }); + + options.MapType(() => new OpenApiSchema + { + Type = "string" + }); + + options.MapType(() => new OpenApiSchema + { + Type = "string", + MaxLength = 4 + }); + + options.MapType(() => new OpenApiSchema + { + // Beware that "duration" does not round-trip universally. NSwag and Kiota are incompatible. + Type = "string", + Format = "duration" + }); + + options.MapType(() => new OpenApiSchema + { + Type = "string", + Format = "ipv4" + }); + + options.MapType(() => new OpenApiSchema + { + Type = "string" + }); + } + + private sealed class Int128JsonConverter() + : ValueTypeJsonConverter(TypeConverterRegistry.Int128FromString, TypeConverterRegistry.Int128ToString); + + private sealed class UInt128JsonConverter() + : ValueTypeJsonConverter(TypeConverterRegistry.UInt128FromString, TypeConverterRegistry.UInt128ToString); + + private sealed class BigIntegerJsonConverter() + : ValueTypeJsonConverter(TypeConverterRegistry.BigIntegerFromString, TypeConverterRegistry.BigIntegerToString); + + private sealed class ComplexJsonConverter() + : ValueTypeJsonConverter(TypeConverterRegistry.ComplexFromString, TypeConverterRegistry.ComplexToString); + + private sealed class RuneJsonConverter() + : ValueTypeJsonConverter(TypeConverterRegistry.RuneFromString, TypeConverterRegistry.RuneToString); + + private sealed class IPAddressJsonConverter() + : ReferenceTypeJsonConverter(TypeConverterRegistry.IPAddressFromString, TypeConverterRegistry.IPAddressToString); + + private sealed class IPNetworkJsonConverter() + : ValueTypeJsonConverter(TypeConverterRegistry.IPNetworkFromString, TypeConverterRegistry.IPNetworkToString); +} diff --git a/test/OpenApiTests/AttributeTypes/GeneratedSwagger/swagger.g.json b/test/OpenApiTests/AttributeTypes/GeneratedSwagger/swagger.g.json new file mode 100644 index 0000000000..370668bcd6 --- /dev/null +++ b/test/OpenApiTests/AttributeTypes/GeneratedSwagger/swagger.g.json @@ -0,0 +1,1995 @@ +{ + "openapi": "3.0.4", + "info": { + "title": "OpenApiTests", + "version": "1.0" + }, + "servers": [ + { + "url": "http://localhost" + } + ], + "paths": { + "/typeContainers": { + "get": { + "tags": [ + "typeContainers" + ], + "summary": "Retrieves a collection of typeContainers.", + "operationId": "getTypeContainerCollection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": "" + } + }, + { + "name": "If-None-Match", + "in": "header", + "description": "A list of ETags, resulting in HTTP status 304 without a body, if one of them matches the current fingerprint.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully returns the found typeContainers, or an empty array if none were found.", + "headers": { + "ETag": { + "description": "A fingerprint of the HTTP response, which can be used in an If-None-Match header to only fetch changes.", + "required": true, + "schema": { + "type": "string" + } + } + }, + "content": { + "application/vnd.api+json; ext=openapi": { + "schema": { + "$ref": "#/components/schemas/typeContainerCollectionResponseDocument" + } + } + } + }, + "304": { + "description": "The fingerprint of the HTTP response matches one of the ETags from the incoming If-None-Match header.", + "headers": { + "ETag": { + "description": "A fingerprint of the HTTP response, which can be used in an If-None-Match header to only fetch changes.", + "required": true, + "schema": { + "type": "string" + } + } + } + }, + "400": { + "description": "The query string is invalid.", + "content": { + "application/vnd.api+json; ext=openapi": { + "schema": { + "$ref": "#/components/schemas/errorResponseDocument" + } + } + } + } + } + }, + "head": { + "tags": [ + "typeContainers" + ], + "summary": "Retrieves a collection of typeContainers without returning them.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", + "operationId": "headTypeContainerCollection", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": "" + } + }, + { + "name": "If-None-Match", + "in": "header", + "description": "A list of ETags, resulting in HTTP status 304 without a body, if one of them matches the current fingerprint.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The operation completed successfully.", + "headers": { + "ETag": { + "description": "A fingerprint of the HTTP response, which can be used in an If-None-Match header to only fetch changes.", + "required": true, + "schema": { + "type": "string" + } + }, + "Content-Length": { + "description": "Size of the HTTP response body, in bytes.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + } + }, + "304": { + "description": "The fingerprint of the HTTP response matches one of the ETags from the incoming If-None-Match header.", + "headers": { + "ETag": { + "description": "A fingerprint of the HTTP response, which can be used in an If-None-Match header to only fetch changes.", + "required": true, + "schema": { + "type": "string" + } + } + } + }, + "400": { + "description": "The query string is invalid." + } + } + }, + "post": { + "tags": [ + "typeContainers" + ], + "summary": "Creates a new typeContainer.", + "operationId": "postTypeContainer", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": "" + } + } + ], + "requestBody": { + "description": "The attributes and relationships of the typeContainer to create.", + "content": { + "application/vnd.api+json; ext=openapi": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/createTypeContainerRequestDocument" + } + ] + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "The typeContainer was successfully created, which resulted in additional changes. The newly created typeContainer is returned.", + "headers": { + "Location": { + "description": "The URL at which the newly created typeContainer can be retrieved.", + "required": true, + "schema": { + "type": "string", + "format": "uri" + } + } + }, + "content": { + "application/vnd.api+json; ext=openapi": { + "schema": { + "$ref": "#/components/schemas/primaryTypeContainerResponseDocument" + } + } + } + }, + "204": { + "description": "The typeContainer was successfully created, which did not result in additional changes." + }, + "400": { + "description": "The query string is invalid or the request body is missing or malformed.", + "content": { + "application/vnd.api+json; ext=openapi": { + "schema": { + "$ref": "#/components/schemas/errorResponseDocument" + } + } + } + }, + "403": { + "description": "Client-generated IDs cannot be used at this endpoint.", + "content": { + "application/vnd.api+json; ext=openapi": { + "schema": { + "$ref": "#/components/schemas/errorResponseDocument" + } + } + } + }, + "404": { + "description": "A related resource does not exist.", + "content": { + "application/vnd.api+json; ext=openapi": { + "schema": { + "$ref": "#/components/schemas/errorResponseDocument" + } + } + } + }, + "409": { + "description": "The request body contains conflicting information or another resource with the same ID already exists.", + "content": { + "application/vnd.api+json; ext=openapi": { + "schema": { + "$ref": "#/components/schemas/errorResponseDocument" + } + } + } + }, + "422": { + "description": "Validation of the request body failed.", + "content": { + "application/vnd.api+json; ext=openapi": { + "schema": { + "$ref": "#/components/schemas/errorResponseDocument" + } + } + } + } + } + } + }, + "/typeContainers/{id}": { + "get": { + "tags": [ + "typeContainers" + ], + "summary": "Retrieves an individual typeContainer by its identifier.", + "operationId": "getTypeContainer", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the typeContainer to retrieve.", + "required": true, + "schema": { + "minLength": 1, + "type": "string", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": "" + } + }, + { + "name": "If-None-Match", + "in": "header", + "description": "A list of ETags, resulting in HTTP status 304 without a body, if one of them matches the current fingerprint.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully returns the found typeContainer.", + "headers": { + "ETag": { + "description": "A fingerprint of the HTTP response, which can be used in an If-None-Match header to only fetch changes.", + "required": true, + "schema": { + "type": "string" + } + } + }, + "content": { + "application/vnd.api+json; ext=openapi": { + "schema": { + "$ref": "#/components/schemas/primaryTypeContainerResponseDocument" + } + } + } + }, + "304": { + "description": "The fingerprint of the HTTP response matches one of the ETags from the incoming If-None-Match header.", + "headers": { + "ETag": { + "description": "A fingerprint of the HTTP response, which can be used in an If-None-Match header to only fetch changes.", + "required": true, + "schema": { + "type": "string" + } + } + } + }, + "400": { + "description": "The query string is invalid.", + "content": { + "application/vnd.api+json; ext=openapi": { + "schema": { + "$ref": "#/components/schemas/errorResponseDocument" + } + } + } + }, + "404": { + "description": "The typeContainer does not exist.", + "content": { + "application/vnd.api+json; ext=openapi": { + "schema": { + "$ref": "#/components/schemas/errorResponseDocument" + } + } + } + } + } + }, + "head": { + "tags": [ + "typeContainers" + ], + "summary": "Retrieves an individual typeContainer by its identifier without returning it.", + "description": "Compare the returned ETag HTTP header with an earlier one to determine if the response has changed since it was fetched.", + "operationId": "headTypeContainer", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the typeContainer to retrieve.", + "required": true, + "schema": { + "minLength": 1, + "type": "string", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": "" + } + }, + { + "name": "If-None-Match", + "in": "header", + "description": "A list of ETags, resulting in HTTP status 304 without a body, if one of them matches the current fingerprint.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The operation completed successfully.", + "headers": { + "ETag": { + "description": "A fingerprint of the HTTP response, which can be used in an If-None-Match header to only fetch changes.", + "required": true, + "schema": { + "type": "string" + } + }, + "Content-Length": { + "description": "Size of the HTTP response body, in bytes.", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + } + }, + "304": { + "description": "The fingerprint of the HTTP response matches one of the ETags from the incoming If-None-Match header.", + "headers": { + "ETag": { + "description": "A fingerprint of the HTTP response, which can be used in an If-None-Match header to only fetch changes.", + "required": true, + "schema": { + "type": "string" + } + } + } + }, + "400": { + "description": "The query string is invalid." + }, + "404": { + "description": "The typeContainer does not exist." + } + } + }, + "patch": { + "tags": [ + "typeContainers" + ], + "summary": "Updates an existing typeContainer.", + "operationId": "patchTypeContainer", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the typeContainer to update.", + "required": true, + "schema": { + "minLength": 1, + "type": "string", + "format": "int64" + } + }, + { + "name": "query", + "in": "query", + "description": "For syntax, see the documentation for the [`include`](https://www.jsonapi.net/usage/reading/including-relationships.html)/[`filter`](https://www.jsonapi.net/usage/reading/filtering.html)/[`sort`](https://www.jsonapi.net/usage/reading/sorting.html)/[`page`](https://www.jsonapi.net/usage/reading/pagination.html)/[`fields`](https://www.jsonapi.net/usage/reading/sparse-fieldset-selection.html) query string parameters.", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "nullable": true + }, + "example": "" + } + } + ], + "requestBody": { + "description": "The attributes and relationships of the typeContainer to update. Omitted fields are left unchanged.", + "content": { + "application/vnd.api+json; ext=openapi": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/updateTypeContainerRequestDocument" + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "The typeContainer was successfully updated, which resulted in additional changes. The updated typeContainer is returned.", + "content": { + "application/vnd.api+json; ext=openapi": { + "schema": { + "$ref": "#/components/schemas/primaryTypeContainerResponseDocument" + } + } + } + }, + "204": { + "description": "The typeContainer was successfully updated, which did not result in additional changes." + }, + "400": { + "description": "The query string is invalid or the request body is missing or malformed.", + "content": { + "application/vnd.api+json; ext=openapi": { + "schema": { + "$ref": "#/components/schemas/errorResponseDocument" + } + } + } + }, + "404": { + "description": "The typeContainer or a related resource does not exist.", + "content": { + "application/vnd.api+json; ext=openapi": { + "schema": { + "$ref": "#/components/schemas/errorResponseDocument" + } + } + } + }, + "409": { + "description": "A resource type or identifier in the request body is incompatible.", + "content": { + "application/vnd.api+json; ext=openapi": { + "schema": { + "$ref": "#/components/schemas/errorResponseDocument" + } + } + } + }, + "422": { + "description": "Validation of the request body failed.", + "content": { + "application/vnd.api+json; ext=openapi": { + "schema": { + "$ref": "#/components/schemas/errorResponseDocument" + } + } + } + } + } + }, + "delete": { + "tags": [ + "typeContainers" + ], + "summary": "Deletes an existing typeContainer by its identifier.", + "operationId": "deleteTypeContainer", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The identifier of the typeContainer to delete.", + "required": true, + "schema": { + "minLength": 1, + "type": "string", + "format": "int64" + } + } + ], + "responses": { + "204": { + "description": "The typeContainer was successfully deleted." + }, + "404": { + "description": "The typeContainer does not exist.", + "content": { + "application/vnd.api+json; ext=openapi": { + "schema": { + "$ref": "#/components/schemas/errorResponseDocument" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "attributesInCreateRequest": { + "required": [ + "openapi:discriminator" + ], + "type": "object", + "properties": { + "openapi:discriminator": { + "allOf": [ + { + "$ref": "#/components/schemas/resourceType" + } + ] + } + }, + "additionalProperties": false, + "discriminator": { + "propertyName": "openapi:discriminator", + "mapping": { + "typeContainers": "#/components/schemas/attributesInCreateTypeContainerRequest" + } + }, + "x-abstract": true + }, + "attributesInCreateTypeContainerRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/attributesInCreateRequest" + }, + { + "required": [ + "testIPAddress", + "testString", + "testUri", + "testVersion" + ], + "type": "object", + "properties": { + "testBoolean": { + "type": "boolean" + }, + "testNullableBoolean": { + "type": "boolean", + "nullable": true + }, + "testByte": { + "type": "integer", + "format": "int32" + }, + "testNullableByte": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "testSignedByte": { + "type": "integer", + "format": "int32" + }, + "testNullableSignedByte": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "testInt16": { + "type": "integer", + "format": "int32" + }, + "testNullableInt16": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "testUnsignedInt16": { + "type": "integer", + "format": "int32" + }, + "testNullableUnsignedInt16": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "testInt32": { + "type": "integer", + "format": "int32" + }, + "testNullableInt32": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "testUnsignedInt32": { + "type": "integer", + "format": "int32" + }, + "testNullableUnsignedInt32": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "testInt64": { + "type": "integer", + "format": "int64" + }, + "testNullableInt64": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "testUnsignedInt64": { + "type": "integer", + "format": "int64" + }, + "testNullableUnsignedInt64": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "testInt128": { + "type": "string" + }, + "testNullableInt128": { + "type": "string", + "nullable": true + }, + "testUnsignedInt128": { + "type": "string" + }, + "testNullableUnsignedInt128": { + "type": "string", + "nullable": true + }, + "testBigInteger": { + "type": "string" + }, + "testNullableBigInteger": { + "type": "string", + "nullable": true + }, + "testHalf": { + "type": "number", + "format": "float" + }, + "testNullableHalf": { + "type": "number", + "format": "float", + "nullable": true + }, + "testFloat": { + "type": "number", + "format": "float" + }, + "testNullableFloat": { + "type": "number", + "format": "float", + "nullable": true + }, + "testDouble": { + "type": "number", + "format": "double" + }, + "testNullableDouble": { + "type": "number", + "format": "double", + "nullable": true + }, + "testDecimal": { + "type": "number", + "format": "double" + }, + "testNullableDecimal": { + "type": "number", + "format": "double", + "nullable": true + }, + "testComplex": { + "type": "string" + }, + "testNullableComplex": { + "type": "string", + "nullable": true + }, + "testChar": { + "type": "string" + }, + "testNullableChar": { + "type": "string", + "nullable": true + }, + "testString": { + "type": "string" + }, + "testNullableString": { + "type": "string", + "nullable": true + }, + "testRune": { + "maxLength": 4, + "type": "string" + }, + "testNullableRune": { + "maxLength": 4, + "type": "string", + "nullable": true + }, + "testDateTimeOffset": { + "type": "string", + "format": "date-time" + }, + "testNullableDateTimeOffset": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "testDateTime": { + "type": "string", + "format": "date-time" + }, + "testNullableDateTime": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "testDateOnly": { + "type": "string", + "format": "date" + }, + "testNullableDateOnly": { + "type": "string", + "format": "date", + "nullable": true + }, + "testTimeOnly": { + "type": "string", + "format": "time" + }, + "testNullableTimeOnly": { + "type": "string", + "format": "time", + "nullable": true + }, + "testTimeSpan": { + "type": "string", + "format": "duration" + }, + "testNullableTimeSpan": { + "type": "string", + "format": "duration", + "nullable": true + }, + "testEnum": { + "allOf": [ + { + "$ref": "#/components/schemas/dayOfWeek" + } + ] + }, + "testNullableEnum": { + "allOf": [ + { + "$ref": "#/components/schemas/dayOfWeek" + } + ], + "nullable": true + }, + "testGuid": { + "type": "string", + "format": "uuid" + }, + "testNullableGuid": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "testUri": { + "type": "string", + "format": "uri" + }, + "testNullableUri": { + "type": "string", + "format": "uri", + "nullable": true + }, + "testIPAddress": { + "type": "string", + "format": "ipv4" + }, + "testNullableIPAddress": { + "type": "string", + "format": "ipv4", + "nullable": true + }, + "testIPNetwork": { + "type": "string" + }, + "testNullableIPNetwork": { + "type": "string", + "nullable": true + }, + "testVersion": { + "type": "string" + }, + "testNullableVersion": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + ], + "additionalProperties": false + }, + "attributesInResponse": { + "required": [ + "openapi:discriminator" + ], + "type": "object", + "properties": { + "openapi:discriminator": { + "allOf": [ + { + "$ref": "#/components/schemas/resourceType" + } + ] + } + }, + "additionalProperties": false, + "discriminator": { + "propertyName": "openapi:discriminator", + "mapping": { + "typeContainers": "#/components/schemas/attributesInTypeContainerResponse" + } + }, + "x-abstract": true + }, + "attributesInTypeContainerResponse": { + "allOf": [ + { + "$ref": "#/components/schemas/attributesInResponse" + }, + { + "type": "object", + "properties": { + "testBoolean": { + "type": "boolean" + }, + "testNullableBoolean": { + "type": "boolean", + "nullable": true + }, + "testByte": { + "type": "integer", + "format": "int32" + }, + "testNullableByte": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "testSignedByte": { + "type": "integer", + "format": "int32" + }, + "testNullableSignedByte": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "testInt16": { + "type": "integer", + "format": "int32" + }, + "testNullableInt16": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "testUnsignedInt16": { + "type": "integer", + "format": "int32" + }, + "testNullableUnsignedInt16": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "testInt32": { + "type": "integer", + "format": "int32" + }, + "testNullableInt32": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "testUnsignedInt32": { + "type": "integer", + "format": "int32" + }, + "testNullableUnsignedInt32": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "testInt64": { + "type": "integer", + "format": "int64" + }, + "testNullableInt64": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "testUnsignedInt64": { + "type": "integer", + "format": "int64" + }, + "testNullableUnsignedInt64": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "testInt128": { + "type": "string" + }, + "testNullableInt128": { + "type": "string", + "nullable": true + }, + "testUnsignedInt128": { + "type": "string" + }, + "testNullableUnsignedInt128": { + "type": "string", + "nullable": true + }, + "testBigInteger": { + "type": "string" + }, + "testNullableBigInteger": { + "type": "string", + "nullable": true + }, + "testHalf": { + "type": "number", + "format": "float" + }, + "testNullableHalf": { + "type": "number", + "format": "float", + "nullable": true + }, + "testFloat": { + "type": "number", + "format": "float" + }, + "testNullableFloat": { + "type": "number", + "format": "float", + "nullable": true + }, + "testDouble": { + "type": "number", + "format": "double" + }, + "testNullableDouble": { + "type": "number", + "format": "double", + "nullable": true + }, + "testDecimal": { + "type": "number", + "format": "double" + }, + "testNullableDecimal": { + "type": "number", + "format": "double", + "nullable": true + }, + "testComplex": { + "type": "string" + }, + "testNullableComplex": { + "type": "string", + "nullable": true + }, + "testChar": { + "type": "string" + }, + "testNullableChar": { + "type": "string", + "nullable": true + }, + "testString": { + "type": "string" + }, + "testNullableString": { + "type": "string", + "nullable": true + }, + "testRune": { + "maxLength": 4, + "type": "string" + }, + "testNullableRune": { + "maxLength": 4, + "type": "string", + "nullable": true + }, + "testDateTimeOffset": { + "type": "string", + "format": "date-time" + }, + "testNullableDateTimeOffset": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "testDateTime": { + "type": "string", + "format": "date-time" + }, + "testNullableDateTime": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "testDateOnly": { + "type": "string", + "format": "date" + }, + "testNullableDateOnly": { + "type": "string", + "format": "date", + "nullable": true + }, + "testTimeOnly": { + "type": "string", + "format": "time" + }, + "testNullableTimeOnly": { + "type": "string", + "format": "time", + "nullable": true + }, + "testTimeSpan": { + "type": "string", + "format": "duration" + }, + "testNullableTimeSpan": { + "type": "string", + "format": "duration", + "nullable": true + }, + "testEnum": { + "allOf": [ + { + "$ref": "#/components/schemas/dayOfWeek" + } + ] + }, + "testNullableEnum": { + "allOf": [ + { + "$ref": "#/components/schemas/dayOfWeek" + } + ], + "nullable": true + }, + "testGuid": { + "type": "string", + "format": "uuid" + }, + "testNullableGuid": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "testUri": { + "type": "string", + "format": "uri" + }, + "testNullableUri": { + "type": "string", + "format": "uri", + "nullable": true + }, + "testIPAddress": { + "type": "string", + "format": "ipv4" + }, + "testNullableIPAddress": { + "type": "string", + "format": "ipv4", + "nullable": true + }, + "testIPNetwork": { + "type": "string" + }, + "testNullableIPNetwork": { + "type": "string", + "nullable": true + }, + "testVersion": { + "type": "string" + }, + "testNullableVersion": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + ], + "additionalProperties": false + }, + "attributesInUpdateRequest": { + "required": [ + "openapi:discriminator" + ], + "type": "object", + "properties": { + "openapi:discriminator": { + "allOf": [ + { + "$ref": "#/components/schemas/resourceType" + } + ] + } + }, + "additionalProperties": false, + "discriminator": { + "propertyName": "openapi:discriminator", + "mapping": { + "typeContainers": "#/components/schemas/attributesInUpdateTypeContainerRequest" + } + }, + "x-abstract": true + }, + "attributesInUpdateTypeContainerRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/attributesInUpdateRequest" + }, + { + "type": "object", + "properties": { + "testBoolean": { + "type": "boolean" + }, + "testNullableBoolean": { + "type": "boolean", + "nullable": true + }, + "testByte": { + "type": "integer", + "format": "int32" + }, + "testNullableByte": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "testSignedByte": { + "type": "integer", + "format": "int32" + }, + "testNullableSignedByte": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "testInt16": { + "type": "integer", + "format": "int32" + }, + "testNullableInt16": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "testUnsignedInt16": { + "type": "integer", + "format": "int32" + }, + "testNullableUnsignedInt16": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "testInt32": { + "type": "integer", + "format": "int32" + }, + "testNullableInt32": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "testUnsignedInt32": { + "type": "integer", + "format": "int32" + }, + "testNullableUnsignedInt32": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "testInt64": { + "type": "integer", + "format": "int64" + }, + "testNullableInt64": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "testUnsignedInt64": { + "type": "integer", + "format": "int64" + }, + "testNullableUnsignedInt64": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "testInt128": { + "type": "string" + }, + "testNullableInt128": { + "type": "string", + "nullable": true + }, + "testUnsignedInt128": { + "type": "string" + }, + "testNullableUnsignedInt128": { + "type": "string", + "nullable": true + }, + "testBigInteger": { + "type": "string" + }, + "testNullableBigInteger": { + "type": "string", + "nullable": true + }, + "testHalf": { + "type": "number", + "format": "float" + }, + "testNullableHalf": { + "type": "number", + "format": "float", + "nullable": true + }, + "testFloat": { + "type": "number", + "format": "float" + }, + "testNullableFloat": { + "type": "number", + "format": "float", + "nullable": true + }, + "testDouble": { + "type": "number", + "format": "double" + }, + "testNullableDouble": { + "type": "number", + "format": "double", + "nullable": true + }, + "testDecimal": { + "type": "number", + "format": "double" + }, + "testNullableDecimal": { + "type": "number", + "format": "double", + "nullable": true + }, + "testComplex": { + "type": "string" + }, + "testNullableComplex": { + "type": "string", + "nullable": true + }, + "testChar": { + "type": "string" + }, + "testNullableChar": { + "type": "string", + "nullable": true + }, + "testString": { + "type": "string" + }, + "testNullableString": { + "type": "string", + "nullable": true + }, + "testRune": { + "maxLength": 4, + "type": "string" + }, + "testNullableRune": { + "maxLength": 4, + "type": "string", + "nullable": true + }, + "testDateTimeOffset": { + "type": "string", + "format": "date-time" + }, + "testNullableDateTimeOffset": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "testDateTime": { + "type": "string", + "format": "date-time" + }, + "testNullableDateTime": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "testDateOnly": { + "type": "string", + "format": "date" + }, + "testNullableDateOnly": { + "type": "string", + "format": "date", + "nullable": true + }, + "testTimeOnly": { + "type": "string", + "format": "time" + }, + "testNullableTimeOnly": { + "type": "string", + "format": "time", + "nullable": true + }, + "testTimeSpan": { + "type": "string", + "format": "duration" + }, + "testNullableTimeSpan": { + "type": "string", + "format": "duration", + "nullable": true + }, + "testEnum": { + "allOf": [ + { + "$ref": "#/components/schemas/dayOfWeek" + } + ] + }, + "testNullableEnum": { + "allOf": [ + { + "$ref": "#/components/schemas/dayOfWeek" + } + ], + "nullable": true + }, + "testGuid": { + "type": "string", + "format": "uuid" + }, + "testNullableGuid": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "testUri": { + "type": "string", + "format": "uri" + }, + "testNullableUri": { + "type": "string", + "format": "uri", + "nullable": true + }, + "testIPAddress": { + "type": "string", + "format": "ipv4" + }, + "testNullableIPAddress": { + "type": "string", + "format": "ipv4", + "nullable": true + }, + "testIPNetwork": { + "type": "string" + }, + "testNullableIPNetwork": { + "type": "string", + "nullable": true + }, + "testVersion": { + "type": "string" + }, + "testNullableVersion": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + ], + "additionalProperties": false + }, + "createTypeContainerRequestDocument": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "allOf": [ + { + "$ref": "#/components/schemas/dataInCreateTypeContainerRequest" + } + ] + }, + "meta": { + "allOf": [ + { + "$ref": "#/components/schemas/meta" + } + ] + } + }, + "additionalProperties": false + }, + "dataInCreateTypeContainerRequest": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/resourceInCreateRequest" + }, + { + "type": "object", + "properties": { + "attributes": { + "allOf": [ + { + "$ref": "#/components/schemas/attributesInCreateTypeContainerRequest" + } + ] + } + }, + "additionalProperties": false + } + ], + "additionalProperties": false + }, + "dataInTypeContainerResponse": { + "allOf": [ + { + "$ref": "#/components/schemas/resourceInResponse" + }, + { + "required": [ + "id" + ], + "type": "object", + "properties": { + "id": { + "minLength": 1, + "type": "string", + "format": "int64" + }, + "attributes": { + "allOf": [ + { + "$ref": "#/components/schemas/attributesInTypeContainerResponse" + } + ] + }, + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/resourceLinks" + } + ] + } + }, + "additionalProperties": false + } + ], + "additionalProperties": false + }, + "dataInUpdateTypeContainerRequest": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/resourceInUpdateRequest" + }, + { + "required": [ + "id" + ], + "type": "object", + "properties": { + "id": { + "minLength": 1, + "type": "string", + "format": "int64" + }, + "attributes": { + "allOf": [ + { + "$ref": "#/components/schemas/attributesInUpdateTypeContainerRequest" + } + ] + } + }, + "additionalProperties": false + } + ], + "additionalProperties": false + }, + "dayOfWeek": { + "enum": [ + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday" + ], + "type": "string" + }, + "errorLinks": { + "type": "object", + "properties": { + "about": { + "type": "string", + "nullable": true + }, + "type": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "errorObject": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true + }, + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/errorLinks" + } + ], + "nullable": true + }, + "status": { + "type": "string" + }, + "code": { + "type": "string", + "nullable": true + }, + "title": { + "type": "string", + "nullable": true + }, + "detail": { + "type": "string", + "nullable": true + }, + "source": { + "allOf": [ + { + "$ref": "#/components/schemas/errorSource" + } + ], + "nullable": true + }, + "meta": { + "allOf": [ + { + "$ref": "#/components/schemas/meta" + } + ] + } + }, + "additionalProperties": false + }, + "errorResponseDocument": { + "required": [ + "errors", + "links" + ], + "type": "object", + "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/errorTopLevelLinks" + } + ] + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/errorObject" + } + }, + "meta": { + "allOf": [ + { + "$ref": "#/components/schemas/meta" + } + ] + } + }, + "additionalProperties": false + }, + "errorSource": { + "type": "object", + "properties": { + "pointer": { + "type": "string", + "nullable": true + }, + "parameter": { + "type": "string", + "nullable": true + }, + "header": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "errorTopLevelLinks": { + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "describedby": { + "type": "string" + } + }, + "additionalProperties": false + }, + "meta": { + "type": "object", + "additionalProperties": { + "nullable": true + } + }, + "primaryTypeContainerResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/resourceTopLevelLinks" + } + ] + }, + "data": { + "allOf": [ + { + "$ref": "#/components/schemas/dataInTypeContainerResponse" + } + ] + }, + "included": { + "type": "array", + "items": { + "$ref": "#/components/schemas/resourceInResponse" + } + }, + "meta": { + "allOf": [ + { + "$ref": "#/components/schemas/meta" + } + ] + } + }, + "additionalProperties": false + }, + "resourceCollectionTopLevelLinks": { + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "describedby": { + "type": "string" + }, + "first": { + "type": "string" + }, + "last": { + "type": "string" + }, + "prev": { + "type": "string" + }, + "next": { + "type": "string" + } + }, + "additionalProperties": false + }, + "resourceInCreateRequest": { + "required": [ + "type" + ], + "type": "object", + "properties": { + "type": { + "allOf": [ + { + "$ref": "#/components/schemas/resourceType" + } + ] + }, + "meta": { + "allOf": [ + { + "$ref": "#/components/schemas/meta" + } + ] + } + }, + "additionalProperties": false, + "discriminator": { + "propertyName": "type", + "mapping": { + "typeContainers": "#/components/schemas/dataInCreateTypeContainerRequest" + } + }, + "x-abstract": true + }, + "resourceInResponse": { + "required": [ + "type" + ], + "type": "object", + "properties": { + "type": { + "allOf": [ + { + "$ref": "#/components/schemas/resourceType" + } + ] + }, + "meta": { + "allOf": [ + { + "$ref": "#/components/schemas/meta" + } + ] + } + }, + "additionalProperties": false, + "discriminator": { + "propertyName": "type", + "mapping": { + "typeContainers": "#/components/schemas/dataInTypeContainerResponse" + } + }, + "x-abstract": true + }, + "resourceInUpdateRequest": { + "required": [ + "type" + ], + "type": "object", + "properties": { + "type": { + "allOf": [ + { + "$ref": "#/components/schemas/resourceType" + } + ] + }, + "meta": { + "allOf": [ + { + "$ref": "#/components/schemas/meta" + } + ] + } + }, + "additionalProperties": false, + "discriminator": { + "propertyName": "type", + "mapping": { + "typeContainers": "#/components/schemas/dataInUpdateTypeContainerRequest" + } + }, + "x-abstract": true + }, + "resourceLinks": { + "type": "object", + "properties": { + "self": { + "type": "string" + } + }, + "additionalProperties": false + }, + "resourceTopLevelLinks": { + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "describedby": { + "type": "string" + } + }, + "additionalProperties": false + }, + "resourceType": { + "enum": [ + "typeContainers" + ], + "type": "string" + }, + "typeContainerCollectionResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "links": { + "allOf": [ + { + "$ref": "#/components/schemas/resourceCollectionTopLevelLinks" + } + ] + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/dataInTypeContainerResponse" + } + }, + "included": { + "type": "array", + "items": { + "$ref": "#/components/schemas/resourceInResponse" + } + }, + "meta": { + "allOf": [ + { + "$ref": "#/components/schemas/meta" + } + ] + } + }, + "additionalProperties": false + }, + "updateTypeContainerRequestDocument": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "allOf": [ + { + "$ref": "#/components/schemas/dataInUpdateTypeContainerRequest" + } + ] + }, + "meta": { + "allOf": [ + { + "$ref": "#/components/schemas/meta" + } + ] + } + }, + "additionalProperties": false + } + } + } +} \ No newline at end of file diff --git a/test/OpenApiTests/AttributeTypes/TypeAwareFilterParser.cs b/test/OpenApiTests/AttributeTypes/TypeAwareFilterParser.cs new file mode 100644 index 0000000000..95bed44c82 --- /dev/null +++ b/test/OpenApiTests/AttributeTypes/TypeAwareFilterParser.cs @@ -0,0 +1,78 @@ +using System.Net; +using System.Numerics; +using System.Text; +using JsonApiDotNetCore.Queries.Parsing; +using JsonApiDotNetCore.Resources; + +namespace OpenApiTests.AttributeTypes; + +public sealed class TypeAwareFilterParser(IResourceFactory resourceFactory) + : FilterParser(resourceFactory) +{ + protected override ConstantValueConverter GetConstantValueConverterForType(Type destinationType) + { + if (destinationType == typeof(Int128) || destinationType == typeof(Int128?)) + { + return CreateConverter(destinationType, TypeConverterRegistry.Int128FromString); + } + + if (destinationType == typeof(UInt128) || destinationType == typeof(UInt128?)) + { + return CreateConverter(destinationType, TypeConverterRegistry.UInt128FromString); + } + + if (destinationType == typeof(BigInteger) || destinationType == typeof(BigInteger?)) + { + return CreateConverter(destinationType, TypeConverterRegistry.BigIntegerFromString); + } + + if (destinationType == typeof(Half) || destinationType == typeof(Half?)) + { + return CreateConverter(destinationType, TypeConverterRegistry.HalfFromString); + } + + if (destinationType == typeof(Complex) || destinationType == typeof(Complex?)) + { + return CreateConverter(destinationType, TypeConverterRegistry.ComplexFromString); + } + + if (destinationType == typeof(Rune) || destinationType == typeof(Rune?)) + { + return CreateConverter(destinationType, TypeConverterRegistry.RuneFromString); + } + + if (destinationType == typeof(IPAddress)) + { + return CreateConverter(destinationType, TypeConverterRegistry.IPAddressFromString); + } + + if (destinationType == typeof(IPNetwork) || destinationType == typeof(IPNetwork?)) + { + return CreateConverter(destinationType, TypeConverterRegistry.IPNetworkFromString); + } + + if (destinationType == typeof(Version)) + { + return CreateConverter(destinationType, TypeConverterRegistry.VersionFromString); + } + + return base.GetConstantValueConverterForType(destinationType); + } + + private static ConstantValueConverter CreateConverter(Type destinationType, Func converter) + where T : notnull + { + return (stringValue, position) => + { + try + { + return converter(stringValue); + } + catch (Exception exception) when (exception is FormatException or OverflowException or InvalidCastException or ArgumentException) + { + string destinationTypeName = RuntimeTypeConverter.GetFriendlyTypeName(destinationType); + throw new QueryParseException($"Failed to convert '{stringValue}' of type 'String' to type '{destinationTypeName}'.", position, exception); + } + }; + } +} diff --git a/test/OpenApiTests/AttributeTypes/TypeContainer.cs b/test/OpenApiTests/AttributeTypes/TypeContainer.cs new file mode 100644 index 0000000000..6e18f8fc60 --- /dev/null +++ b/test/OpenApiTests/AttributeTypes/TypeContainer.cs @@ -0,0 +1,211 @@ +using System.Net; +using System.Numerics; +using System.Text; +using JetBrains.Annotations; +using JsonApiDotNetCore.Resources; +using JsonApiDotNetCore.Resources.Annotations; + +namespace OpenApiTests.AttributeTypes; + +[UsedImplicitly(ImplicitUseTargetFlags.Members)] +[Resource(ControllerNamespace = "OpenApiTests.AttributeTypes")] +public sealed class TypeContainer : Identifiable +{ + // Integral numeric types + + [Attr] + public bool TestBoolean { get; set; } + + [Attr] + public bool? TestNullableBoolean { get; set; } + + [Attr] + public byte TestByte { get; set; } + + [Attr] + public byte? TestNullableByte { get; set; } + + [Attr] + public sbyte TestSignedByte { get; set; } + + [Attr] + public sbyte? TestNullableSignedByte { get; set; } + + [Attr] + public short TestInt16 { get; set; } + + [Attr] + public short? TestNullableInt16 { get; set; } + + [Attr] + public ushort TestUnsignedInt16 { get; set; } + + [Attr] + public ushort? TestNullableUnsignedInt16 { get; set; } + + [Attr] + public int TestInt32 { get; set; } + + [Attr] + public int? TestNullableInt32 { get; set; } + + [Attr] + public uint TestUnsignedInt32 { get; set; } + + [Attr] + public uint? TestNullableUnsignedInt32 { get; set; } + + [Attr] + public long TestInt64 { get; set; } + + [Attr] + public long? TestNullableInt64 { get; set; } + + [Attr] + public ulong TestUnsignedInt64 { get; set; } + + [Attr] + public ulong? TestNullableUnsignedInt64 { get; set; } + + [Attr] + public Int128 TestInt128 { get; set; } + + [Attr] + public Int128? TestNullableInt128 { get; set; } + + [Attr] + public UInt128 TestUnsignedInt128 { get; set; } + + [Attr] + public UInt128? TestNullableUnsignedInt128 { get; set; } + + [Attr] + public BigInteger TestBigInteger { get; set; } + + [Attr] + public BigInteger? TestNullableBigInteger { get; set; } + + // Floating-point numeric types + + [Attr] + public Half TestHalf { get; set; } + + [Attr] + public Half? TestNullableHalf { get; set; } + + [Attr] + public float TestFloat { get; set; } + + [Attr] + public float? TestNullableFloat { get; set; } + + [Attr] + public double TestDouble { get; set; } + + [Attr] + public double? TestNullableDouble { get; set; } + + [Attr] + public decimal TestDecimal { get; set; } + + [Attr] + public decimal? TestNullableDecimal { get; set; } + + // Other numeric types + + [Attr] + public Complex TestComplex { get; set; } + + [Attr] + public Complex? TestNullableComplex { get; set; } + + // Text types + + [Attr] + public char TestChar { get; set; } + + [Attr] + public char? TestNullableChar { get; set; } + + [Attr] + public required string TestString { get; set; } + + [Attr] + public string? TestNullableString { get; set; } + + [Attr] + public Rune TestRune { get; set; } + + [Attr] + public Rune? TestNullableRune { get; set; } + + // Temporal types + + [Attr] + public DateTimeOffset TestDateTimeOffset { get; set; } + + [Attr] + public DateTimeOffset? TestNullableDateTimeOffset { get; set; } + + [Attr] + public DateTime TestDateTime { get; set; } + + [Attr] + public DateTime? TestNullableDateTime { get; set; } + + [Attr] + public DateOnly TestDateOnly { get; set; } + + [Attr] + public DateOnly? TestNullableDateOnly { get; set; } + + [Attr] + public TimeOnly TestTimeOnly { get; set; } + + [Attr] + public TimeOnly? TestNullableTimeOnly { get; set; } + + [Attr] + public TimeSpan TestTimeSpan { get; set; } + + [Attr] + public TimeSpan? TestNullableTimeSpan { get; set; } + + // Various other types + + [Attr] + public DayOfWeek TestEnum { get; set; } + + [Attr] + public DayOfWeek? TestNullableEnum { get; set; } + + [Attr] + public Guid TestGuid { get; set; } + + [Attr] + public Guid? TestNullableGuid { get; set; } + + [Attr] + public required Uri TestUri { get; set; } + + [Attr] + public Uri? TestNullableUri { get; set; } + + [Attr] + public required IPAddress TestIPAddress { get; set; } + + [Attr] + public IPAddress? TestNullableIPAddress { get; set; } + + [Attr] + public IPNetwork TestIPNetwork { get; set; } + + [Attr] + public IPNetwork? TestNullableIPNetwork { get; set; } + + [Attr] + public required Version TestVersion { get; set; } + + [Attr] + public Version? TestNullableVersion { get; set; } +} diff --git a/test/OpenApiTests/AttributeTypes/TypeConverterRegistry.cs b/test/OpenApiTests/AttributeTypes/TypeConverterRegistry.cs new file mode 100644 index 0000000000..530b0033ed --- /dev/null +++ b/test/OpenApiTests/AttributeTypes/TypeConverterRegistry.cs @@ -0,0 +1,89 @@ +using System.Globalization; +using System.Net; +using System.Numerics; +using System.Text; +using TestBuildingBlocks; + +namespace OpenApiTests.AttributeTypes; + +public sealed class TypeConverterRegistry +{ + internal static Func Int128ToString { get; } = value => value.ToString(CultureInfo.InvariantCulture); + internal static Func Int128FromString { get; } = value => Int128.Parse(value, CultureInfo.InvariantCulture); + + internal static Func UInt128ToString { get; } = value => value.ToString(CultureInfo.InvariantCulture); + internal static Func UInt128FromString { get; } = value => UInt128.Parse(value, CultureInfo.InvariantCulture); + + internal static Func BigIntegerToString { get; } = value => value.ToString(CultureInfo.InvariantCulture); + internal static Func BigIntegerFromString { get; } = value => BigInteger.Parse(value, CultureInfo.InvariantCulture); + + internal static Func HalfToFloat { get; } = value => value.AsFloat(); + internal static Func HalfFromFloat { get; } = Half.CreateChecked; + internal static Func HalfFromString { get; } = value => Half.Parse(value, CultureInfo.InvariantCulture); + + internal static Func ComplexToString { get; } = value => value.ToString(CultureInfo.InvariantCulture); + internal static Func ComplexFromString { get; } = value => Complex.Parse(value, CultureInfo.InvariantCulture); + + internal static Func RuneToString { get; } = value => value.ToString(); + internal static Func RuneFromString { get; } = value => Rune.GetRuneAt(value, 0); + + internal static Func IPAddressToString { get; } = value => value.ToString(); + internal static Func IPAddressFromString { get; } = IPAddress.Parse; + + internal static Func IPNetworkToString { get; } = ipNetwork => ipNetwork.ToString(); + internal static Func IPNetworkFromString { get; } = IPNetwork.Parse; + + internal static Func VersionToString { get; } = value => value.ToString(); + internal static Func VersionFromString { get; } = Version.Parse; + + public static TypeConverterRegistry Instance { get; } = new(); + + private TypeConverterRegistry() + { + } + + public Func? FindToStringConverter(Type type) + { + if (type == typeof(Int128) || type == typeof(Int128?)) + { + return typedValue => Int128ToString((Int128)typedValue); + } + + if (type == typeof(UInt128) || type == typeof(UInt128?)) + { + return typedValue => UInt128ToString((UInt128)typedValue); + } + + if (type == typeof(BigInteger) || type == typeof(BigInteger?)) + { + return typedValue => BigIntegerToString((BigInteger)typedValue); + } + + if (type == typeof(Complex) || type == typeof(Complex?)) + { + return typedValue => ComplexToString((Complex)typedValue); + } + + if (type == typeof(Rune) || type == typeof(Rune?)) + { + return typedValue => RuneToString((Rune)typedValue); + } + + if (type == typeof(IPAddress)) + { + return typedValue => IPAddressToString((IPAddress)typedValue); + } + + if (type == typeof(IPNetwork) || type == typeof(IPNetwork?)) + { + return typedValue => IPNetworkToString((IPNetwork)typedValue); + } + + if (type == typeof(Version)) + { + return typedValue => VersionToString((Version)typedValue); + } + + return null; + } +} diff --git a/test/OpenApiTests/ModelStateValidation/ModelStateValidationFakers.cs b/test/OpenApiTests/ModelStateValidation/ModelStateValidationFakers.cs index 1fdc2203da..0030ed0eed 100644 --- a/test/OpenApiTests/ModelStateValidation/ModelStateValidationFakers.cs +++ b/test/OpenApiTests/ModelStateValidation/ModelStateValidationFakers.cs @@ -37,8 +37,8 @@ public sealed class ModelStateValidationFakers .RuleFor(socialMediaAccount => socialMediaAccount.Planet, faker => faker.Random.Word()) .RuleFor(socialMediaAccount => socialMediaAccount.NextRevalidation, faker => TimeSpan.FromHours(faker.Random.Number(1, 5))) .RuleFor(socialMediaAccount => socialMediaAccount.ValidatedAt, faker => faker.Date.Recent().ToUniversalTime().TruncateToWholeMilliseconds()) - .RuleFor(socialMediaAccount => socialMediaAccount.ValidatedAtDate, faker => DateOnly.FromDateTime(faker.Date.Recent())) - .RuleFor(socialMediaAccount => socialMediaAccount.ValidatedAtTime, faker => TimeOnly.FromDateTime(faker.Date.Recent().TruncateToWholeMilliseconds()))); + .RuleFor(socialMediaAccount => socialMediaAccount.ValidatedAtDate, faker => faker.Date.RecentDateOnly()) + .RuleFor(socialMediaAccount => socialMediaAccount.ValidatedAtTime, faker => faker.Date.RecentTimeOnly())); public Faker SocialMediaAccount => _lazySocialMediaAccountFaker.Value; } diff --git a/test/OpenApiTests/ModelStateValidation/ModelStateValidationTests.cs b/test/OpenApiTests/ModelStateValidation/ModelStateValidationTests.cs index 3040cb6a26..a4f02bc492 100644 --- a/test/OpenApiTests/ModelStateValidation/ModelStateValidationTests.cs +++ b/test/OpenApiTests/ModelStateValidation/ModelStateValidationTests.cs @@ -7,13 +7,12 @@ namespace OpenApiTests.ModelStateValidation; public sealed class ModelStateValidationTests : IClassFixture, ModelStateValidationDbContext>> { - // ReSharper disable once UseCollectionExpression (https://youtrack.jetbrains.com/issue/RSRP-497450) - public static readonly TheoryData SchemaNames = new() - { + public static readonly TheoryData SchemaNames = + [ "attributesInCreateSocialMediaAccountRequest", "attributesInUpdateSocialMediaAccountRequest", "attributesInSocialMediaAccountResponse" - }; + ]; private readonly OpenApiTestContext, ModelStateValidationDbContext> _testContext; diff --git a/test/OpenApiTests/ReferenceTypeJsonConverter.cs b/test/OpenApiTests/ReferenceTypeJsonConverter.cs new file mode 100644 index 0000000000..71201c37e2 --- /dev/null +++ b/test/OpenApiTests/ReferenceTypeJsonConverter.cs @@ -0,0 +1,44 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace OpenApiTests; + +internal abstract class ReferenceTypeJsonConverter(Func fromStringConverter, Func toStringConverter) : JsonConverter + where T : class +{ + public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + + if (reader.TokenType == JsonTokenType.String) + { + try + { + string stringValue = reader.GetString()!; + return fromStringConverter(stringValue); + } + catch (Exception exception) when (exception is FormatException or OverflowException or InvalidCastException or ArgumentException) + { + throw new JsonException("Failed to parse attribute value.", exception); + } + } + + throw new JsonException($"Expected JSON token type '{JsonTokenType.String}' or '{JsonTokenType.Null}', but found '{reader.TokenType}'."); + } + + public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) + { + try + { + string stringValue = toStringConverter(value); + writer.WriteStringValue(stringValue); + } + catch (Exception exception) when (exception is FormatException or OverflowException or InvalidCastException or ArgumentException) + { + throw new JsonException("Failed to format attribute value.", exception); + } + } +} diff --git a/test/OpenApiTests/UtcDateTimeJsonConverter.cs b/test/OpenApiTests/UtcDateTimeJsonConverter.cs new file mode 100644 index 0000000000..5afe7fffd5 --- /dev/null +++ b/test/OpenApiTests/UtcDateTimeJsonConverter.cs @@ -0,0 +1,5 @@ +namespace OpenApiTests; + +// Used by client libraries only, to enforce that sent DateTime values are always in UTC. +public sealed class UtcDateTimeJsonConverter() + : ValueTypeJsonConverter(value => DateTimeOffset.Parse(value).UtcDateTime, value => value.ToUniversalTime().ToString("O")); diff --git a/test/OpenApiTests/ValueTypeJsonConverter.cs b/test/OpenApiTests/ValueTypeJsonConverter.cs new file mode 100644 index 0000000000..8c0bcd63f8 --- /dev/null +++ b/test/OpenApiTests/ValueTypeJsonConverter.cs @@ -0,0 +1,39 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace OpenApiTests; + +public abstract class ValueTypeJsonConverter(Func fromStringConverter, Func toStringConverter) : JsonConverter + where T : struct +{ + public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.String) + { + try + { + string stringValue = reader.GetString()!; + return fromStringConverter(stringValue); + } + catch (Exception exception) when (exception is FormatException or OverflowException or InvalidCastException or ArgumentException) + { + throw new JsonException("Failed to parse attribute value.", exception); + } + } + + throw new JsonException($"Expected JSON token type '{JsonTokenType.String}', but found '{reader.TokenType}'."); + } + + public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) + { + try + { + string stringValue = toStringConverter(value); + writer.WriteStringValue(stringValue); + } + catch (Exception exception) when (exception is FormatException or OverflowException or InvalidCastException or ArgumentException) + { + throw new JsonException("Failed to format attribute value.", exception); + } + } +} diff --git a/test/TestBuildingBlocks/DateTimeExtensions.cs b/test/TestBuildingBlocks/DateTimeExtensions.cs deleted file mode 100644 index bf7e1325ce..0000000000 --- a/test/TestBuildingBlocks/DateTimeExtensions.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace TestBuildingBlocks; - -public static class DateTimeExtensions -{ - // The milliseconds precision in DateTime/DateTimeOffset values that fakers produce is higher - // than what PostgreSQL can store. This results in our resource change tracker to detect - // that the time stored in the database differs from the time in the request body. While that's - // technically correct, we don't want such side effects influencing our tests everywhere. - - public static DateTimeOffset TruncateToWholeMilliseconds(this DateTimeOffset value) - { - // Because PostgreSQL does not store the UTC offset in the database, it cannot round-trip - // values with a non-zero UTC offset, and therefore always rejects such values. - - DateTime dateTime = TruncateToWholeMilliseconds(value.DateTime); - return new DateTimeOffset(dateTime, TimeSpan.Zero); - } - - public static DateTime TruncateToWholeMilliseconds(this DateTime value) - { - long ticksToSubtract = value.Ticks % TimeSpan.TicksPerMillisecond; - long ticksInWholeMilliseconds = value.Ticks - ticksToSubtract; - - return new DateTime(ticksInWholeMilliseconds, value.Kind); - } -} diff --git a/test/TestBuildingBlocks/HalfExtensions.cs b/test/TestBuildingBlocks/HalfExtensions.cs new file mode 100644 index 0000000000..a00cb7aad8 --- /dev/null +++ b/test/TestBuildingBlocks/HalfExtensions.cs @@ -0,0 +1,12 @@ +using System.Globalization; + +namespace TestBuildingBlocks; + +public static class HalfExtensions +{ + public static float AsFloat(this Half half) + { + // Caution: Simply casting to float returns a higher precision (more digits). + return float.Parse(half.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture); + } +} diff --git a/test/TestBuildingBlocks/TimeExtensions.cs b/test/TestBuildingBlocks/TimeExtensions.cs new file mode 100644 index 0000000000..9392aa2d41 --- /dev/null +++ b/test/TestBuildingBlocks/TimeExtensions.cs @@ -0,0 +1,54 @@ +namespace TestBuildingBlocks; + +public static class TimeExtensions +{ + // The milliseconds precision in DateTime/DateTimeOffset/TimeSpan/TimeOnly values that fakers produce + // is higher than what PostgreSQL can store. This results in our resource change tracker to detect + // that the time stored in the database differs from the time in the request body. While that's + // technically correct, we don't want such side effects influencing our tests everywhere. + + public static DateTimeOffset TruncateToWholeMilliseconds(this DateTimeOffset value) + { + // Because PostgreSQL does not store the UTC offset in the database, it cannot round-trip + // values with a non-zero UTC offset, and therefore always rejects such values. + + DateTime dateTime = TruncateToWholeMilliseconds(value.DateTime); + return new DateTimeOffset(dateTime, TimeSpan.Zero); + } + + public static DateTime TruncateToWholeMilliseconds(this DateTime value) + { + long ticksInWholeMilliseconds = TruncateTicksInWholeMilliseconds(value.Ticks); + return new DateTime(ticksInWholeMilliseconds, value.Kind); + } + + private static long TruncateTicksInWholeMilliseconds(long ticks) + { + long ticksToSubtract = ticks % TimeSpan.TicksPerMillisecond; + return ticks - ticksToSubtract; + } + + public static TimeSpan TruncateToWholeMilliseconds(this TimeSpan value) + { + long ticksInWholeMilliseconds = TruncateTicksInWholeMilliseconds(value.Ticks); + return new TimeSpan(ticksInWholeMilliseconds); + } + + public static TimeOnly TruncateToWholeMilliseconds(this TimeOnly value) + { + long ticksInWholeMilliseconds = TruncateTicksInWholeMilliseconds(value.Ticks); + return new TimeOnly(ticksInWholeMilliseconds); + } + + public static TimeOnly TruncateToWholeSeconds(this TimeOnly value) + { + long ticksInWholeSeconds = TruncateTicksInWholeSeconds(value.Ticks); + return new TimeOnly(ticksInWholeSeconds); + } + + private static long TruncateTicksInWholeSeconds(long ticks) + { + long ticksToSubtract = ticks % TimeSpan.TicksPerSecond; + return ticks - ticksToSubtract; + } +}