diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs index c747e93db7b..a21f31ffba6 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs @@ -2384,7 +2384,9 @@ var t when ValueTypeIsNumber(t) => var t when t == typeof(string) || t == typeof(char) || t == typeof(Guid) => utf8JsonWriter.WriteStringValue(value), var t when t == typeof(bool) => - utf8JsonWriter.WriteBooleanValue(value), + serializationFormat == SerializationFormat.Boolean_String + ? utf8JsonWriter.WriteStringValue(new TernaryConditionalExpression(value, Literal("true"), Literal("false"))) + : utf8JsonWriter.WriteBooleanValue(value), var t when t == typeof(byte[]) => utf8JsonWriter.WriteBase64StringValue(value, serializationFormat.ToFormatSpecifier()), var t when t == typeof(DateTimeOffset) || t == typeof(DateTime) || t == typeof(TimeSpan) => @@ -2470,7 +2472,9 @@ format is SerializationFormat.Bytes_Base64 or SerializationFormat.Bytes_Base64Ur Type t when t == typeof(object) => element.GetObject(), Type t when t == typeof(bool) => - element.GetBoolean(), + format == SerializationFormat.Boolean_String + ? Static().Invoke(nameof(bool.Parse), element.GetString()) + : element.GetBoolean(), Type t when t == typeof(char) => element.GetChar(), Type t when ValueTypeIsInt(t) => diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/MrwSerializationTypeDefinitionTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/MrwSerializationTypeDefinitionTests.cs index 32ade7fd931..07d552ce406 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/MrwSerializationTypeDefinitionTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/MrwSerializationTypeDefinitionTests.cs @@ -909,6 +909,40 @@ public void TestIntSerializationStatement( Assert.IsTrue(HasMethodBodyStatement(serialization.BuildJsonModelWriteCoreMethod().BodyStatements, encode is null ? "writer.WriteNumberValue(RequiredInt);\n" : "writer.WriteStringValue(RequiredInt.ToString());\n")); } + [TestCase("string")] + [TestCase(null)] + public void TestBooleanSerialization(string? encode) + { + MockHelpers.LoadMockGenerator(); + var input = new InputPrimitiveType(InputPrimitiveTypeKind.Boolean, "boolean", "TypeSpec.boolean", encode); + var format = ScmCodeModelGenerator.Instance.TypeFactory.GetSerializationFormat(input); + var statement = MrwSerializationTypeDefinition.SerializeJsonValueCore( + typeof(bool), + new VariableExpression(typeof(bool), "value"), + new ScopedApi(new VariableExpression(typeof(Utf8JsonWriter), "writer")), + new ScopedApi(new VariableExpression(typeof(ModelReaderWriterOptions), "options")), + format); + + Assert.AreEqual(Helpers.GetExpectedFromFile(encode ?? "default"), statement.ToDisplayString()); + } + + [TestCase("string")] + [TestCase(null)] + public void TestBooleanDeserialization(string? encode) + { + MockHelpers.LoadMockGenerator(); + var input = new InputPrimitiveType(InputPrimitiveTypeKind.Boolean, "boolean", "TypeSpec.boolean", encode); + var format = ScmCodeModelGenerator.Instance.TypeFactory.GetSerializationFormat(input); + var expression = MrwSerializationTypeDefinition.DeserializeJsonValueCore( + typeof(bool), + new ScopedApi(new VariableExpression(typeof(JsonElement), "foo")), + new ScopedApi(new VariableExpression(typeof(BinaryData), "data")), + new ScopedApi(new VariableExpression(typeof(ModelReaderWriterOptions), "options")), + format); + + Assert.AreEqual(Helpers.GetExpectedFromFile(encode ?? "default").TrimEnd(), expression.ToDisplayString()); + } + [TestCase(typeof(long), SerializationFormat.Int_String, ExpectedResult = "long.Parse(foo.GetString())")] [TestCase(typeof(int), SerializationFormat.Int_String, ExpectedResult = "int.Parse(foo.GetString())")] [TestCase(typeof(short), SerializationFormat.Int_String, ExpectedResult = "short.Parse(foo.GetString())")] diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/MrwSerializationTypeDefinitionTests/TestBooleanDeserialization(default).cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/MrwSerializationTypeDefinitionTests/TestBooleanDeserialization(default).cs new file mode 100644 index 00000000000..164e8c65dac --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/MrwSerializationTypeDefinitionTests/TestBooleanDeserialization(default).cs @@ -0,0 +1 @@ +foo.GetBoolean() diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/MrwSerializationTypeDefinitionTests/TestBooleanDeserialization(string).cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/MrwSerializationTypeDefinitionTests/TestBooleanDeserialization(string).cs new file mode 100644 index 00000000000..fbd3b91030f --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/MrwSerializationTypeDefinitionTests/TestBooleanDeserialization(string).cs @@ -0,0 +1 @@ +bool.Parse(foo.GetString()) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/MrwSerializationTypeDefinitionTests/TestBooleanSerialization(default).cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/MrwSerializationTypeDefinitionTests/TestBooleanSerialization(default).cs new file mode 100644 index 00000000000..d0c406dfbaf --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/MrwSerializationTypeDefinitionTests/TestBooleanSerialization(default).cs @@ -0,0 +1 @@ +writer.WriteBooleanValue(value); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/MrwSerializationTypeDefinitionTests/TestBooleanSerialization(string).cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/MrwSerializationTypeDefinitionTests/TestBooleanSerialization(string).cs new file mode 100644 index 00000000000..2f8e20e874e --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/MrwSerializationTypeDefinitionTests/TestBooleanSerialization(string).cs @@ -0,0 +1 @@ +writer.WriteStringValue(value ? "true" : "false"); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/SerializationFormat.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/SerializationFormat.cs index a467eea4c47..2520ed0f6de 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/SerializationFormat.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.Input/src/InputTypes/Serialization/SerializationFormat.cs @@ -34,5 +34,6 @@ public enum SerializationFormat Array_NewlineDelimited, Duration_Seconds_Int64, Duration_Milliseconds_Int64, + Boolean_String, } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs index 79bfbb5d3d9..17dcbd3808f 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/TypeFactory.cs @@ -485,6 +485,7 @@ InputPrimitiveTypeKind.Integer or InputPrimitiveTypeKind.Int64 or InputPrimitive InputPrimitiveTypeKind.Integer or InputPrimitiveTypeKind.Int8 or InputPrimitiveTypeKind.Int16 or InputPrimitiveTypeKind.Int32 or InputPrimitiveTypeKind.Int64 or InputPrimitiveTypeKind.UInt8 or InputPrimitiveTypeKind.UInt16 or InputPrimitiveTypeKind.UInt32 or InputPrimitiveTypeKind.UInt64 or InputPrimitiveTypeKind.SafeInt when primitiveType.Encode is "string" => SerializationFormat.Int_String, + InputPrimitiveTypeKind.Boolean when primitiveType.Encode is "string" => SerializationFormat.Boolean_String, _ => SerializationFormat.Default }, _ => SerializationFormat.Default diff --git a/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/Encode/Boolean/EncodeBooleanTests.cs b/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/Encode/Boolean/EncodeBooleanTests.cs new file mode 100644 index 00000000000..f818d4ade10 --- /dev/null +++ b/packages/http-client-csharp/generator/TestProjects/Spector.Tests/Http/Encode/Boolean/EncodeBooleanTests.cs @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.ClientModel.Primitives; +using System.Threading.Tasks; +using Encode.Boolean; +using Encode.Boolean._Property; +using NUnit.Framework; + +namespace TestProjects.Spector.Tests.Http.Encode.Boolean +{ + public class EncodeBooleanTests : SpectorTestBase + { + [SpectorTest] + public Task Encode_Boolean_Property_trueLower() => Test(async (host) => + { + var response = await new BooleanClient(host, null).GetPropertyClient().TrueLowerAsync(new BoolAsStringProperty(true)); + Assert.AreEqual(200, response.GetRawResponse().Status); + Assert.IsTrue(response.Value.Value); + }); + + [SpectorTest] + public Task Encode_Boolean_Property_falseLower() => Test(async (host) => + { + var response = await new BooleanClient(host, null).GetPropertyClient().FalseLowerAsync(new BoolAsStringProperty(false)); + Assert.AreEqual(200, response.GetRawResponse().Status); + Assert.IsFalse(response.Value.Value); + }); + + [SpectorTest] + public Task Encode_Boolean_Property_trueUpper() => Test(async (host) => + { + var response = await new BooleanClient(host, null).GetPropertyClient().TrueUpperAsync(new BoolAsStringProperty(true)); + Assert.AreEqual(200, response.GetRawResponse().Status); + Assert.IsTrue(response.Value.Value); + }); + + [SpectorTest] + public Task Encode_Boolean_Property_falseMixed() => Test(async (host) => + { + var response = await new BooleanClient(host, null).GetPropertyClient().FalseMixedAsync(new BoolAsStringProperty(false)); + Assert.AreEqual(200, response.GetRawResponse().Status); + Assert.IsFalse(response.Value.Value); + }); + + [SpectorTest] + public void InvalidBooleanEncoding() + { + Assert.Throws(() => ModelReaderWriter.Read( + BinaryData.FromString("{\"value\":\"not-a-boolean\"}"))); + Assert.Throws(() => ModelReaderWriter.Read( + BinaryData.FromString("{\"value\":true}"))); + } + } +} diff --git a/packages/http-client-csharp/generator/TestProjects/Spector.Tests/TestProjects.Spector.Tests.csproj b/packages/http-client-csharp/generator/TestProjects/Spector.Tests/TestProjects.Spector.Tests.csproj index 3b3fc0d96b6..b3a872210c7 100644 --- a/packages/http-client-csharp/generator/TestProjects/Spector.Tests/TestProjects.Spector.Tests.csproj +++ b/packages/http-client-csharp/generator/TestProjects/Spector.Tests/TestProjects.Spector.Tests.csproj @@ -34,6 +34,7 @@ +