Skip to content

Commit

Permalink
Fix serialization of properties customized to be framework types (#4812)
Browse files Browse the repository at this point in the history
Fixes #4810
  • Loading branch information
JoshLove-msft authored Oct 21, 2024
1 parent b33fe85 commit 12a5605
Show file tree
Hide file tree
Showing 6 changed files with 374 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -174,5 +174,59 @@ public async Task CanCustomizeNullableStringToFixedEnum()
var file = writer.Write();
Assert.AreEqual(Helpers.GetExpectedFromFile(), file.Content);
}

[Test]
public async Task CanCustomizeEnumToFrameworkType()
{
await MockHelpers.LoadMockPluginAsync(compilation: async () => await Helpers.GetCompilationFromDirectoryAsync());

var props = new[] {
InputFactory.EnumMember.String("one", "val1"),
InputFactory.EnumMember.String("two", "val2"),
InputFactory.EnumMember.String("three", "val3")
};

var inputEnum = InputFactory.Enum("mockInputEnum", underlyingType: InputPrimitiveType.String, values: props, isExtensible: true);
var modelProp = InputFactory.Property("prop1", inputEnum);
var inputModel = InputFactory.Model("mockInputModel", properties: [modelProp], usage: InputModelTypeUsage.Json);

var plugin = await MockHelpers.LoadMockPluginAsync(
inputModels: () => [inputModel],
compilation: async () => await Helpers.GetCompilationFromDirectoryAsync());

var modelProvider = plugin.Object.OutputLibrary.TypeProviders.Single(t => t is ModelProvider);
var serializationProvider = modelProvider.SerializationProviders.Single(t => t is MrwSerializationTypeDefinition);
Assert.IsNotNull(serializationProvider);
var writer = new TypeProviderWriter(serializationProvider);
var file = writer.Write();
Assert.AreEqual(Helpers.GetExpectedFromFile(), file.Content);
}

[Test]
public async Task CanCustomizeEnumToFieldFrameworkType()
{
await MockHelpers.LoadMockPluginAsync(compilation: async () => await Helpers.GetCompilationFromDirectoryAsync());

var props = new[] {
InputFactory.EnumMember.String("one", "val1"),
InputFactory.EnumMember.String("two", "val2"),
InputFactory.EnumMember.String("three", "val3")
};

var inputEnum = InputFactory.Enum("mockInputEnum", underlyingType: InputPrimitiveType.String, values: props, isExtensible: true);
var modelProp = InputFactory.Property("prop1", inputEnum);
var inputModel = InputFactory.Model("mockInputModel", properties: [modelProp], usage: InputModelTypeUsage.Json);

var plugin = await MockHelpers.LoadMockPluginAsync(
inputModels: () => [inputModel],
compilation: async () => await Helpers.GetCompilationFromDirectoryAsync());

var modelProvider = plugin.Object.OutputLibrary.TypeProviders.Single(t => t is ModelProvider);
var serializationProvider = modelProvider.SerializationProviders.Single(t => t is MrwSerializationTypeDefinition);
Assert.IsNotNull(serializationProvider);
var writer = new TypeProviderWriter(serializationProvider);
var file = writer.Write();
Assert.AreEqual(Helpers.GetExpectedFromFile(), file.Content);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// <auto-generated/>

#nullable disable

using System;
using System.ClientModel;
using System.ClientModel.Primitives;
using System.Collections.Generic;
using System.Text.Json;
using Sample;

namespace Sample.Models
{
/// <summary></summary>
public partial class MockInputModel : global::System.ClientModel.Primitives.IJsonModel<global::Sample.Models.MockInputModel>
{
void global::System.ClientModel.Primitives.IJsonModel<global::Sample.Models.MockInputModel>.Write(global::System.Text.Json.Utf8JsonWriter writer, global::System.ClientModel.Primitives.ModelReaderWriterOptions options)
{
writer.WriteStartObject();
this.JsonModelWriteCore(writer, options);
writer.WriteEndObject();
}

/// <param name="writer"> The JSON writer. </param>
/// <param name="options"> The client options for reading and writing models. </param>
protected virtual void JsonModelWriteCore(global::System.Text.Json.Utf8JsonWriter writer, global::System.ClientModel.Primitives.ModelReaderWriterOptions options)
{
string format = (options.Format == "W") ? ((global::System.ClientModel.Primitives.IPersistableModel<global::Sample.Models.MockInputModel>)this).GetFormatFromOptions(options) : options.Format;
if ((format != "J"))
{
throw new global::System.FormatException($"The model {nameof(global::Sample.Models.MockInputModel)} does not support writing '{format}' format.");
}
if (global::Sample.Optional.IsDefined(_prop1))
{
writer.WritePropertyName("prop1"u8);
writer.WriteObjectValue<object>(_prop1, options);
}
if (((options.Format != "W") && (_additionalBinaryDataProperties != null)))
{
foreach (var item in _additionalBinaryDataProperties)
{
writer.WritePropertyName(item.Key);
#if NET6_0_OR_GREATER
writer.WriteRawValue(item.Value);
#else
using (global::System.Text.Json.JsonDocument document = global::System.Text.Json.JsonDocument.Parse(item.Value))
{
global::System.Text.Json.JsonSerializer.Serialize(writer, document.RootElement);
}
#endif
}
}
}

global::Sample.Models.MockInputModel global::System.ClientModel.Primitives.IJsonModel<global::Sample.Models.MockInputModel>.Create(ref global::System.Text.Json.Utf8JsonReader reader, global::System.ClientModel.Primitives.ModelReaderWriterOptions options) => ((global::Sample.Models.MockInputModel)this.JsonModelCreateCore(ref reader, options));

/// <param name="reader"> The JSON reader. </param>
/// <param name="options"> The client options for reading and writing models. </param>
protected virtual global::Sample.Models.MockInputModel JsonModelCreateCore(ref global::System.Text.Json.Utf8JsonReader reader, global::System.ClientModel.Primitives.ModelReaderWriterOptions options)
{
string format = (options.Format == "W") ? ((global::System.ClientModel.Primitives.IPersistableModel<global::Sample.Models.MockInputModel>)this).GetFormatFromOptions(options) : options.Format;
if ((format != "J"))
{
throw new global::System.FormatException($"The model {nameof(global::Sample.Models.MockInputModel)} does not support reading '{format}' format.");
}
using global::System.Text.Json.JsonDocument document = global::System.Text.Json.JsonDocument.ParseValue(ref reader);
return global::Sample.Models.MockInputModel.DeserializeMockInputModel(document.RootElement, options);
}

internal static global::Sample.Models.MockInputModel DeserializeMockInputModel(global::System.Text.Json.JsonElement element, global::System.ClientModel.Primitives.ModelReaderWriterOptions options)
{
if ((element.ValueKind == global::System.Text.Json.JsonValueKind.Null))
{
return null;
}
object prop1 = default;
global::System.Collections.Generic.IDictionary<string, global::System.BinaryData> additionalBinaryDataProperties = new global::Sample.ChangeTrackingDictionary<string, global::System.BinaryData>();
foreach (var prop in element.EnumerateObject())
{
if (prop.NameEquals("prop1"u8))
{
if ((prop.Value.ValueKind == global::System.Text.Json.JsonValueKind.Null))
{
prop1 = null;
continue;
}
prop1 = prop.Value.GetObject();
continue;
}
if ((options.Format != "W"))
{
additionalBinaryDataProperties.Add(prop.Name, global::System.BinaryData.FromString(prop.Value.GetRawText()));
}
}
return new global::Sample.Models.MockInputModel(prop1, additionalBinaryDataProperties);
}

global::System.BinaryData global::System.ClientModel.Primitives.IPersistableModel<global::Sample.Models.MockInputModel>.Write(global::System.ClientModel.Primitives.ModelReaderWriterOptions options) => this.PersistableModelWriteCore(options);

/// <param name="options"> The client options for reading and writing models. </param>
protected virtual global::System.BinaryData PersistableModelWriteCore(global::System.ClientModel.Primitives.ModelReaderWriterOptions options)
{
string format = (options.Format == "W") ? ((global::System.ClientModel.Primitives.IPersistableModel<global::Sample.Models.MockInputModel>)this).GetFormatFromOptions(options) : options.Format;
switch (format)
{
case "J":
return global::System.ClientModel.Primitives.ModelReaderWriter.Write(this, options);
default:
throw new global::System.FormatException($"The model {nameof(global::Sample.Models.MockInputModel)} does not support writing '{options.Format}' format.");
}
}

global::Sample.Models.MockInputModel global::System.ClientModel.Primitives.IPersistableModel<global::Sample.Models.MockInputModel>.Create(global::System.BinaryData data, global::System.ClientModel.Primitives.ModelReaderWriterOptions options) => ((global::Sample.Models.MockInputModel)this.PersistableModelCreateCore(data, options));

/// <param name="data"> The data to parse. </param>
/// <param name="options"> The client options for reading and writing models. </param>
protected virtual global::Sample.Models.MockInputModel PersistableModelCreateCore(global::System.BinaryData data, global::System.ClientModel.Primitives.ModelReaderWriterOptions options)
{
string format = (options.Format == "W") ? ((global::System.ClientModel.Primitives.IPersistableModel<global::Sample.Models.MockInputModel>)this).GetFormatFromOptions(options) : options.Format;
switch (format)
{
case "J":
using (global::System.Text.Json.JsonDocument document = global::System.Text.Json.JsonDocument.Parse(data))
{
return global::Sample.Models.MockInputModel.DeserializeMockInputModel(document.RootElement, options);
}
default:
throw new global::System.FormatException($"The model {nameof(global::Sample.Models.MockInputModel)} does not support reading '{options.Format}' format.");
}
}

string global::System.ClientModel.Primitives.IPersistableModel<global::Sample.Models.MockInputModel>.GetFormatFromOptions(global::System.ClientModel.Primitives.ModelReaderWriterOptions options) => "J";

/// <param name="mockInputModel"> The <see cref="global::Sample.Models.MockInputModel"/> to serialize into <see cref="global::System.ClientModel.BinaryContent"/>. </param>
public static implicit operator BinaryContent(global::Sample.Models.MockInputModel mockInputModel)
{
return global::System.ClientModel.BinaryContent.Create(mockInputModel, global::Sample.ModelSerializationExtensions.WireOptions);
}

/// <param name="result"> The <see cref="global::System.ClientModel.ClientResult"/> to deserialize the <see cref="global::Sample.Models.MockInputModel"/> from. </param>
public static explicit operator MockInputModel(global::System.ClientModel.ClientResult result)
{
using global::System.ClientModel.Primitives.PipelineResponse response = result.GetRawResponse();
using global::System.Text.Json.JsonDocument document = global::System.Text.Json.JsonDocument.Parse(response.Content);
return global::Sample.Models.MockInputModel.DeserializeMockInputModel(document.RootElement, global::Sample.ModelSerializationExtensions.WireOptions);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#nullable disable

using Microsoft.Generator.CSharp.Customization;

namespace Sample.Models
{
public partial class MockInputModel
{
[CodeGenMember("Prop1")]
private object _prop1;
}
}
Loading

0 comments on commit 12a5605

Please sign in to comment.