Skip to content

Commit

Permalink
Support customizing enum member name (#4485)
Browse files Browse the repository at this point in the history
This PR adds support for customizing enum member names, including in the
serialization code for an enum.

Fixes: #4372
  • Loading branch information
jorgerangel-msft authored Sep 23, 2024
1 parent 48099f0 commit d62adb1
Show file tree
Hide file tree
Showing 40 changed files with 278 additions and 90 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@

using System.Threading;

namespace sample.namespace
namespace Sample
{
/// <summary></summary>
public partial class TestClient
{
/// <summary> Initializes a new instance of Animal. </summary>
public virtual global::sample.namespace.Animal GetAnimalClient()
public virtual global::Sample.Animal GetAnimalClient()
{
return (global::System.Threading.Volatile.Read(ref _cachedAnimal) ?? (global::System.Threading.Interlocked.CompareExchange(ref _cachedAnimal, new global::sample.namespace.Animal(), null) ?? _cachedAnimal));
return (global::System.Threading.Volatile.Read(ref _cachedAnimal) ?? (global::System.Threading.Interlocked.CompareExchange(ref _cachedAnimal, new global::Sample.Animal(), null) ?? _cachedAnimal));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@

using System.Threading;

namespace sample.namespace
namespace Sample
{
/// <summary></summary>
public partial class Animal
{
/// <summary> Initializes a new instance of Dog. </summary>
public virtual global::sample.namespace.Dog GetDogClient()
public virtual global::Sample.Dog GetDogClient()
{
return (global::System.Threading.Volatile.Read(ref _cachedDog) ?? (global::System.Threading.Interlocked.CompareExchange(ref _cachedDog, new global::sample.namespace.Dog(), null) ?? _cachedDog));
return (global::System.Threading.Volatile.Read(ref _cachedDog) ?? (global::System.Threading.Interlocked.CompareExchange(ref _cachedDog, new global::Sample.Dog(), null) ?? _cachedDog));
}

/// <summary> Initializes a new instance of Cat. </summary>
public virtual global::sample.namespace.Cat GetCatClient()
public virtual global::Sample.Cat GetCatClient()
{
return (global::System.Threading.Volatile.Read(ref _cachedCat) ?? (global::System.Threading.Interlocked.CompareExchange(ref _cachedCat, new global::sample.namespace.Cat(), null) ?? _cachedCat));
return (global::System.Threading.Volatile.Read(ref _cachedCat) ?? (global::System.Threading.Interlocked.CompareExchange(ref _cachedCat, new global::Sample.Cat(), null) ?? _cachedCat));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@

using System.Threading;

namespace sample.namespace
namespace Sample
{
/// <summary></summary>
public partial class Dog
{
/// <summary> Initializes a new instance of Husky. </summary>
public virtual global::sample.namespace.Husky GetHuskyClient()
public virtual global::Sample.Husky GetHuskyClient()
{
return (global::System.Threading.Volatile.Read(ref _cachedHusky) ?? (global::System.Threading.Interlocked.CompareExchange(ref _cachedHusky, new global::sample.namespace.Husky(), null) ?? _cachedHusky));
return (global::System.Threading.Volatile.Read(ref _cachedHusky) ?? (global::System.Threading.Interlocked.CompareExchange(ref _cachedHusky, new global::Sample.Husky(), null) ?? _cachedHusky));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
#nullable disable

using System.ClientModel;
using sample.namespace.Models;
using Sample.Models;

namespace sample.namespace
namespace Sample
{
/// <summary></summary>
public partial class TestClient
{
public virtual global::System.ClientModel.ClientResult Operation(global::sample.namespace.Models.InputEnum queryParam)
public virtual global::System.ClientModel.ClientResult Operation(global::Sample.Models.InputEnum queryParam)
{
return this.Operation(queryParam.ToString(), null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using System.ClientModel;
using System.ClientModel.Primitives;

namespace sample.namespace
namespace Sample
{
/// <summary></summary>
public partial class TestClient
Expand All @@ -17,10 +17,10 @@ public partial class TestClient
message.ResponseClassifier = PipelineMessageClassifier200;
global::System.ClientModel.Primitives.PipelineRequest request = message.Request;
request.Method = "GET";
global::sample.namespace.ClientUriBuilder uri = new global::sample.namespace.ClientUriBuilder();
global::Sample.ClientUriBuilder uri = new global::Sample.ClientUriBuilder();
uri.Reset(_endpoint);
request.Uri = uri.ToUri();
request.Headers.Set("repeatability-first-sent", global::sample.namespace.TypeFormatters.ConvertToString(global::System.DateTimeOffset.Now, "R"));
request.Headers.Set("repeatability-first-sent", global::Sample.TypeFormatters.ConvertToString(global::System.DateTimeOffset.Now, "R"));
request.Headers.Set("repeatability-request-ID", global::System.Guid.NewGuid().ToString());
request.Content = content;
message.Apply(options);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
using Microsoft.Generator.CSharp.Tests.Common;
using NUnit.Framework;

namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers
namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.EnumProvider
{
public class EnumProviderSerializationTests
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Generator.CSharp.ClientModel.Providers;
using Microsoft.Generator.CSharp.Input;
using Microsoft.Generator.CSharp.Primitives;
using Microsoft.Generator.CSharp.Tests.Common;
using NUnit.Framework;

namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.EnumProvider
{
public class SerializationCustomizationTests
{
[Test]
public async Task CanChangeEnumMemberName()
{
var enumValues = new[]
{
InputFactory.EnumMember.Int32("Red", 1),
InputFactory.EnumMember.Int32("Green", 2),
InputFactory.EnumMember.Int32("Blue", 3)
};
var inputEnum = InputFactory.Enum("mockInputModel", underlyingType: InputPrimitiveType.String, values: enumValues);
var plugin = await MockHelpers.LoadMockPluginAsync(
inputEnums: () => [inputEnum],
compilation: async () => await Helpers.GetCompilationFromDirectoryAsync());

Assert.IsNull(plugin.Object.OutputLibrary.TypeProviders.SingleOrDefault(t => t.IsEnum));

var serializationProvider = plugin.Object.OutputLibrary.TypeProviders.Single(t => t is FixedEnumSerializationProvider);
Assert.IsNotNull(serializationProvider);
Assert.AreEqual(0, serializationProvider!.Fields.Count);

// validate the methods use the custom member name
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,36 @@
// <auto-generated/>

#nullable disable

using System;

namespace Sample.Models
{
internal static partial class MockInputModelExtensions
{
public static string ToSerialString(this global::Sample.Models.MockInputModel value) => value switch
{
global::Sample.Models.MockInputModel.Red => 1,
global::Sample.Models.MockInputModel.Green => 2,
global::Sample.Models.MockInputModel.SkyBlue => 3,
_ => throw new global::System.ArgumentOutOfRangeException(nameof(value), value, "Unknown MockInputModel value.")
};

public static global::Sample.Models.MockInputModel ToMockInputModel(this string value)
{
if (string.Equals(value, 1, global::System.StringComparison.InvariantCultureIgnoreCase))
{
return global::Sample.Models.MockInputModel.Red;
}
if (string.Equals(value, 2, global::System.StringComparison.InvariantCultureIgnoreCase))
{
return global::Sample.Models.MockInputModel.Green;
}
if (string.Equals(value, 3, global::System.StringComparison.InvariantCultureIgnoreCase))
{
return global::Sample.Models.MockInputModel.SkyBlue;
}
throw new global::System.ArgumentOutOfRangeException(nameof(value), value, "Unknown MockInputModel value.");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#nullable disable

using Microsoft.Generator.CSharp.Customization;

namespace Sample.Models
{
public enum MockInputModel
{
Red,
Green,
[CodeGenMember("Blue")]
SkyBlue
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ public void TestBuildDeserializationMethod(
{
// skip the first value type name as it is already included in the return statement
var additionalPropertiesVariables = "additionalProperties, " + string.Join(", ", expectedValueTypeNames.Skip(1).Select(v => $"additional{v.ToCleanName()}Properties,"));
var expectedReturnStatement = $"return new global::sample.namespace.Models.Cat(color, {additionalPropertiesVariables} additionalBinaryDataProperties);";
var expectedReturnStatement = $"return new global::Sample.Models.Cat(color, {additionalPropertiesVariables} additionalBinaryDataProperties);";
Assert.IsTrue(methodBodyString.Contains(expectedReturnStatement));
}
else
{
Assert.IsTrue(methodBodyString.Contains("return new global::sample.namespace.Models.Cat(color, additionalProperties, additionalBinaryDataProperties);"));
Assert.IsTrue(methodBodyString.Contains("return new global::Sample.Models.Cat(color, additionalProperties, additionalBinaryDataProperties);"));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@
using System.ClientModel.Primitives;
using System.Text.Json;

namespace sample.namespace.Models
namespace Sample.Models
{
/// <summary></summary>
public partial class TestModel : global::System.ClientModel.Primitives.IJsonModel<global::sample.namespace.Models.TestModel>
public partial class TestModel : global::System.ClientModel.Primitives.IJsonModel<global::Sample.Models.TestModel>
{
/// <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.namespace.Models.TestModel>)this).GetFormatFromOptions(options) : options.Format;
string format = (options.Format == "W") ? ((global::System.ClientModel.Primitives.IPersistableModel<global::Sample.Models.TestModel>)this).GetFormatFromOptions(options) : options.Format;
if ((format != "J"))
{
throw new global::System.FormatException($"The model {nameof(global::sample.namespace.Models.TestModel)} does not support writing '{format}' format.");
throw new global::System.FormatException($"The model {nameof(global::Sample.Models.TestModel)} does not support writing '{format}' format.");
}
writer.WritePropertyName("color"u8);
writer.WriteStringValue(Color);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@
using System.ClientModel.Primitives;
using System.Text.Json;

namespace sample.namespace.Models
namespace Sample.Models
{
/// <summary></summary>
public partial class TestModel : global::System.ClientModel.Primitives.IJsonModel<global::sample.namespace.Models.TestModel>
public partial class TestModel : global::System.ClientModel.Primitives.IJsonModel<global::Sample.Models.TestModel>
{
/// <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.namespace.Models.TestModel>)this).GetFormatFromOptions(options) : options.Format;
string format = (options.Format == "W") ? ((global::System.ClientModel.Primitives.IPersistableModel<global::Sample.Models.TestModel>)this).GetFormatFromOptions(options) : options.Format;
if ((format != "J"))
{
throw new global::System.FormatException($"The model {nameof(global::sample.namespace.Models.TestModel)} does not support writing '{format}' format.");
throw new global::System.FormatException($"The model {nameof(global::Sample.Models.TestModel)} does not support writing '{format}' format.");
}
writer.WritePropertyName("camelCase"u8);
writer.WriteStringValue(CamelCase);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@
using System.ClientModel.Primitives;
using System.Text.Json;

namespace sample.namespace.Models
namespace Sample.Models
{
/// <summary></summary>
public partial class TestModel : global::System.ClientModel.Primitives.IJsonModel<global::sample.namespace.Models.TestModel>
public partial class TestModel : global::System.ClientModel.Primitives.IJsonModel<global::Sample.Models.TestModel>
{
/// <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.namespace.Models.TestModel>)this).GetFormatFromOptions(options) : options.Format;
string format = (options.Format == "W") ? ((global::System.ClientModel.Primitives.IPersistableModel<global::Sample.Models.TestModel>)this).GetFormatFromOptions(options) : options.Format;
if ((format != "J"))
{
throw new global::System.FormatException($"The model {nameof(global::sample.namespace.Models.TestModel)} does not support writing '{format}' format.");
throw new global::System.FormatException($"The model {nameof(global::Sample.Models.TestModel)} does not support writing '{format}' format.");
}
writer.WritePropertyName("kebab-case"u8);
writer.WriteStringValue(KebabCase);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@
using System.ClientModel.Primitives;
using System.Text.Json;

namespace sample.namespace.Models
namespace Sample.Models
{
/// <summary></summary>
public partial class TestModel : global::System.ClientModel.Primitives.IJsonModel<global::sample.namespace.Models.TestModel>
public partial class TestModel : global::System.ClientModel.Primitives.IJsonModel<global::Sample.Models.TestModel>
{
/// <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.namespace.Models.TestModel>)this).GetFormatFromOptions(options) : options.Format;
string format = (options.Format == "W") ? ((global::System.ClientModel.Primitives.IPersistableModel<global::Sample.Models.TestModel>)this).GetFormatFromOptions(options) : options.Format;
if ((format != "J"))
{
throw new global::System.FormatException($"The model {nameof(global::sample.namespace.Models.TestModel)} does not support writing '{format}' format.");
throw new global::System.FormatException($"The model {nameof(global::Sample.Models.TestModel)} does not support writing '{format}' format.");
}
writer.WritePropertyName("color"u8);
writer.WriteStringValue(Color);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@
using System.ClientModel.Primitives;
using System.Text.Json;

namespace sample.namespace.Models
namespace Sample.Models
{
/// <summary></summary>
public partial class TestModel : global::System.ClientModel.Primitives.IJsonModel<global::sample.namespace.Models.TestModel>
public partial class TestModel : global::System.ClientModel.Primitives.IJsonModel<global::Sample.Models.TestModel>
{
/// <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.namespace.Models.TestModel>)this).GetFormatFromOptions(options) : options.Format;
string format = (options.Format == "W") ? ((global::System.ClientModel.Primitives.IPersistableModel<global::Sample.Models.TestModel>)this).GetFormatFromOptions(options) : options.Format;
if ((format != "J"))
{
throw new global::System.FormatException($"The model {nameof(global::sample.namespace.Models.TestModel)} does not support writing '{format}' format.");
throw new global::System.FormatException($"The model {nameof(global::Sample.Models.TestModel)} does not support writing '{format}' format.");
}
writer.WritePropertyName("PascalCase"u8);
writer.WriteStringValue(PascalCase);
Expand Down
Loading

0 comments on commit d62adb1

Please sign in to comment.