From fbd34d12e5a1867c7ff37dd979b16945c9e7f469 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 14:47:42 +0000 Subject: [PATCH 1/8] Initial plan From d250f4796df65cae469606b9e847ff52916db2da Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 15:09:24 +0000 Subject: [PATCH 2/8] feat: only use full namespace for api version enum when there are collisions Use last namespace segment for api version enum names in multi-service scenarios by default. Fall back to full namespace only when two or more services share the same last namespace segment, avoiding unnecessary prefix noise while still guaranteeing uniqueness. Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../src/Providers/ClientOptionsProvider.cs | 42 ++++++++++++-- .../ClientProviders/ClientProviderTests.cs | 8 +-- ...ceClient_GeneratesExpectedClientOptions.cs | 38 ++++++------ ...Services_GeneratesExpectedClientOptions.cs | 58 +++++++++---------- ...edClient_GeneratesExpectedClientOptions.cs | 38 ++++++------ ...Services_GeneratesExpectedClientOptions.cs | 58 +++++++++---------- .../src/Providers/ApiVersionEnumProvider.cs | 20 ++++++- .../ApiVersionEnumProviderTests.cs | 45 +++++++++++++- 8 files changed, 196 insertions(+), 111 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs index 975c2492146..a3a74991fa8 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs @@ -131,13 +131,39 @@ private static bool UseSingletonInstance(InputClient inputClient) } var properties = new Dictionary(_serviceVersionsEnums.Count); + + // Precompute which last namespace segments have collisions + HashSet? collidingSegments = null; + if (_inputClient.IsMultiServiceClient) + { + var segmentCounts = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (var (inputEnum, _) in _serviceVersionsEnums) + { + var segment = GetLastNamespaceSegment(inputEnum.Namespace); + segmentCounts[segment] = segmentCounts.TryGetValue(segment, out var count) ? count + 1 : 1; + } + collidingSegments = new HashSet( + segmentCounts.Where(kv => kv.Value > 1).Select(kv => kv.Key), + StringComparer.OrdinalIgnoreCase); + } + foreach (var (inputEnum, enumProvider) in _serviceVersionsEnums) { - // For multi-service clients, use the full namespace to guarantee uniqueness - // (the last segment alone can collide when services share a namespace). - var versionPropertyName = _inputClient.IsMultiServiceClient - ? $"{inputEnum.Namespace.ToIdentifierName()}{ApiVersionSuffix}" - : VersionSuffix; + string versionPropertyName; + if (_inputClient.IsMultiServiceClient) + { + var ns = inputEnum.Namespace; + var lastSegment = GetLastNamespaceSegment(ns); + // Only use the full namespace when the last segment collides + // with another service's last segment. + versionPropertyName = collidingSegments!.Contains(lastSegment) + ? $"{ns.ToIdentifierName()}{ApiVersionSuffix}" + : $"{lastSegment.ToIdentifierName()}{ApiVersionSuffix}"; + } + else + { + versionPropertyName = VersionSuffix; + } var versionProperty = new PropertyProvider( null, @@ -151,6 +177,12 @@ private static bool UseSingletonInstance(InputClient inputClient) return properties; } + + private static string GetLastNamespaceSegment(string ns) + { + int lastDot = ns.LastIndexOf('.'); + return lastDot >= 0 ? ns.Substring(lastDot + 1) : ns; + } private IReadOnlyDictionary? LatestVersionsFields => field ??= BuildLatestVersionsFields(); private Dictionary? BuildLatestVersionsFields() diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs index 127e1420d06..5276928178a 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs @@ -3678,12 +3678,12 @@ public void GetApiVersionFieldForService_MultiService_ReturnsMatchingField() // Should return the matching field for ServiceA var fieldA = clientProvider!.GetApiVersionFieldForService("Sample.ServiceA"); Assert.IsNotNull(fieldA); - Assert.AreEqual("_sampleServiceAApiVersion", fieldA!.Name); + Assert.AreEqual("_serviceAApiVersion", fieldA!.Name); // Should return the matching field for ServiceB var fieldB = clientProvider.GetApiVersionFieldForService("Sample.ServiceB"); Assert.IsNotNull(fieldB); - Assert.AreEqual("_sampleServiceBApiVersion", fieldB!.Name); + Assert.AreEqual("_serviceBApiVersion", fieldB!.Name); } [Test] @@ -3814,11 +3814,11 @@ public void GetApiVersionFieldForService_MultiService_CaseInsensitiveMatch() // Should match case-insensitively var fieldLowerCase = clientProvider!.GetApiVersionFieldForService("sample.serviceA"); Assert.IsNotNull(fieldLowerCase); - Assert.AreEqual("_sampleServiceAApiVersion", fieldLowerCase!.Name); + Assert.AreEqual("_serviceAApiVersion", fieldLowerCase!.Name); var fieldUpperCase = clientProvider.GetApiVersionFieldForService("SAMPLE.SERVICEa"); Assert.IsNotNull(fieldUpperCase); - Assert.AreEqual("_sampleServiceAApiVersion", fieldUpperCase!.Name); + Assert.AreEqual("_serviceAApiVersion", fieldUpperCase!.Name); } [Test] diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_GeneratesExpectedClientOptions.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_GeneratesExpectedClientOptions.cs index 30c5361bdaf..1eb960fa71f 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_GeneratesExpectedClientOptions.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_GeneratesExpectedClientOptions.cs @@ -11,21 +11,21 @@ namespace Sample { public partial class TestClientOptions : global::System.ClientModel.Primitives.ClientPipelineOptions { - private const global::Sample.TestClientOptions.SampleServiceAVersion LatestSampleServiceAVersion = global::Sample.TestClientOptions.SampleServiceAVersion.V2_0; - private const global::Sample.TestClientOptions.SampleServiceBVersion LatestSampleServiceBVersion = global::Sample.TestClientOptions.SampleServiceBVersion.V4_0; + private const global::Sample.TestClientOptions.ServiceAVersion LatestServiceAVersion = global::Sample.TestClientOptions.ServiceAVersion.V2_0; + private const global::Sample.TestClientOptions.ServiceBVersion LatestServiceBVersion = global::Sample.TestClientOptions.ServiceBVersion.V4_0; - public TestClientOptions(global::Sample.TestClientOptions.SampleServiceAVersion sampleServiceAVersion = LatestSampleServiceAVersion, global::Sample.TestClientOptions.SampleServiceBVersion sampleServiceBVersion = LatestSampleServiceBVersion) + public TestClientOptions(global::Sample.TestClientOptions.ServiceAVersion serviceAVersion = LatestServiceAVersion, global::Sample.TestClientOptions.ServiceBVersion serviceBVersion = LatestServiceBVersion) { - SampleServiceAApiVersion = sampleServiceAVersion switch + ServiceAApiVersion = serviceAVersion switch { - global::Sample.TestClientOptions.SampleServiceAVersion.V1_0 => "1.0", - global::Sample.TestClientOptions.SampleServiceAVersion.V2_0 => "2.0", + global::Sample.TestClientOptions.ServiceAVersion.V1_0 => "1.0", + global::Sample.TestClientOptions.ServiceAVersion.V2_0 => "2.0", _ => throw new global::System.NotSupportedException() }; - SampleServiceBApiVersion = sampleServiceBVersion switch + ServiceBApiVersion = serviceBVersion switch { - global::Sample.TestClientOptions.SampleServiceBVersion.V3_0 => "3.0", - global::Sample.TestClientOptions.SampleServiceBVersion.V4_0 => "4.0", + global::Sample.TestClientOptions.ServiceBVersion.V3_0 => "3.0", + global::Sample.TestClientOptions.ServiceBVersion.V4_0 => "4.0", _ => throw new global::System.NotSupportedException() }; } @@ -33,33 +33,33 @@ public TestClientOptions(global::Sample.TestClientOptions.SampleServiceAVersion [global::System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SCME0002")] internal TestClientOptions(global::Microsoft.Extensions.Configuration.IConfigurationSection section) : base(section) { - SampleServiceAApiVersion = "2.0"; - SampleServiceBApiVersion = "4.0"; + ServiceAApiVersion = "2.0"; + ServiceBApiVersion = "4.0"; if (((section is null) || !section.Exists())) { return; } - if ((section["SampleServiceAApiVersion"] is string sampleServiceAApiVersion)) + if ((section["ServiceAApiVersion"] is string serviceAApiVersion)) { - this.SampleServiceAApiVersion = sampleServiceAApiVersion; + this.ServiceAApiVersion = serviceAApiVersion; } - if ((section["SampleServiceBApiVersion"] is string sampleServiceBApiVersion)) + if ((section["ServiceBApiVersion"] is string serviceBApiVersion)) { - this.SampleServiceBApiVersion = sampleServiceBApiVersion; + this.ServiceBApiVersion = serviceBApiVersion; } } - internal string SampleServiceAApiVersion { get; } + internal string ServiceAApiVersion { get; } - internal string SampleServiceBApiVersion { get; } + internal string ServiceBApiVersion { get; } - public enum SampleServiceAVersion + public enum ServiceAVersion { V1_0 = 1, V2_0 = 2 } - public enum SampleServiceBVersion + public enum ServiceBVersion { V3_0 = 1, V4_0 = 2 diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_WithThreeServices_GeneratesExpectedClientOptions.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_WithThreeServices_GeneratesExpectedClientOptions.cs index 740d3a43b3a..7dd1ff9bf30 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_WithThreeServices_GeneratesExpectedClientOptions.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_WithThreeServices_GeneratesExpectedClientOptions.cs @@ -11,29 +11,29 @@ namespace Sample { public partial class TestClientOptions : global::System.ClientModel.Primitives.ClientPipelineOptions { - private const global::Sample.TestClientOptions.SampleComputeVersion LatestSampleComputeVersion = global::Sample.TestClientOptions.SampleComputeVersion.V2024_07_01; - private const global::Sample.TestClientOptions.SampleKeyVaultVersion LatestSampleKeyVaultVersion = global::Sample.TestClientOptions.SampleKeyVaultVersion.V7_5; - private const global::Sample.TestClientOptions.SampleStorageVersion LatestSampleStorageVersion = global::Sample.TestClientOptions.SampleStorageVersion.V2024_01_01; + private const global::Sample.TestClientOptions.ComputeVersion LatestComputeVersion = global::Sample.TestClientOptions.ComputeVersion.V2024_07_01; + private const global::Sample.TestClientOptions.KeyVaultVersion LatestKeyVaultVersion = global::Sample.TestClientOptions.KeyVaultVersion.V7_5; + private const global::Sample.TestClientOptions.StorageVersion LatestStorageVersion = global::Sample.TestClientOptions.StorageVersion.V2024_01_01; - public TestClientOptions(global::Sample.TestClientOptions.SampleKeyVaultVersion sampleKeyVaultVersion = LatestSampleKeyVaultVersion, global::Sample.TestClientOptions.SampleStorageVersion sampleStorageVersion = LatestSampleStorageVersion, global::Sample.TestClientOptions.SampleComputeVersion sampleComputeVersion = LatestSampleComputeVersion) + public TestClientOptions(global::Sample.TestClientOptions.KeyVaultVersion keyVaultVersion = LatestKeyVaultVersion, global::Sample.TestClientOptions.StorageVersion storageVersion = LatestStorageVersion, global::Sample.TestClientOptions.ComputeVersion computeVersion = LatestComputeVersion) { - SampleKeyVaultApiVersion = sampleKeyVaultVersion switch + KeyVaultApiVersion = keyVaultVersion switch { - global::Sample.TestClientOptions.SampleKeyVaultVersion.V7_4 => "7.4", - global::Sample.TestClientOptions.SampleKeyVaultVersion.V7_5 => "7.5", + global::Sample.TestClientOptions.KeyVaultVersion.V7_4 => "7.4", + global::Sample.TestClientOptions.KeyVaultVersion.V7_5 => "7.5", _ => throw new global::System.NotSupportedException() }; - SampleStorageApiVersion = sampleStorageVersion switch + StorageApiVersion = storageVersion switch { - global::Sample.TestClientOptions.SampleStorageVersion.V2023_01_01 => "2023-01-01", - global::Sample.TestClientOptions.SampleStorageVersion.V2024_01_01 => "2024-01-01", + global::Sample.TestClientOptions.StorageVersion.V2023_01_01 => "2023-01-01", + global::Sample.TestClientOptions.StorageVersion.V2024_01_01 => "2024-01-01", _ => throw new global::System.NotSupportedException() }; - SampleComputeApiVersion = sampleComputeVersion switch + ComputeApiVersion = computeVersion switch { - global::Sample.TestClientOptions.SampleComputeVersion.V2023_07_01 => "2023-07-01", - global::Sample.TestClientOptions.SampleComputeVersion.V2024_03_01 => "2024-03-01", - global::Sample.TestClientOptions.SampleComputeVersion.V2024_07_01 => "2024-07-01", + global::Sample.TestClientOptions.ComputeVersion.V2023_07_01 => "2023-07-01", + global::Sample.TestClientOptions.ComputeVersion.V2024_03_01 => "2024-03-01", + global::Sample.TestClientOptions.ComputeVersion.V2024_07_01 => "2024-07-01", _ => throw new global::System.NotSupportedException() }; } @@ -41,47 +41,47 @@ public TestClientOptions(global::Sample.TestClientOptions.SampleKeyVaultVersion [global::System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SCME0002")] internal TestClientOptions(global::Microsoft.Extensions.Configuration.IConfigurationSection section) : base(section) { - SampleComputeApiVersion = "2024-07-01"; - SampleKeyVaultApiVersion = "7.5"; - SampleStorageApiVersion = "2024-01-01"; + ComputeApiVersion = "2024-07-01"; + KeyVaultApiVersion = "7.5"; + StorageApiVersion = "2024-01-01"; if (((section is null) || !section.Exists())) { return; } - if ((section["SampleComputeApiVersion"] is string sampleComputeApiVersion)) + if ((section["ComputeApiVersion"] is string computeApiVersion)) { - this.SampleComputeApiVersion = sampleComputeApiVersion; + this.ComputeApiVersion = computeApiVersion; } - if ((section["SampleKeyVaultApiVersion"] is string sampleKeyVaultApiVersion)) + if ((section["KeyVaultApiVersion"] is string keyVaultApiVersion)) { - this.SampleKeyVaultApiVersion = sampleKeyVaultApiVersion; + this.KeyVaultApiVersion = keyVaultApiVersion; } - if ((section["SampleStorageApiVersion"] is string sampleStorageApiVersion)) + if ((section["StorageApiVersion"] is string storageApiVersion)) { - this.SampleStorageApiVersion = sampleStorageApiVersion; + this.StorageApiVersion = storageApiVersion; } } - internal string SampleComputeApiVersion { get; } + internal string ComputeApiVersion { get; } - internal string SampleKeyVaultApiVersion { get; } + internal string KeyVaultApiVersion { get; } - internal string SampleStorageApiVersion { get; } + internal string StorageApiVersion { get; } - public enum SampleComputeVersion + public enum ComputeVersion { V2023_07_01 = 1, V2024_03_01 = 2, V2024_07_01 = 3 } - public enum SampleKeyVaultVersion + public enum KeyVaultVersion { V7_4 = 1, V7_5 = 2 } - public enum SampleStorageVersion + public enum StorageVersion { V2023_01_01 = 1, V2024_01_01 = 2 diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_GeneratesExpectedClientOptions.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_GeneratesExpectedClientOptions.cs index 30c5361bdaf..1eb960fa71f 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_GeneratesExpectedClientOptions.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_GeneratesExpectedClientOptions.cs @@ -11,21 +11,21 @@ namespace Sample { public partial class TestClientOptions : global::System.ClientModel.Primitives.ClientPipelineOptions { - private const global::Sample.TestClientOptions.SampleServiceAVersion LatestSampleServiceAVersion = global::Sample.TestClientOptions.SampleServiceAVersion.V2_0; - private const global::Sample.TestClientOptions.SampleServiceBVersion LatestSampleServiceBVersion = global::Sample.TestClientOptions.SampleServiceBVersion.V4_0; + private const global::Sample.TestClientOptions.ServiceAVersion LatestServiceAVersion = global::Sample.TestClientOptions.ServiceAVersion.V2_0; + private const global::Sample.TestClientOptions.ServiceBVersion LatestServiceBVersion = global::Sample.TestClientOptions.ServiceBVersion.V4_0; - public TestClientOptions(global::Sample.TestClientOptions.SampleServiceAVersion sampleServiceAVersion = LatestSampleServiceAVersion, global::Sample.TestClientOptions.SampleServiceBVersion sampleServiceBVersion = LatestSampleServiceBVersion) + public TestClientOptions(global::Sample.TestClientOptions.ServiceAVersion serviceAVersion = LatestServiceAVersion, global::Sample.TestClientOptions.ServiceBVersion serviceBVersion = LatestServiceBVersion) { - SampleServiceAApiVersion = sampleServiceAVersion switch + ServiceAApiVersion = serviceAVersion switch { - global::Sample.TestClientOptions.SampleServiceAVersion.V1_0 => "1.0", - global::Sample.TestClientOptions.SampleServiceAVersion.V2_0 => "2.0", + global::Sample.TestClientOptions.ServiceAVersion.V1_0 => "1.0", + global::Sample.TestClientOptions.ServiceAVersion.V2_0 => "2.0", _ => throw new global::System.NotSupportedException() }; - SampleServiceBApiVersion = sampleServiceBVersion switch + ServiceBApiVersion = serviceBVersion switch { - global::Sample.TestClientOptions.SampleServiceBVersion.V3_0 => "3.0", - global::Sample.TestClientOptions.SampleServiceBVersion.V4_0 => "4.0", + global::Sample.TestClientOptions.ServiceBVersion.V3_0 => "3.0", + global::Sample.TestClientOptions.ServiceBVersion.V4_0 => "4.0", _ => throw new global::System.NotSupportedException() }; } @@ -33,33 +33,33 @@ public TestClientOptions(global::Sample.TestClientOptions.SampleServiceAVersion [global::System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SCME0002")] internal TestClientOptions(global::Microsoft.Extensions.Configuration.IConfigurationSection section) : base(section) { - SampleServiceAApiVersion = "2.0"; - SampleServiceBApiVersion = "4.0"; + ServiceAApiVersion = "2.0"; + ServiceBApiVersion = "4.0"; if (((section is null) || !section.Exists())) { return; } - if ((section["SampleServiceAApiVersion"] is string sampleServiceAApiVersion)) + if ((section["ServiceAApiVersion"] is string serviceAApiVersion)) { - this.SampleServiceAApiVersion = sampleServiceAApiVersion; + this.ServiceAApiVersion = serviceAApiVersion; } - if ((section["SampleServiceBApiVersion"] is string sampleServiceBApiVersion)) + if ((section["ServiceBApiVersion"] is string serviceBApiVersion)) { - this.SampleServiceBApiVersion = sampleServiceBApiVersion; + this.ServiceBApiVersion = serviceBApiVersion; } } - internal string SampleServiceAApiVersion { get; } + internal string ServiceAApiVersion { get; } - internal string SampleServiceBApiVersion { get; } + internal string ServiceBApiVersion { get; } - public enum SampleServiceAVersion + public enum ServiceAVersion { V1_0 = 1, V2_0 = 2 } - public enum SampleServiceBVersion + public enum ServiceBVersion { V3_0 = 1, V4_0 = 2 diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedClientOptions.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedClientOptions.cs index 740d3a43b3a..7dd1ff9bf30 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedClientOptions.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedClientOptions.cs @@ -11,29 +11,29 @@ namespace Sample { public partial class TestClientOptions : global::System.ClientModel.Primitives.ClientPipelineOptions { - private const global::Sample.TestClientOptions.SampleComputeVersion LatestSampleComputeVersion = global::Sample.TestClientOptions.SampleComputeVersion.V2024_07_01; - private const global::Sample.TestClientOptions.SampleKeyVaultVersion LatestSampleKeyVaultVersion = global::Sample.TestClientOptions.SampleKeyVaultVersion.V7_5; - private const global::Sample.TestClientOptions.SampleStorageVersion LatestSampleStorageVersion = global::Sample.TestClientOptions.SampleStorageVersion.V2024_01_01; + private const global::Sample.TestClientOptions.ComputeVersion LatestComputeVersion = global::Sample.TestClientOptions.ComputeVersion.V2024_07_01; + private const global::Sample.TestClientOptions.KeyVaultVersion LatestKeyVaultVersion = global::Sample.TestClientOptions.KeyVaultVersion.V7_5; + private const global::Sample.TestClientOptions.StorageVersion LatestStorageVersion = global::Sample.TestClientOptions.StorageVersion.V2024_01_01; - public TestClientOptions(global::Sample.TestClientOptions.SampleKeyVaultVersion sampleKeyVaultVersion = LatestSampleKeyVaultVersion, global::Sample.TestClientOptions.SampleStorageVersion sampleStorageVersion = LatestSampleStorageVersion, global::Sample.TestClientOptions.SampleComputeVersion sampleComputeVersion = LatestSampleComputeVersion) + public TestClientOptions(global::Sample.TestClientOptions.KeyVaultVersion keyVaultVersion = LatestKeyVaultVersion, global::Sample.TestClientOptions.StorageVersion storageVersion = LatestStorageVersion, global::Sample.TestClientOptions.ComputeVersion computeVersion = LatestComputeVersion) { - SampleKeyVaultApiVersion = sampleKeyVaultVersion switch + KeyVaultApiVersion = keyVaultVersion switch { - global::Sample.TestClientOptions.SampleKeyVaultVersion.V7_4 => "7.4", - global::Sample.TestClientOptions.SampleKeyVaultVersion.V7_5 => "7.5", + global::Sample.TestClientOptions.KeyVaultVersion.V7_4 => "7.4", + global::Sample.TestClientOptions.KeyVaultVersion.V7_5 => "7.5", _ => throw new global::System.NotSupportedException() }; - SampleStorageApiVersion = sampleStorageVersion switch + StorageApiVersion = storageVersion switch { - global::Sample.TestClientOptions.SampleStorageVersion.V2023_01_01 => "2023-01-01", - global::Sample.TestClientOptions.SampleStorageVersion.V2024_01_01 => "2024-01-01", + global::Sample.TestClientOptions.StorageVersion.V2023_01_01 => "2023-01-01", + global::Sample.TestClientOptions.StorageVersion.V2024_01_01 => "2024-01-01", _ => throw new global::System.NotSupportedException() }; - SampleComputeApiVersion = sampleComputeVersion switch + ComputeApiVersion = computeVersion switch { - global::Sample.TestClientOptions.SampleComputeVersion.V2023_07_01 => "2023-07-01", - global::Sample.TestClientOptions.SampleComputeVersion.V2024_03_01 => "2024-03-01", - global::Sample.TestClientOptions.SampleComputeVersion.V2024_07_01 => "2024-07-01", + global::Sample.TestClientOptions.ComputeVersion.V2023_07_01 => "2023-07-01", + global::Sample.TestClientOptions.ComputeVersion.V2024_03_01 => "2024-03-01", + global::Sample.TestClientOptions.ComputeVersion.V2024_07_01 => "2024-07-01", _ => throw new global::System.NotSupportedException() }; } @@ -41,47 +41,47 @@ public TestClientOptions(global::Sample.TestClientOptions.SampleKeyVaultVersion [global::System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SCME0002")] internal TestClientOptions(global::Microsoft.Extensions.Configuration.IConfigurationSection section) : base(section) { - SampleComputeApiVersion = "2024-07-01"; - SampleKeyVaultApiVersion = "7.5"; - SampleStorageApiVersion = "2024-01-01"; + ComputeApiVersion = "2024-07-01"; + KeyVaultApiVersion = "7.5"; + StorageApiVersion = "2024-01-01"; if (((section is null) || !section.Exists())) { return; } - if ((section["SampleComputeApiVersion"] is string sampleComputeApiVersion)) + if ((section["ComputeApiVersion"] is string computeApiVersion)) { - this.SampleComputeApiVersion = sampleComputeApiVersion; + this.ComputeApiVersion = computeApiVersion; } - if ((section["SampleKeyVaultApiVersion"] is string sampleKeyVaultApiVersion)) + if ((section["KeyVaultApiVersion"] is string keyVaultApiVersion)) { - this.SampleKeyVaultApiVersion = sampleKeyVaultApiVersion; + this.KeyVaultApiVersion = keyVaultApiVersion; } - if ((section["SampleStorageApiVersion"] is string sampleStorageApiVersion)) + if ((section["StorageApiVersion"] is string storageApiVersion)) { - this.SampleStorageApiVersion = sampleStorageApiVersion; + this.StorageApiVersion = storageApiVersion; } } - internal string SampleComputeApiVersion { get; } + internal string ComputeApiVersion { get; } - internal string SampleKeyVaultApiVersion { get; } + internal string KeyVaultApiVersion { get; } - internal string SampleStorageApiVersion { get; } + internal string StorageApiVersion { get; } - public enum SampleComputeVersion + public enum ComputeVersion { V2023_07_01 = 1, V2024_03_01 = 2, V2024_07_01 = 3 } - public enum SampleKeyVaultVersion + public enum KeyVaultVersion { V7_4 = 1, V7_5 = 2 } - public enum SampleStorageVersion + public enum StorageVersion { V2023_01_01 = 1, V2024_01_01 = 2 diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ApiVersionEnumProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ApiVersionEnumProvider.cs index 836497737a6..346284286c2 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ApiVersionEnumProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ApiVersionEnumProvider.cs @@ -38,15 +38,29 @@ protected override string BuildName() var serviceNamespace = _inputEnum.Namespace; if (!string.IsNullOrEmpty(serviceNamespace)) { - // Use the full namespace to guarantee uniqueness when services - // have different namespaces but the same last segment. - return $"{serviceNamespace.ToIdentifierName()}{VersionSuffix}"; + var lastSegment = GetLastNamespaceSegment(serviceNamespace); + bool hasCollision = apiVersionEnums.Any(e => + e != _inputEnum && + !string.IsNullOrEmpty(e.Namespace) && + string.Equals(GetLastNamespaceSegment(e.Namespace), lastSegment, StringComparison.OrdinalIgnoreCase)); + + // Only use the full namespace when there is a collision in the + // last segment; otherwise, use just the last segment. + return hasCollision + ? $"{serviceNamespace.ToIdentifierName()}{VersionSuffix}" + : $"{lastSegment.ToIdentifierName()}{VersionSuffix}"; } } return ApiVersionEnumName; } + private static string GetLastNamespaceSegment(string ns) + { + int lastDot = ns.LastIndexOf('.'); + return lastDot >= 0 ? ns.Substring(lastDot + 1) : ns; + } + protected override FormattableString BuildDescription() => $"{ApiVersionEnumDescription}"; protected override IReadOnlyList BuildEnumValues() diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/EnumProviders/ApiVersionEnumProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/EnumProviders/ApiVersionEnumProviderTests.cs index 49ba16c2aad..8289cae49e3 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/EnumProviders/ApiVersionEnumProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/EnumProviders/ApiVersionEnumProviderTests.cs @@ -178,9 +178,9 @@ public void MultiServiceClient_WithMultipleApiVersionEnums_GeneratesCorrectEnumN Assert.IsTrue(storageEnumType is ApiVersionEnumProvider); var storageProvider = (ApiVersionEnumProvider)storageEnumType; - // Verify enum names use the full namespace for uniqueness: {FullNamespace}Version - Assert.AreEqual("SampleKeyVaultVersion", keyVaultProvider.Name); - Assert.AreEqual("SampleStorageVersion", storageProvider.Name); + // Verify enum names use only the last namespace segment when there are no collisions: {LastSegment}Version + Assert.AreEqual("KeyVaultVersion", keyVaultProvider.Name); + Assert.AreEqual("StorageVersion", storageProvider.Name); } [Test] @@ -211,5 +211,44 @@ public void MultiServiceClient_WithOneApiVersionEnums_GeneratesCorrectEnumNames( // Verify enum names follow the multiservice naming pattern: Service{ServiceName}Version Assert.AreEqual("ServiceVersion", keyVaultProvider.Name); } + + [Test] + public void MultiServiceClient_WithCollidingLastSegments_UsesFullNamespace() + { + // When two services have different full namespaces but the same last segment, + // the full namespace should be used to avoid collisions. + var serviceOneEnum = InputFactory.StringEnum( + "ServiceOneVersion", + [("1.0", "1.0"), ("2.0", "2.0")], + usage: InputModelTypeUsage.ApiVersionEnum, + clientNamespace: "Azure.ServiceOne.Tests"); + var serviceTwoEnum = InputFactory.StringEnum( + "ServiceTwoVersion", + [("3.0", "3.0"), ("4.0", "4.0")], + usage: InputModelTypeUsage.ApiVersionEnum, + clientNamespace: "Azure.ServiceTwo.Tests"); + + var client = InputFactory.Client("TestClient", isMultiServiceClient: true); + + MockHelpers.LoadMockGenerator( + inputEnumTypes: [serviceOneEnum, serviceTwoEnum], + inputClients: [client]); + + var mockDeclaringType = new Mock(); + mockDeclaringType.Protected().Setup("BuildName").Returns("TestClientOptions"); + mockDeclaringType.Protected().Setup("BuildNamespace").Returns("Azure"); + + var serviceOneEnumType = EnumProvider.Create(serviceOneEnum, mockDeclaringType.Object); + Assert.IsTrue(serviceOneEnumType is ApiVersionEnumProvider); + var serviceOneProvider = (ApiVersionEnumProvider)serviceOneEnumType; + + var serviceTwoEnumType = EnumProvider.Create(serviceTwoEnum, mockDeclaringType.Object); + Assert.IsTrue(serviceTwoEnumType is ApiVersionEnumProvider); + var serviceTwoProvider = (ApiVersionEnumProvider)serviceTwoEnumType; + + // Verify enum names use the full namespace for uniqueness when last segments collide + Assert.AreEqual("AzureServiceOneTestsVersion", serviceOneProvider.Name); + Assert.AreEqual("AzureServiceTwoTestsVersion", serviceTwoProvider.Name); + } } } From 564104b85206c76f7879e99793ff788473f269ab Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 15:13:22 +0000 Subject: [PATCH 3/8] refactor: remove null-forgiving operator on collidingSegments Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../src/Providers/ClientOptionsProvider.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs index a3a74991fa8..9605d3b6327 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs @@ -133,7 +133,7 @@ private static bool UseSingletonInstance(InputClient inputClient) var properties = new Dictionary(_serviceVersionsEnums.Count); // Precompute which last namespace segments have collisions - HashSet? collidingSegments = null; + var collidingSegments = new HashSet(StringComparer.OrdinalIgnoreCase); if (_inputClient.IsMultiServiceClient) { var segmentCounts = new Dictionary(StringComparer.OrdinalIgnoreCase); @@ -142,9 +142,13 @@ private static bool UseSingletonInstance(InputClient inputClient) var segment = GetLastNamespaceSegment(inputEnum.Namespace); segmentCounts[segment] = segmentCounts.TryGetValue(segment, out var count) ? count + 1 : 1; } - collidingSegments = new HashSet( - segmentCounts.Where(kv => kv.Value > 1).Select(kv => kv.Key), - StringComparer.OrdinalIgnoreCase); + foreach (var kv in segmentCounts) + { + if (kv.Value > 1) + { + collidingSegments.Add(kv.Key); + } + } } foreach (var (inputEnum, enumProvider) in _serviceVersionsEnums) @@ -156,7 +160,7 @@ private static bool UseSingletonInstance(InputClient inputClient) var lastSegment = GetLastNamespaceSegment(ns); // Only use the full namespace when the last segment collides // with another service's last segment. - versionPropertyName = collidingSegments!.Contains(lastSegment) + versionPropertyName = collidingSegments.Contains(lastSegment) ? $"{ns.ToIdentifierName()}{ApiVersionSuffix}" : $"{lastSegment.ToIdentifierName()}{ApiVersionSuffix}"; } From 4672dd527b3aba1321e1e3c6b6b08407d50aeecf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 15:25:46 +0000 Subject: [PATCH 4/8] feat: restore BuildNameForService helper and use it for non-collision naming Re-adds ClientHelper.BuildNameForService and its tests that were removed in PR #10061. Uses BuildNameForService for the non-collision case in both ApiVersionEnumProvider.BuildName() and ClientOptionsProvider.BuildVersionProperties(), falling back to the full namespace only when last segments collide. Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../src/Providers/ClientOptionsProvider.cs | 4 +- ...Services_GeneratesExpectedClientOptions.cs | 58 +++--- ...Services_GeneratesExpectedClientOptions.cs | 58 +++--- .../src/Providers/ApiVersionEnumProvider.cs | 20 +- .../src/Shared/ClientHelper.cs | 39 ++++ .../ApiVersionEnumProviderTests.cs | 6 +- .../test/Shared/ClientHelperTests.cs | 171 ++++++++++++++++++ 7 files changed, 287 insertions(+), 69 deletions(-) create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Shared/ClientHelper.cs create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Shared/ClientHelperTests.cs diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs index 9605d3b6327..c0553333ee7 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs @@ -10,6 +10,7 @@ using Microsoft.TypeSpec.Generator.Input.Extensions; using Microsoft.TypeSpec.Generator.Primitives; using Microsoft.TypeSpec.Generator.Providers; +using Microsoft.TypeSpec.Generator.Shared; using Microsoft.TypeSpec.Generator.Snippets; using Microsoft.TypeSpec.Generator.Statements; using Microsoft.TypeSpec.Generator.Utilities; @@ -162,7 +163,7 @@ private static bool UseSingletonInstance(InputClient inputClient) // with another service's last segment. versionPropertyName = collidingSegments.Contains(lastSegment) ? $"{ns.ToIdentifierName()}{ApiVersionSuffix}" - : $"{lastSegment.ToIdentifierName()}{ApiVersionSuffix}"; + : ClientHelper.BuildNameForService(ns, ServicePrefix, ApiVersionSuffix); } else { @@ -187,6 +188,7 @@ private static string GetLastNamespaceSegment(string ns) int lastDot = ns.LastIndexOf('.'); return lastDot >= 0 ? ns.Substring(lastDot + 1) : ns; } + private IReadOnlyDictionary? LatestVersionsFields => field ??= BuildLatestVersionsFields(); private Dictionary? BuildLatestVersionsFields() diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_WithThreeServices_GeneratesExpectedClientOptions.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_WithThreeServices_GeneratesExpectedClientOptions.cs index 7dd1ff9bf30..1dffdca1dbb 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_WithThreeServices_GeneratesExpectedClientOptions.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_WithThreeServices_GeneratesExpectedClientOptions.cs @@ -11,29 +11,29 @@ namespace Sample { public partial class TestClientOptions : global::System.ClientModel.Primitives.ClientPipelineOptions { - private const global::Sample.TestClientOptions.ComputeVersion LatestComputeVersion = global::Sample.TestClientOptions.ComputeVersion.V2024_07_01; - private const global::Sample.TestClientOptions.KeyVaultVersion LatestKeyVaultVersion = global::Sample.TestClientOptions.KeyVaultVersion.V7_5; - private const global::Sample.TestClientOptions.StorageVersion LatestStorageVersion = global::Sample.TestClientOptions.StorageVersion.V2024_01_01; + private const global::Sample.TestClientOptions.ServiceComputeVersion LatestServiceComputeVersion = global::Sample.TestClientOptions.ServiceComputeVersion.V2024_07_01; + private const global::Sample.TestClientOptions.ServiceKeyVaultVersion LatestServiceKeyVaultVersion = global::Sample.TestClientOptions.ServiceKeyVaultVersion.V7_5; + private const global::Sample.TestClientOptions.ServiceStorageVersion LatestServiceStorageVersion = global::Sample.TestClientOptions.ServiceStorageVersion.V2024_01_01; - public TestClientOptions(global::Sample.TestClientOptions.KeyVaultVersion keyVaultVersion = LatestKeyVaultVersion, global::Sample.TestClientOptions.StorageVersion storageVersion = LatestStorageVersion, global::Sample.TestClientOptions.ComputeVersion computeVersion = LatestComputeVersion) + public TestClientOptions(global::Sample.TestClientOptions.ServiceKeyVaultVersion serviceKeyVaultVersion = LatestServiceKeyVaultVersion, global::Sample.TestClientOptions.ServiceStorageVersion serviceStorageVersion = LatestServiceStorageVersion, global::Sample.TestClientOptions.ServiceComputeVersion serviceComputeVersion = LatestServiceComputeVersion) { - KeyVaultApiVersion = keyVaultVersion switch + ServiceKeyVaultApiVersion = serviceKeyVaultVersion switch { - global::Sample.TestClientOptions.KeyVaultVersion.V7_4 => "7.4", - global::Sample.TestClientOptions.KeyVaultVersion.V7_5 => "7.5", + global::Sample.TestClientOptions.ServiceKeyVaultVersion.V7_4 => "7.4", + global::Sample.TestClientOptions.ServiceKeyVaultVersion.V7_5 => "7.5", _ => throw new global::System.NotSupportedException() }; - StorageApiVersion = storageVersion switch + ServiceStorageApiVersion = serviceStorageVersion switch { - global::Sample.TestClientOptions.StorageVersion.V2023_01_01 => "2023-01-01", - global::Sample.TestClientOptions.StorageVersion.V2024_01_01 => "2024-01-01", + global::Sample.TestClientOptions.ServiceStorageVersion.V2023_01_01 => "2023-01-01", + global::Sample.TestClientOptions.ServiceStorageVersion.V2024_01_01 => "2024-01-01", _ => throw new global::System.NotSupportedException() }; - ComputeApiVersion = computeVersion switch + ServiceComputeApiVersion = serviceComputeVersion switch { - global::Sample.TestClientOptions.ComputeVersion.V2023_07_01 => "2023-07-01", - global::Sample.TestClientOptions.ComputeVersion.V2024_03_01 => "2024-03-01", - global::Sample.TestClientOptions.ComputeVersion.V2024_07_01 => "2024-07-01", + global::Sample.TestClientOptions.ServiceComputeVersion.V2023_07_01 => "2023-07-01", + global::Sample.TestClientOptions.ServiceComputeVersion.V2024_03_01 => "2024-03-01", + global::Sample.TestClientOptions.ServiceComputeVersion.V2024_07_01 => "2024-07-01", _ => throw new global::System.NotSupportedException() }; } @@ -41,47 +41,47 @@ public TestClientOptions(global::Sample.TestClientOptions.KeyVaultVersion keyVau [global::System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SCME0002")] internal TestClientOptions(global::Microsoft.Extensions.Configuration.IConfigurationSection section) : base(section) { - ComputeApiVersion = "2024-07-01"; - KeyVaultApiVersion = "7.5"; - StorageApiVersion = "2024-01-01"; + ServiceComputeApiVersion = "2024-07-01"; + ServiceKeyVaultApiVersion = "7.5"; + ServiceStorageApiVersion = "2024-01-01"; if (((section is null) || !section.Exists())) { return; } - if ((section["ComputeApiVersion"] is string computeApiVersion)) + if ((section["ServiceComputeApiVersion"] is string serviceComputeApiVersion)) { - this.ComputeApiVersion = computeApiVersion; + this.ServiceComputeApiVersion = serviceComputeApiVersion; } - if ((section["KeyVaultApiVersion"] is string keyVaultApiVersion)) + if ((section["ServiceKeyVaultApiVersion"] is string serviceKeyVaultApiVersion)) { - this.KeyVaultApiVersion = keyVaultApiVersion; + this.ServiceKeyVaultApiVersion = serviceKeyVaultApiVersion; } - if ((section["StorageApiVersion"] is string storageApiVersion)) + if ((section["ServiceStorageApiVersion"] is string serviceStorageApiVersion)) { - this.StorageApiVersion = storageApiVersion; + this.ServiceStorageApiVersion = serviceStorageApiVersion; } } - internal string ComputeApiVersion { get; } + internal string ServiceComputeApiVersion { get; } - internal string KeyVaultApiVersion { get; } + internal string ServiceKeyVaultApiVersion { get; } - internal string StorageApiVersion { get; } + internal string ServiceStorageApiVersion { get; } - public enum ComputeVersion + public enum ServiceComputeVersion { V2023_07_01 = 1, V2024_03_01 = 2, V2024_07_01 = 3 } - public enum KeyVaultVersion + public enum ServiceKeyVaultVersion { V7_4 = 1, V7_5 = 2 } - public enum StorageVersion + public enum ServiceStorageVersion { V2023_01_01 = 1, V2024_01_01 = 2 diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedClientOptions.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedClientOptions.cs index 7dd1ff9bf30..1dffdca1dbb 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedClientOptions.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedClientOptions.cs @@ -11,29 +11,29 @@ namespace Sample { public partial class TestClientOptions : global::System.ClientModel.Primitives.ClientPipelineOptions { - private const global::Sample.TestClientOptions.ComputeVersion LatestComputeVersion = global::Sample.TestClientOptions.ComputeVersion.V2024_07_01; - private const global::Sample.TestClientOptions.KeyVaultVersion LatestKeyVaultVersion = global::Sample.TestClientOptions.KeyVaultVersion.V7_5; - private const global::Sample.TestClientOptions.StorageVersion LatestStorageVersion = global::Sample.TestClientOptions.StorageVersion.V2024_01_01; + private const global::Sample.TestClientOptions.ServiceComputeVersion LatestServiceComputeVersion = global::Sample.TestClientOptions.ServiceComputeVersion.V2024_07_01; + private const global::Sample.TestClientOptions.ServiceKeyVaultVersion LatestServiceKeyVaultVersion = global::Sample.TestClientOptions.ServiceKeyVaultVersion.V7_5; + private const global::Sample.TestClientOptions.ServiceStorageVersion LatestServiceStorageVersion = global::Sample.TestClientOptions.ServiceStorageVersion.V2024_01_01; - public TestClientOptions(global::Sample.TestClientOptions.KeyVaultVersion keyVaultVersion = LatestKeyVaultVersion, global::Sample.TestClientOptions.StorageVersion storageVersion = LatestStorageVersion, global::Sample.TestClientOptions.ComputeVersion computeVersion = LatestComputeVersion) + public TestClientOptions(global::Sample.TestClientOptions.ServiceKeyVaultVersion serviceKeyVaultVersion = LatestServiceKeyVaultVersion, global::Sample.TestClientOptions.ServiceStorageVersion serviceStorageVersion = LatestServiceStorageVersion, global::Sample.TestClientOptions.ServiceComputeVersion serviceComputeVersion = LatestServiceComputeVersion) { - KeyVaultApiVersion = keyVaultVersion switch + ServiceKeyVaultApiVersion = serviceKeyVaultVersion switch { - global::Sample.TestClientOptions.KeyVaultVersion.V7_4 => "7.4", - global::Sample.TestClientOptions.KeyVaultVersion.V7_5 => "7.5", + global::Sample.TestClientOptions.ServiceKeyVaultVersion.V7_4 => "7.4", + global::Sample.TestClientOptions.ServiceKeyVaultVersion.V7_5 => "7.5", _ => throw new global::System.NotSupportedException() }; - StorageApiVersion = storageVersion switch + ServiceStorageApiVersion = serviceStorageVersion switch { - global::Sample.TestClientOptions.StorageVersion.V2023_01_01 => "2023-01-01", - global::Sample.TestClientOptions.StorageVersion.V2024_01_01 => "2024-01-01", + global::Sample.TestClientOptions.ServiceStorageVersion.V2023_01_01 => "2023-01-01", + global::Sample.TestClientOptions.ServiceStorageVersion.V2024_01_01 => "2024-01-01", _ => throw new global::System.NotSupportedException() }; - ComputeApiVersion = computeVersion switch + ServiceComputeApiVersion = serviceComputeVersion switch { - global::Sample.TestClientOptions.ComputeVersion.V2023_07_01 => "2023-07-01", - global::Sample.TestClientOptions.ComputeVersion.V2024_03_01 => "2024-03-01", - global::Sample.TestClientOptions.ComputeVersion.V2024_07_01 => "2024-07-01", + global::Sample.TestClientOptions.ServiceComputeVersion.V2023_07_01 => "2023-07-01", + global::Sample.TestClientOptions.ServiceComputeVersion.V2024_03_01 => "2024-03-01", + global::Sample.TestClientOptions.ServiceComputeVersion.V2024_07_01 => "2024-07-01", _ => throw new global::System.NotSupportedException() }; } @@ -41,47 +41,47 @@ public TestClientOptions(global::Sample.TestClientOptions.KeyVaultVersion keyVau [global::System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SCME0002")] internal TestClientOptions(global::Microsoft.Extensions.Configuration.IConfigurationSection section) : base(section) { - ComputeApiVersion = "2024-07-01"; - KeyVaultApiVersion = "7.5"; - StorageApiVersion = "2024-01-01"; + ServiceComputeApiVersion = "2024-07-01"; + ServiceKeyVaultApiVersion = "7.5"; + ServiceStorageApiVersion = "2024-01-01"; if (((section is null) || !section.Exists())) { return; } - if ((section["ComputeApiVersion"] is string computeApiVersion)) + if ((section["ServiceComputeApiVersion"] is string serviceComputeApiVersion)) { - this.ComputeApiVersion = computeApiVersion; + this.ServiceComputeApiVersion = serviceComputeApiVersion; } - if ((section["KeyVaultApiVersion"] is string keyVaultApiVersion)) + if ((section["ServiceKeyVaultApiVersion"] is string serviceKeyVaultApiVersion)) { - this.KeyVaultApiVersion = keyVaultApiVersion; + this.ServiceKeyVaultApiVersion = serviceKeyVaultApiVersion; } - if ((section["StorageApiVersion"] is string storageApiVersion)) + if ((section["ServiceStorageApiVersion"] is string serviceStorageApiVersion)) { - this.StorageApiVersion = storageApiVersion; + this.ServiceStorageApiVersion = serviceStorageApiVersion; } } - internal string ComputeApiVersion { get; } + internal string ServiceComputeApiVersion { get; } - internal string KeyVaultApiVersion { get; } + internal string ServiceKeyVaultApiVersion { get; } - internal string StorageApiVersion { get; } + internal string ServiceStorageApiVersion { get; } - public enum ComputeVersion + public enum ServiceComputeVersion { V2023_07_01 = 1, V2024_03_01 = 2, V2024_07_01 = 3 } - public enum KeyVaultVersion + public enum ServiceKeyVaultVersion { V7_4 = 1, V7_5 = 2 } - public enum StorageVersion + public enum ServiceStorageVersion { V2023_01_01 = 1, V2024_01_01 = 2 diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ApiVersionEnumProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ApiVersionEnumProvider.cs index 346284286c2..8d2cd415c8a 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ApiVersionEnumProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ApiVersionEnumProvider.cs @@ -9,6 +9,7 @@ using Microsoft.TypeSpec.Generator.Input; using Microsoft.TypeSpec.Generator.Input.Extensions; using Microsoft.TypeSpec.Generator.Primitives; +using Microsoft.TypeSpec.Generator.Shared; using Microsoft.TypeSpec.Generator.Utilities; using static Microsoft.TypeSpec.Generator.Snippets.Snippet; @@ -38,23 +39,28 @@ protected override string BuildName() var serviceNamespace = _inputEnum.Namespace; if (!string.IsNullOrEmpty(serviceNamespace)) { - var lastSegment = GetLastNamespaceSegment(serviceNamespace); - bool hasCollision = apiVersionEnums.Any(e => - e != _inputEnum && - !string.IsNullOrEmpty(e.Namespace) && - string.Equals(GetLastNamespaceSegment(e.Namespace), lastSegment, StringComparison.OrdinalIgnoreCase)); + bool hasCollision = HasLastSegmentCollision(serviceNamespace, apiVersionEnums); // Only use the full namespace when there is a collision in the - // last segment; otherwise, use just the last segment. + // last segment; otherwise, use BuildNameForService with the last segment. return hasCollision ? $"{serviceNamespace.ToIdentifierName()}{VersionSuffix}" - : $"{lastSegment.ToIdentifierName()}{VersionSuffix}"; + : ClientHelper.BuildNameForService(serviceNamespace, ServicePrefix, VersionSuffix); } } return ApiVersionEnumName; } + private bool HasLastSegmentCollision(string serviceNamespace, List apiVersionEnums) + { + var lastSegment = GetLastNamespaceSegment(serviceNamespace); + return apiVersionEnums.Any(e => + e != _inputEnum && + !string.IsNullOrEmpty(e.Namespace) && + string.Equals(GetLastNamespaceSegment(e.Namespace), lastSegment, StringComparison.OrdinalIgnoreCase)); + } + private static string GetLastNamespaceSegment(string ns) { int lastDot = ns.LastIndexOf('.'); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Shared/ClientHelper.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Shared/ClientHelper.cs new file mode 100644 index 00000000000..527959086ec --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Shared/ClientHelper.cs @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; + +namespace Microsoft.TypeSpec.Generator.Shared +{ + internal static class ClientHelper + { + /// + /// Builds a name with the specified prefix and suffix, ensuring no duplicate prefix or suffix + /// if the namespace/service segment already contains them. + /// + /// The full service name. + /// The prefix to ensure (e.g., "Service", "Latest"). + /// The suffix to ensure (e.g., "Version"). + /// A name with the specified prefix and suffix. + public static string BuildNameForService(string serviceName, string prefix, string suffix) + { + var lastNamespaceSegment = serviceName.AsSpan(); + int lastDotIndex = serviceName.LastIndexOf('.'); + if (lastDotIndex >= 0) + { + lastNamespaceSegment = lastNamespaceSegment.Slice(lastDotIndex + 1); + } + + bool hasPrefix = lastNamespaceSegment.StartsWith(prefix.AsSpan(), StringComparison.OrdinalIgnoreCase); + bool hasSuffix = lastNamespaceSegment.EndsWith(suffix.AsSpan(), StringComparison.OrdinalIgnoreCase); + + return (hasPrefix, hasSuffix) switch + { + (true, true) => lastNamespaceSegment.ToString(), + (true, false) => $"{lastNamespaceSegment}{suffix}", + (false, true) => $"{prefix}{lastNamespaceSegment}", + (false, false) => $"{prefix}{lastNamespaceSegment}{suffix}" + }; + } + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/EnumProviders/ApiVersionEnumProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/EnumProviders/ApiVersionEnumProviderTests.cs index 8289cae49e3..afbd8979764 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/EnumProviders/ApiVersionEnumProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/EnumProviders/ApiVersionEnumProviderTests.cs @@ -178,9 +178,9 @@ public void MultiServiceClient_WithMultipleApiVersionEnums_GeneratesCorrectEnumN Assert.IsTrue(storageEnumType is ApiVersionEnumProvider); var storageProvider = (ApiVersionEnumProvider)storageEnumType; - // Verify enum names use only the last namespace segment when there are no collisions: {LastSegment}Version - Assert.AreEqual("KeyVaultVersion", keyVaultProvider.Name); - Assert.AreEqual("StorageVersion", storageProvider.Name); + // Verify enum names use BuildNameForService when there are no collisions + Assert.AreEqual("ServiceKeyVaultVersion", keyVaultProvider.Name); + Assert.AreEqual("ServiceStorageVersion", storageProvider.Name); } [Test] diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Shared/ClientHelperTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Shared/ClientHelperTests.cs new file mode 100644 index 00000000000..e9ea467e259 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Shared/ClientHelperTests.cs @@ -0,0 +1,171 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.TypeSpec.Generator.Shared; +using NUnit.Framework; + +namespace Microsoft.TypeSpec.Generator.Tests.Shared +{ + public class ClientHelperTests + { + [Test] + public void BuildNameForService_NoPrefixNoSuffix_AddsBoth() + { + var result = ClientHelper.BuildNameForService("Sample.KeyVault", "Service", "Version"); + Assert.AreEqual("ServiceKeyVaultVersion", result); + } + + [Test] + public void BuildNameForService_HasPrefixNoSuffix_AddsSuffix() + { + var result = ClientHelper.BuildNameForService("Sample.ServiceKeyVault", "Service", "Version"); + Assert.AreEqual("ServiceKeyVaultVersion", result); + } + + [Test] + public void BuildNameForService_NoPrefixHasSuffix_AddsPrefix() + { + var result = ClientHelper.BuildNameForService("Sample.KeyVaultVersion", "Service", "Version"); + Assert.AreEqual("ServiceKeyVaultVersion", result); + } + + [Test] + public void BuildNameForService_HasPrefixAndSuffix_ReturnsAsIs() + { + var result = ClientHelper.BuildNameForService("Sample.ServiceKeyVaultVersion", "Service", "Version"); + Assert.AreEqual("ServiceKeyVaultVersion", result); + } + + // Namespace handling tests + + [Test] + public void BuildNameForService_MultipleNamespaceSegments_ExtractsLastSegment() + { + var result = ClientHelper.BuildNameForService("Azure.ResourceManager.Storage", "Service", "Version"); + Assert.AreEqual("ServiceStorageVersion", result); + } + + [Test] + public void BuildNameForService_NoNamespaceSegments_UsesFullName() + { + var result = ClientHelper.BuildNameForService("Storage", "Service", "Version"); + Assert.AreEqual("ServiceStorageVersion", result); + } + + [Test] + public void BuildNameForService_SingleDotNamespace_ExtractsLastSegment() + { + var result = ClientHelper.BuildNameForService("Sample.Compute", "Service", "Version"); + Assert.AreEqual("ServiceComputeVersion", result); + } + + // Case insensitivity tests + + [Test] + public void BuildNameForService_PrefixCaseInsensitive_LowerCase() + { + var result = ClientHelper.BuildNameForService("Sample.serviceKeyVault", "Service", "Version"); + Assert.AreEqual("serviceKeyVaultVersion", result); + } + + [Test] + public void BuildNameForService_SuffixCaseInsensitive_LowerCase() + { + var result = ClientHelper.BuildNameForService("Sample.KeyVaultversion", "Service", "Version"); + Assert.AreEqual("ServiceKeyVaultversion", result); + } + + [Test] + public void BuildNameForService_BothCaseInsensitive_MixedCase() + { + var result = ClientHelper.BuildNameForService("Sample.SERVICEKeyVaultVERSION", "Service", "Version"); + Assert.AreEqual("SERVICEKeyVaultVERSION", result); + } + + // Edge cases + + [Test] + public void BuildNameForService_EmptyServiceName_ReturnsEmptyWithPrefixAndSuffix() + { + var result = ClientHelper.BuildNameForService("", "Service", "Version"); + Assert.AreEqual("ServiceVersion", result); + } + + [Test] + public void BuildNameForService_TrailingDot_ReturnsEmptyWithPrefixAndSuffix() + { + var result = ClientHelper.BuildNameForService("Sample.", "Service", "Version"); + Assert.AreEqual("ServiceVersion", result); + } + + [Test] + public void BuildNameForService_EmptyPrefix_OnlyAddsSuffix() + { + var result = ClientHelper.BuildNameForService("Sample.KeyVault", "", "Version"); + Assert.AreEqual("KeyVaultVersion", result); + } + + [Test] + public void BuildNameForService_EmptySuffix_OnlyAddsPrefix() + { + var result = ClientHelper.BuildNameForService("Sample.KeyVault", "Service", ""); + Assert.AreEqual("ServiceKeyVault", result); + } + + [Test] + public void BuildNameForService_BothPrefixAndSuffixEmpty_ReturnsLastSegment() + { + var result = ClientHelper.BuildNameForService("Sample.KeyVault", "", ""); + Assert.AreEqual("KeyVault", result); + } + + [Test] + public void BuildNameForService_ServiceNameEqualsPrefix_AddsSuffix() + { + var result = ClientHelper.BuildNameForService("Sample.Service", "Service", "Version"); + Assert.AreEqual("ServiceVersion", result); + } + + [Test] + public void BuildNameForService_ServiceNameEqualsSuffix_AddsPrefix() + { + var result = ClientHelper.BuildNameForService("Sample.Version", "Service", "Version"); + Assert.AreEqual("ServiceVersion", result); + } + + [Test] + public void BuildNameForService_ServiceNameEqualsPrefixAndSuffix_ReturnsAsIs() + { + var result = ClientHelper.BuildNameForService("Sample.ServiceVersion", "Service", "Version"); + Assert.AreEqual("ServiceVersion", result); + } + + [Test] + public void BuildNameForService_AzureKeyVault_GeneratesCorrectName() + { + var result = ClientHelper.BuildNameForService("Azure.Security.KeyVault", "Service", "Version"); + Assert.AreEqual("ServiceKeyVaultVersion", result); + } + + [Test] + public void BuildNameForService_AzureStorage_GeneratesCorrectName() + { + var result = ClientHelper.BuildNameForService("Azure.Storage.Blobs", "Service", "Version"); + Assert.AreEqual("ServiceBlobsVersion", result); + } + + [Test] + public void BuildNameForService_ApiVersionSuffix_GeneratesCorrectName() + { + var result = ClientHelper.BuildNameForService("Sample.KeyVault", "Service", "ApiVersion"); + Assert.AreEqual("ServiceKeyVaultApiVersion", result); + } + + [Test] + public void BuildNameForService_LatestPrefix_GeneratesCorrectName() + { + var result = ClientHelper.BuildNameForService("Sample.KeyVault", "Latest", "Version"); + Assert.AreEqual("LatestKeyVaultVersion", result); + } + } +} From 5b29b5809aa685c621ac2f63eec3015ea9adb02d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 16:28:37 +0000 Subject: [PATCH 5/8] refactor: address review feedback - keep field names unchanged, extract helpers, add TestData validation - Revert ClientOptionsProvider.BuildVersionProperties() to use full namespace (field names unchanged) - Revert ClientProviderTests assertions to original field names - Move GetLastNamespaceSegment and HasLastSegmentCollision to ClientHelper as shared static helpers - Update ApiVersionEnumProvider.BuildName() to use shared ClientHelper methods - Add TestData golden file validation for collision test - Update test data files: only enum type names change, property/field names stay the same Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../src/Providers/ClientOptionsProvider.cs | 48 ++----------------- .../ClientProviders/ClientProviderTests.cs | 8 ++-- ...ceClient_GeneratesExpectedClientOptions.cs | 20 ++++---- ...Services_GeneratesExpectedClientOptions.cs | 30 ++++++------ ...edClient_GeneratesExpectedClientOptions.cs | 20 ++++---- ...Services_GeneratesExpectedClientOptions.cs | 30 ++++++------ .../src/Providers/ApiVersionEnumProvider.cs | 19 +------- .../src/Shared/ClientHelper.cs | 31 ++++++++++++ .../ApiVersionEnumProviderTests.cs | 10 ++++ ...tSegments_UsesFullNamespace(ServiceOne).cs | 12 +++++ ...tSegments_UsesFullNamespace(ServiceTwo).cs | 12 +++++ 11 files changed, 125 insertions(+), 115 deletions(-) create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/EnumProviders/TestData/ApiVersionEnumProviderTests/MultiServiceClient_WithCollidingLastSegments_UsesFullNamespace(ServiceOne).cs create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/EnumProviders/TestData/ApiVersionEnumProviderTests/MultiServiceClient_WithCollidingLastSegments_UsesFullNamespace(ServiceTwo).cs diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs index c0553333ee7..975c2492146 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs @@ -10,7 +10,6 @@ using Microsoft.TypeSpec.Generator.Input.Extensions; using Microsoft.TypeSpec.Generator.Primitives; using Microsoft.TypeSpec.Generator.Providers; -using Microsoft.TypeSpec.Generator.Shared; using Microsoft.TypeSpec.Generator.Snippets; using Microsoft.TypeSpec.Generator.Statements; using Microsoft.TypeSpec.Generator.Utilities; @@ -132,43 +131,13 @@ private static bool UseSingletonInstance(InputClient inputClient) } var properties = new Dictionary(_serviceVersionsEnums.Count); - - // Precompute which last namespace segments have collisions - var collidingSegments = new HashSet(StringComparer.OrdinalIgnoreCase); - if (_inputClient.IsMultiServiceClient) - { - var segmentCounts = new Dictionary(StringComparer.OrdinalIgnoreCase); - foreach (var (inputEnum, _) in _serviceVersionsEnums) - { - var segment = GetLastNamespaceSegment(inputEnum.Namespace); - segmentCounts[segment] = segmentCounts.TryGetValue(segment, out var count) ? count + 1 : 1; - } - foreach (var kv in segmentCounts) - { - if (kv.Value > 1) - { - collidingSegments.Add(kv.Key); - } - } - } - foreach (var (inputEnum, enumProvider) in _serviceVersionsEnums) { - string versionPropertyName; - if (_inputClient.IsMultiServiceClient) - { - var ns = inputEnum.Namespace; - var lastSegment = GetLastNamespaceSegment(ns); - // Only use the full namespace when the last segment collides - // with another service's last segment. - versionPropertyName = collidingSegments.Contains(lastSegment) - ? $"{ns.ToIdentifierName()}{ApiVersionSuffix}" - : ClientHelper.BuildNameForService(ns, ServicePrefix, ApiVersionSuffix); - } - else - { - versionPropertyName = VersionSuffix; - } + // For multi-service clients, use the full namespace to guarantee uniqueness + // (the last segment alone can collide when services share a namespace). + var versionPropertyName = _inputClient.IsMultiServiceClient + ? $"{inputEnum.Namespace.ToIdentifierName()}{ApiVersionSuffix}" + : VersionSuffix; var versionProperty = new PropertyProvider( null, @@ -182,13 +151,6 @@ private static bool UseSingletonInstance(InputClient inputClient) return properties; } - - private static string GetLastNamespaceSegment(string ns) - { - int lastDot = ns.LastIndexOf('.'); - return lastDot >= 0 ? ns.Substring(lastDot + 1) : ns; - } - private IReadOnlyDictionary? LatestVersionsFields => field ??= BuildLatestVersionsFields(); private Dictionary? BuildLatestVersionsFields() diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs index 5276928178a..127e1420d06 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs @@ -3678,12 +3678,12 @@ public void GetApiVersionFieldForService_MultiService_ReturnsMatchingField() // Should return the matching field for ServiceA var fieldA = clientProvider!.GetApiVersionFieldForService("Sample.ServiceA"); Assert.IsNotNull(fieldA); - Assert.AreEqual("_serviceAApiVersion", fieldA!.Name); + Assert.AreEqual("_sampleServiceAApiVersion", fieldA!.Name); // Should return the matching field for ServiceB var fieldB = clientProvider.GetApiVersionFieldForService("Sample.ServiceB"); Assert.IsNotNull(fieldB); - Assert.AreEqual("_serviceBApiVersion", fieldB!.Name); + Assert.AreEqual("_sampleServiceBApiVersion", fieldB!.Name); } [Test] @@ -3814,11 +3814,11 @@ public void GetApiVersionFieldForService_MultiService_CaseInsensitiveMatch() // Should match case-insensitively var fieldLowerCase = clientProvider!.GetApiVersionFieldForService("sample.serviceA"); Assert.IsNotNull(fieldLowerCase); - Assert.AreEqual("_serviceAApiVersion", fieldLowerCase!.Name); + Assert.AreEqual("_sampleServiceAApiVersion", fieldLowerCase!.Name); var fieldUpperCase = clientProvider.GetApiVersionFieldForService("SAMPLE.SERVICEa"); Assert.IsNotNull(fieldUpperCase); - Assert.AreEqual("_serviceAApiVersion", fieldUpperCase!.Name); + Assert.AreEqual("_sampleServiceAApiVersion", fieldUpperCase!.Name); } [Test] diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_GeneratesExpectedClientOptions.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_GeneratesExpectedClientOptions.cs index 1eb960fa71f..aea43de4818 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_GeneratesExpectedClientOptions.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_GeneratesExpectedClientOptions.cs @@ -16,13 +16,13 @@ public partial class TestClientOptions : global::System.ClientModel.Primitives.C public TestClientOptions(global::Sample.TestClientOptions.ServiceAVersion serviceAVersion = LatestServiceAVersion, global::Sample.TestClientOptions.ServiceBVersion serviceBVersion = LatestServiceBVersion) { - ServiceAApiVersion = serviceAVersion switch + SampleServiceAApiVersion = serviceAVersion switch { global::Sample.TestClientOptions.ServiceAVersion.V1_0 => "1.0", global::Sample.TestClientOptions.ServiceAVersion.V2_0 => "2.0", _ => throw new global::System.NotSupportedException() }; - ServiceBApiVersion = serviceBVersion switch + SampleServiceBApiVersion = serviceBVersion switch { global::Sample.TestClientOptions.ServiceBVersion.V3_0 => "3.0", global::Sample.TestClientOptions.ServiceBVersion.V4_0 => "4.0", @@ -33,25 +33,25 @@ public TestClientOptions(global::Sample.TestClientOptions.ServiceAVersion servic [global::System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SCME0002")] internal TestClientOptions(global::Microsoft.Extensions.Configuration.IConfigurationSection section) : base(section) { - ServiceAApiVersion = "2.0"; - ServiceBApiVersion = "4.0"; + SampleServiceAApiVersion = "2.0"; + SampleServiceBApiVersion = "4.0"; if (((section is null) || !section.Exists())) { return; } - if ((section["ServiceAApiVersion"] is string serviceAApiVersion)) + if ((section["SampleServiceAApiVersion"] is string sampleServiceAApiVersion)) { - this.ServiceAApiVersion = serviceAApiVersion; + this.SampleServiceAApiVersion = sampleServiceAApiVersion; } - if ((section["ServiceBApiVersion"] is string serviceBApiVersion)) + if ((section["SampleServiceBApiVersion"] is string sampleServiceBApiVersion)) { - this.ServiceBApiVersion = serviceBApiVersion; + this.SampleServiceBApiVersion = sampleServiceBApiVersion; } } - internal string ServiceAApiVersion { get; } + internal string SampleServiceAApiVersion { get; } - internal string ServiceBApiVersion { get; } + internal string SampleServiceBApiVersion { get; } public enum ServiceAVersion { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_WithThreeServices_GeneratesExpectedClientOptions.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_WithThreeServices_GeneratesExpectedClientOptions.cs index 1dffdca1dbb..ebba2f7aebd 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_WithThreeServices_GeneratesExpectedClientOptions.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_WithThreeServices_GeneratesExpectedClientOptions.cs @@ -17,19 +17,19 @@ public partial class TestClientOptions : global::System.ClientModel.Primitives.C public TestClientOptions(global::Sample.TestClientOptions.ServiceKeyVaultVersion serviceKeyVaultVersion = LatestServiceKeyVaultVersion, global::Sample.TestClientOptions.ServiceStorageVersion serviceStorageVersion = LatestServiceStorageVersion, global::Sample.TestClientOptions.ServiceComputeVersion serviceComputeVersion = LatestServiceComputeVersion) { - ServiceKeyVaultApiVersion = serviceKeyVaultVersion switch + SampleKeyVaultApiVersion = serviceKeyVaultVersion switch { global::Sample.TestClientOptions.ServiceKeyVaultVersion.V7_4 => "7.4", global::Sample.TestClientOptions.ServiceKeyVaultVersion.V7_5 => "7.5", _ => throw new global::System.NotSupportedException() }; - ServiceStorageApiVersion = serviceStorageVersion switch + SampleStorageApiVersion = serviceStorageVersion switch { global::Sample.TestClientOptions.ServiceStorageVersion.V2023_01_01 => "2023-01-01", global::Sample.TestClientOptions.ServiceStorageVersion.V2024_01_01 => "2024-01-01", _ => throw new global::System.NotSupportedException() }; - ServiceComputeApiVersion = serviceComputeVersion switch + SampleComputeApiVersion = serviceComputeVersion switch { global::Sample.TestClientOptions.ServiceComputeVersion.V2023_07_01 => "2023-07-01", global::Sample.TestClientOptions.ServiceComputeVersion.V2024_03_01 => "2024-03-01", @@ -41,32 +41,32 @@ public TestClientOptions(global::Sample.TestClientOptions.ServiceKeyVaultVersion [global::System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SCME0002")] internal TestClientOptions(global::Microsoft.Extensions.Configuration.IConfigurationSection section) : base(section) { - ServiceComputeApiVersion = "2024-07-01"; - ServiceKeyVaultApiVersion = "7.5"; - ServiceStorageApiVersion = "2024-01-01"; + SampleComputeApiVersion = "2024-07-01"; + SampleKeyVaultApiVersion = "7.5"; + SampleStorageApiVersion = "2024-01-01"; if (((section is null) || !section.Exists())) { return; } - if ((section["ServiceComputeApiVersion"] is string serviceComputeApiVersion)) + if ((section["SampleComputeApiVersion"] is string sampleComputeApiVersion)) { - this.ServiceComputeApiVersion = serviceComputeApiVersion; + this.SampleComputeApiVersion = sampleComputeApiVersion; } - if ((section["ServiceKeyVaultApiVersion"] is string serviceKeyVaultApiVersion)) + if ((section["SampleKeyVaultApiVersion"] is string sampleKeyVaultApiVersion)) { - this.ServiceKeyVaultApiVersion = serviceKeyVaultApiVersion; + this.SampleKeyVaultApiVersion = sampleKeyVaultApiVersion; } - if ((section["ServiceStorageApiVersion"] is string serviceStorageApiVersion)) + if ((section["SampleStorageApiVersion"] is string sampleStorageApiVersion)) { - this.ServiceStorageApiVersion = serviceStorageApiVersion; + this.SampleStorageApiVersion = sampleStorageApiVersion; } } - internal string ServiceComputeApiVersion { get; } + internal string SampleComputeApiVersion { get; } - internal string ServiceKeyVaultApiVersion { get; } + internal string SampleKeyVaultApiVersion { get; } - internal string ServiceStorageApiVersion { get; } + internal string SampleStorageApiVersion { get; } public enum ServiceComputeVersion { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_GeneratesExpectedClientOptions.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_GeneratesExpectedClientOptions.cs index 1eb960fa71f..aea43de4818 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_GeneratesExpectedClientOptions.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_GeneratesExpectedClientOptions.cs @@ -16,13 +16,13 @@ public partial class TestClientOptions : global::System.ClientModel.Primitives.C public TestClientOptions(global::Sample.TestClientOptions.ServiceAVersion serviceAVersion = LatestServiceAVersion, global::Sample.TestClientOptions.ServiceBVersion serviceBVersion = LatestServiceBVersion) { - ServiceAApiVersion = serviceAVersion switch + SampleServiceAApiVersion = serviceAVersion switch { global::Sample.TestClientOptions.ServiceAVersion.V1_0 => "1.0", global::Sample.TestClientOptions.ServiceAVersion.V2_0 => "2.0", _ => throw new global::System.NotSupportedException() }; - ServiceBApiVersion = serviceBVersion switch + SampleServiceBApiVersion = serviceBVersion switch { global::Sample.TestClientOptions.ServiceBVersion.V3_0 => "3.0", global::Sample.TestClientOptions.ServiceBVersion.V4_0 => "4.0", @@ -33,25 +33,25 @@ public TestClientOptions(global::Sample.TestClientOptions.ServiceAVersion servic [global::System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SCME0002")] internal TestClientOptions(global::Microsoft.Extensions.Configuration.IConfigurationSection section) : base(section) { - ServiceAApiVersion = "2.0"; - ServiceBApiVersion = "4.0"; + SampleServiceAApiVersion = "2.0"; + SampleServiceBApiVersion = "4.0"; if (((section is null) || !section.Exists())) { return; } - if ((section["ServiceAApiVersion"] is string serviceAApiVersion)) + if ((section["SampleServiceAApiVersion"] is string sampleServiceAApiVersion)) { - this.ServiceAApiVersion = serviceAApiVersion; + this.SampleServiceAApiVersion = sampleServiceAApiVersion; } - if ((section["ServiceBApiVersion"] is string serviceBApiVersion)) + if ((section["SampleServiceBApiVersion"] is string sampleServiceBApiVersion)) { - this.ServiceBApiVersion = serviceBApiVersion; + this.SampleServiceBApiVersion = sampleServiceBApiVersion; } } - internal string ServiceAApiVersion { get; } + internal string SampleServiceAApiVersion { get; } - internal string ServiceBApiVersion { get; } + internal string SampleServiceBApiVersion { get; } public enum ServiceAVersion { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedClientOptions.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedClientOptions.cs index 1dffdca1dbb..ebba2f7aebd 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedClientOptions.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedClientOptions.cs @@ -17,19 +17,19 @@ public partial class TestClientOptions : global::System.ClientModel.Primitives.C public TestClientOptions(global::Sample.TestClientOptions.ServiceKeyVaultVersion serviceKeyVaultVersion = LatestServiceKeyVaultVersion, global::Sample.TestClientOptions.ServiceStorageVersion serviceStorageVersion = LatestServiceStorageVersion, global::Sample.TestClientOptions.ServiceComputeVersion serviceComputeVersion = LatestServiceComputeVersion) { - ServiceKeyVaultApiVersion = serviceKeyVaultVersion switch + SampleKeyVaultApiVersion = serviceKeyVaultVersion switch { global::Sample.TestClientOptions.ServiceKeyVaultVersion.V7_4 => "7.4", global::Sample.TestClientOptions.ServiceKeyVaultVersion.V7_5 => "7.5", _ => throw new global::System.NotSupportedException() }; - ServiceStorageApiVersion = serviceStorageVersion switch + SampleStorageApiVersion = serviceStorageVersion switch { global::Sample.TestClientOptions.ServiceStorageVersion.V2023_01_01 => "2023-01-01", global::Sample.TestClientOptions.ServiceStorageVersion.V2024_01_01 => "2024-01-01", _ => throw new global::System.NotSupportedException() }; - ServiceComputeApiVersion = serviceComputeVersion switch + SampleComputeApiVersion = serviceComputeVersion switch { global::Sample.TestClientOptions.ServiceComputeVersion.V2023_07_01 => "2023-07-01", global::Sample.TestClientOptions.ServiceComputeVersion.V2024_03_01 => "2024-03-01", @@ -41,32 +41,32 @@ public TestClientOptions(global::Sample.TestClientOptions.ServiceKeyVaultVersion [global::System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SCME0002")] internal TestClientOptions(global::Microsoft.Extensions.Configuration.IConfigurationSection section) : base(section) { - ServiceComputeApiVersion = "2024-07-01"; - ServiceKeyVaultApiVersion = "7.5"; - ServiceStorageApiVersion = "2024-01-01"; + SampleComputeApiVersion = "2024-07-01"; + SampleKeyVaultApiVersion = "7.5"; + SampleStorageApiVersion = "2024-01-01"; if (((section is null) || !section.Exists())) { return; } - if ((section["ServiceComputeApiVersion"] is string serviceComputeApiVersion)) + if ((section["SampleComputeApiVersion"] is string sampleComputeApiVersion)) { - this.ServiceComputeApiVersion = serviceComputeApiVersion; + this.SampleComputeApiVersion = sampleComputeApiVersion; } - if ((section["ServiceKeyVaultApiVersion"] is string serviceKeyVaultApiVersion)) + if ((section["SampleKeyVaultApiVersion"] is string sampleKeyVaultApiVersion)) { - this.ServiceKeyVaultApiVersion = serviceKeyVaultApiVersion; + this.SampleKeyVaultApiVersion = sampleKeyVaultApiVersion; } - if ((section["ServiceStorageApiVersion"] is string serviceStorageApiVersion)) + if ((section["SampleStorageApiVersion"] is string sampleStorageApiVersion)) { - this.ServiceStorageApiVersion = serviceStorageApiVersion; + this.SampleStorageApiVersion = sampleStorageApiVersion; } } - internal string ServiceComputeApiVersion { get; } + internal string SampleComputeApiVersion { get; } - internal string ServiceKeyVaultApiVersion { get; } + internal string SampleKeyVaultApiVersion { get; } - internal string ServiceStorageApiVersion { get; } + internal string SampleStorageApiVersion { get; } public enum ServiceComputeVersion { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ApiVersionEnumProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ApiVersionEnumProvider.cs index 8d2cd415c8a..cbcc6cd648e 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ApiVersionEnumProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ApiVersionEnumProvider.cs @@ -39,11 +39,9 @@ protected override string BuildName() var serviceNamespace = _inputEnum.Namespace; if (!string.IsNullOrEmpty(serviceNamespace)) { - bool hasCollision = HasLastSegmentCollision(serviceNamespace, apiVersionEnums); - // Only use the full namespace when there is a collision in the // last segment; otherwise, use BuildNameForService with the last segment. - return hasCollision + return ClientHelper.HasLastSegmentCollision(serviceNamespace, _inputEnum, apiVersionEnums) ? $"{serviceNamespace.ToIdentifierName()}{VersionSuffix}" : ClientHelper.BuildNameForService(serviceNamespace, ServicePrefix, VersionSuffix); } @@ -52,21 +50,6 @@ protected override string BuildName() return ApiVersionEnumName; } - private bool HasLastSegmentCollision(string serviceNamespace, List apiVersionEnums) - { - var lastSegment = GetLastNamespaceSegment(serviceNamespace); - return apiVersionEnums.Any(e => - e != _inputEnum && - !string.IsNullOrEmpty(e.Namespace) && - string.Equals(GetLastNamespaceSegment(e.Namespace), lastSegment, StringComparison.OrdinalIgnoreCase)); - } - - private static string GetLastNamespaceSegment(string ns) - { - int lastDot = ns.LastIndexOf('.'); - return lastDot >= 0 ? ns.Substring(lastDot + 1) : ns; - } - protected override FormattableString BuildDescription() => $"{ApiVersionEnumDescription}"; protected override IReadOnlyList BuildEnumValues() diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Shared/ClientHelper.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Shared/ClientHelper.cs index 527959086ec..62fd5551840 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Shared/ClientHelper.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Shared/ClientHelper.cs @@ -2,6 +2,9 @@ // Licensed under the MIT License. using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.TypeSpec.Generator.Input; namespace Microsoft.TypeSpec.Generator.Shared { @@ -35,5 +38,33 @@ public static string BuildNameForService(string serviceName, string prefix, stri (false, false) => $"{prefix}{lastNamespaceSegment}{suffix}" }; } + + /// + /// Extracts the last segment of a dotted namespace. + /// + /// The full namespace (e.g., "Sample.KeyVault"). + /// The last segment (e.g., "KeyVault"), or the input if there is no dot. + public static string GetLastNamespaceSegment(string ns) + { + int lastDot = ns.LastIndexOf('.'); + return lastDot >= 0 ? ns.Substring(lastDot + 1) : ns; + } + + /// + /// Determines whether the last namespace segment of the given service namespace + /// collides with any other enum's last namespace segment in the collection. + /// + /// The namespace to check for collisions. + /// The current enum to exclude from the comparison. + /// All API version enums to compare against. + /// True if another enum has the same last namespace segment. + public static bool HasLastSegmentCollision(string serviceNamespace, InputEnumType currentEnum, IEnumerable apiVersionEnums) + { + var lastSegment = GetLastNamespaceSegment(serviceNamespace); + return apiVersionEnums.Any(e => + e != currentEnum && + !string.IsNullOrEmpty(e.Namespace) && + string.Equals(GetLastNamespaceSegment(e.Namespace), lastSegment, StringComparison.OrdinalIgnoreCase)); + } } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/EnumProviders/ApiVersionEnumProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/EnumProviders/ApiVersionEnumProviderTests.cs index afbd8979764..bde61723da4 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/EnumProviders/ApiVersionEnumProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/EnumProviders/ApiVersionEnumProviderTests.cs @@ -3,6 +3,7 @@ using System.Linq; using Microsoft.TypeSpec.Generator.Input; +using Microsoft.TypeSpec.Generator.Primitives; using Microsoft.TypeSpec.Generator.Providers; using Microsoft.TypeSpec.Generator.Tests.Common; using NUnit.Framework; @@ -249,6 +250,15 @@ public void MultiServiceClient_WithCollidingLastSegments_UsesFullNamespace() // Verify enum names use the full namespace for uniqueness when last segments collide Assert.AreEqual("AzureServiceOneTestsVersion", serviceOneProvider.Name); Assert.AreEqual("AzureServiceTwoTestsVersion", serviceTwoProvider.Name); + + // Validate generated output + var writerOne = new TypeProviderWriter(serviceOneProvider); + var fileOne = writerOne.Write(); + Assert.AreEqual(Helpers.GetExpectedFromFile("ServiceOne"), fileOne.Content); + + var writerTwo = new TypeProviderWriter(serviceTwoProvider); + var fileTwo = writerTwo.Write(); + Assert.AreEqual(Helpers.GetExpectedFromFile("ServiceTwo"), fileTwo.Content); } } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/EnumProviders/TestData/ApiVersionEnumProviderTests/MultiServiceClient_WithCollidingLastSegments_UsesFullNamespace(ServiceOne).cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/EnumProviders/TestData/ApiVersionEnumProviderTests/MultiServiceClient_WithCollidingLastSegments_UsesFullNamespace(ServiceOne).cs new file mode 100644 index 00000000000..4f8c659dd91 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/EnumProviders/TestData/ApiVersionEnumProviderTests/MultiServiceClient_WithCollidingLastSegments_UsesFullNamespace(ServiceOne).cs @@ -0,0 +1,12 @@ +// + +#nullable disable + +namespace Azure.ServiceOne.Tests +{ + public enum AzureServiceOneTestsVersion + { + V1_0 = 1, + V2_0 = 2 + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/EnumProviders/TestData/ApiVersionEnumProviderTests/MultiServiceClient_WithCollidingLastSegments_UsesFullNamespace(ServiceTwo).cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/EnumProviders/TestData/ApiVersionEnumProviderTests/MultiServiceClient_WithCollidingLastSegments_UsesFullNamespace(ServiceTwo).cs new file mode 100644 index 00000000000..eb92b3edda9 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/EnumProviders/TestData/ApiVersionEnumProviderTests/MultiServiceClient_WithCollidingLastSegments_UsesFullNamespace(ServiceTwo).cs @@ -0,0 +1,12 @@ +// + +#nullable disable + +namespace Azure.ServiceTwo.Tests +{ + public enum AzureServiceTwoTestsVersion + { + V3_0 = 1, + V4_0 = 2 + } +} From 10024bc904a519d6d629b4cf0f7b0b44e282bc2e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 19:29:00 +0000 Subject: [PATCH 6/8] refactor: apply collision-aware naming to all multi-service members (enum type, version properties, fields) Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> Agent-Logs-Url: https://github.com/microsoft/typespec/sessions/4bb660ba-ec46-42ad-8074-4e13314801b6 --- .../src/Providers/ClientOptionsProvider.cs | 41 +++++++++++++++---- .../ClientProviders/ClientProviderTests.cs | 8 ++-- ...tiServiceClient_GeneratesExpectedClient.cs | 12 +++--- ...thThreeServices_GeneratesExpectedClient.cs | 18 ++++---- ...eCombinedClient_GeneratesExpectedClient.cs | 8 ++-- ...thThreeServices_GeneratesExpectedClient.cs | 12 +++--- ...binedClient_GeneratesExpectedRestClient.cs | 4 +- ...reeServices_GeneratesExpectedRestClient.cs | 6 +-- ...ceClient_GeneratesExpectedClientOptions.cs | 20 ++++----- ...Services_GeneratesExpectedClientOptions.cs | 38 ++++++++--------- ...edClient_GeneratesExpectedClientOptions.cs | 20 ++++----- ...Services_GeneratesExpectedClientOptions.cs | 38 ++++++++--------- 12 files changed, 124 insertions(+), 101 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs index 975c2492146..d7af600dd76 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientOptionsProvider.cs @@ -12,6 +12,7 @@ using Microsoft.TypeSpec.Generator.Providers; using Microsoft.TypeSpec.Generator.Snippets; using Microsoft.TypeSpec.Generator.Statements; +using Microsoft.TypeSpec.Generator.Shared; using Microsoft.TypeSpec.Generator.Utilities; using static Microsoft.TypeSpec.Generator.Snippets.Snippet; @@ -133,11 +134,21 @@ private static bool UseSingletonInstance(InputClient inputClient) var properties = new Dictionary(_serviceVersionsEnums.Count); foreach (var (inputEnum, enumProvider) in _serviceVersionsEnums) { - // For multi-service clients, use the full namespace to guarantee uniqueness - // (the last segment alone can collide when services share a namespace). - var versionPropertyName = _inputClient.IsMultiServiceClient - ? $"{inputEnum.Namespace.ToIdentifierName()}{ApiVersionSuffix}" - : VersionSuffix; + string versionPropertyName; + if (!_inputClient.IsMultiServiceClient) + { + versionPropertyName = VersionSuffix; + } + else + { + var serviceNamespace = inputEnum.Namespace; + // Use the full namespace only when the last segment collides; + // otherwise, use BuildNameForService for shorter names. + versionPropertyName = !string.IsNullOrEmpty(serviceNamespace) && + ClientHelper.HasLastSegmentCollision(serviceNamespace, inputEnum, _serviceVersionsEnums.Keys) + ? $"{serviceNamespace.ToIdentifierName()}{ApiVersionSuffix}" + : ClientHelper.BuildNameForService(serviceNamespace ?? string.Empty, string.Empty, ApiVersionSuffix); + } var versionProperty = new PropertyProvider( null, @@ -161,11 +172,23 @@ private static bool UseSingletonInstance(InputClient inputClient) } Dictionary latestVersionFields = new(_serviceVersionsEnums.Count); - foreach (var enumProvider in _serviceVersionsEnums.Values) + foreach (var (inputEnum, enumProvider) in _serviceVersionsEnums) { - var fieldName = _inputClient.IsMultiServiceClient - ? $"{LatestPrefix}{enumProvider.Name.ToIdentifierName()}" - : LatestVersionFieldName; + string fieldName; + if (!_inputClient.IsMultiServiceClient) + { + fieldName = LatestVersionFieldName; + } + else + { + var serviceNamespace = inputEnum.Namespace; + // Use the full namespace only when the last segment collides; + // otherwise, use BuildNameForService for shorter names. + fieldName = !string.IsNullOrEmpty(serviceNamespace) && + ClientHelper.HasLastSegmentCollision(serviceNamespace, inputEnum, _serviceVersionsEnums.Keys) + ? $"{LatestPrefix}{serviceNamespace.ToIdentifierName()}{VersionSuffix}" + : ClientHelper.BuildNameForService(serviceNamespace ?? string.Empty, LatestPrefix, VersionSuffix); + } var field = new FieldProvider( modifiers: FieldModifiers.Private | FieldModifiers.Const, type: enumProvider.Type, diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs index 127e1420d06..5276928178a 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs @@ -3678,12 +3678,12 @@ public void GetApiVersionFieldForService_MultiService_ReturnsMatchingField() // Should return the matching field for ServiceA var fieldA = clientProvider!.GetApiVersionFieldForService("Sample.ServiceA"); Assert.IsNotNull(fieldA); - Assert.AreEqual("_sampleServiceAApiVersion", fieldA!.Name); + Assert.AreEqual("_serviceAApiVersion", fieldA!.Name); // Should return the matching field for ServiceB var fieldB = clientProvider.GetApiVersionFieldForService("Sample.ServiceB"); Assert.IsNotNull(fieldB); - Assert.AreEqual("_sampleServiceBApiVersion", fieldB!.Name); + Assert.AreEqual("_serviceBApiVersion", fieldB!.Name); } [Test] @@ -3814,11 +3814,11 @@ public void GetApiVersionFieldForService_MultiService_CaseInsensitiveMatch() // Should match case-insensitively var fieldLowerCase = clientProvider!.GetApiVersionFieldForService("sample.serviceA"); Assert.IsNotNull(fieldLowerCase); - Assert.AreEqual("_sampleServiceAApiVersion", fieldLowerCase!.Name); + Assert.AreEqual("_serviceAApiVersion", fieldLowerCase!.Name); var fieldUpperCase = clientProvider.GetApiVersionFieldForService("SAMPLE.SERVICEa"); Assert.IsNotNull(fieldUpperCase); - Assert.AreEqual("_sampleServiceAApiVersion", fieldUpperCase!.Name); + Assert.AreEqual("_serviceAApiVersion", fieldUpperCase!.Name); } [Test] diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/MultiServiceClient_GeneratesExpectedClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/MultiServiceClient_GeneratesExpectedClient.cs index 1c2e1a29911..7aa404c1406 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/MultiServiceClient_GeneratesExpectedClient.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/MultiServiceClient_GeneratesExpectedClient.cs @@ -14,8 +14,8 @@ public partial class TestClient { private readonly global::System.Uri _endpoint; private readonly string _subscriptionId; - private readonly string _sampleServiceAApiVersion; - private readonly string _sampleServiceBApiVersion; + private readonly string _serviceAApiVersion; + private readonly string _serviceBApiVersion; private global::Sample.ServiceA.ServiceA _cachedServiceA; private global::Sample.ServiceB.ServiceB _cachedServiceB; @@ -44,8 +44,8 @@ internal TestClient(global::System.ClientModel.Primitives.AuthenticationPolicy a { Pipeline = global::System.ClientModel.Primitives.ClientPipeline.Create(options, Array.Empty(), new global::System.ClientModel.Primitives.PipelinePolicy[] { new global::System.ClientModel.Primitives.UserAgentPolicy(typeof(global::Sample.TestClient).Assembly) }, Array.Empty()); } - _sampleServiceAApiVersion = options.SampleServiceAApiVersion; - _sampleServiceBApiVersion = options.SampleServiceBApiVersion; + _serviceAApiVersion = options.ServiceAApiVersion; + _serviceBApiVersion = options.ServiceBApiVersion; } public TestClient(global::System.Uri endpoint, string subscriptionId, global::Sample.TestClientOptions options) : this(null, endpoint, subscriptionId, options) @@ -56,12 +56,12 @@ public TestClient(global::System.Uri endpoint, string subscriptionId, global::Sa public virtual global::Sample.ServiceA.ServiceA GetServiceAClient() { - return (global::System.Threading.Volatile.Read(ref _cachedServiceA) ?? (global::System.Threading.Interlocked.CompareExchange(ref _cachedServiceA, new global::Sample.ServiceA.ServiceA(Pipeline, _endpoint, _sampleServiceAApiVersion, _subscriptionId), null) ?? _cachedServiceA)); + return (global::System.Threading.Volatile.Read(ref _cachedServiceA) ?? (global::System.Threading.Interlocked.CompareExchange(ref _cachedServiceA, new global::Sample.ServiceA.ServiceA(Pipeline, _endpoint, _serviceAApiVersion, _subscriptionId), null) ?? _cachedServiceA)); } public virtual global::Sample.ServiceB.ServiceB GetServiceBClient() { - return (global::System.Threading.Volatile.Read(ref _cachedServiceB) ?? (global::System.Threading.Interlocked.CompareExchange(ref _cachedServiceB, new global::Sample.ServiceB.ServiceB(Pipeline, _endpoint, _sampleServiceBApiVersion, _subscriptionId), null) ?? _cachedServiceB)); + return (global::System.Threading.Volatile.Read(ref _cachedServiceB) ?? (global::System.Threading.Interlocked.CompareExchange(ref _cachedServiceB, new global::Sample.ServiceB.ServiceB(Pipeline, _endpoint, _serviceBApiVersion, _subscriptionId), null) ?? _cachedServiceB)); } } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/MultiServiceClient_WithThreeServices_GeneratesExpectedClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/MultiServiceClient_WithThreeServices_GeneratesExpectedClient.cs index bc0774b1cce..f0dc227b3eb 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/MultiServiceClient_WithThreeServices_GeneratesExpectedClient.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/MultiServiceClient_WithThreeServices_GeneratesExpectedClient.cs @@ -15,9 +15,9 @@ public partial class TestClient { private readonly global::System.Uri _endpoint; private readonly string _subscriptionId; - private readonly string _sampleComputeApiVersion; - private readonly string _sampleKeyVaultApiVersion; - private readonly string _sampleStorageApiVersion; + private readonly string _computeApiVersion; + private readonly string _keyVaultApiVersion; + private readonly string _storageApiVersion; private global::Sample.KeyVault.KeyVault _cachedKeyVault; private global::Sample.Storage.Storage _cachedStorage; private global::Sample.Compute.Compute _cachedCompute; @@ -47,9 +47,9 @@ internal TestClient(global::System.ClientModel.Primitives.AuthenticationPolicy a { Pipeline = global::System.ClientModel.Primitives.ClientPipeline.Create(options, Array.Empty(), new global::System.ClientModel.Primitives.PipelinePolicy[] { new global::System.ClientModel.Primitives.UserAgentPolicy(typeof(global::Sample.TestClient).Assembly) }, Array.Empty()); } - _sampleComputeApiVersion = options.SampleComputeApiVersion; - _sampleKeyVaultApiVersion = options.SampleKeyVaultApiVersion; - _sampleStorageApiVersion = options.SampleStorageApiVersion; + _computeApiVersion = options.ComputeApiVersion; + _keyVaultApiVersion = options.KeyVaultApiVersion; + _storageApiVersion = options.StorageApiVersion; } public TestClient(global::System.Uri endpoint, string subscriptionId, global::Sample.TestClientOptions options) : this(null, endpoint, subscriptionId, options) @@ -60,17 +60,17 @@ public TestClient(global::System.Uri endpoint, string subscriptionId, global::Sa public virtual global::Sample.KeyVault.KeyVault GetKeyVaultClient() { - return (global::System.Threading.Volatile.Read(ref _cachedKeyVault) ?? (global::System.Threading.Interlocked.CompareExchange(ref _cachedKeyVault, new global::Sample.KeyVault.KeyVault(Pipeline, _endpoint, _sampleKeyVaultApiVersion, _subscriptionId), null) ?? _cachedKeyVault)); + return (global::System.Threading.Volatile.Read(ref _cachedKeyVault) ?? (global::System.Threading.Interlocked.CompareExchange(ref _cachedKeyVault, new global::Sample.KeyVault.KeyVault(Pipeline, _endpoint, _keyVaultApiVersion, _subscriptionId), null) ?? _cachedKeyVault)); } public virtual global::Sample.Storage.Storage GetStorageClient() { - return (global::System.Threading.Volatile.Read(ref _cachedStorage) ?? (global::System.Threading.Interlocked.CompareExchange(ref _cachedStorage, new global::Sample.Storage.Storage(Pipeline, _endpoint, _sampleStorageApiVersion, _subscriptionId), null) ?? _cachedStorage)); + return (global::System.Threading.Volatile.Read(ref _cachedStorage) ?? (global::System.Threading.Interlocked.CompareExchange(ref _cachedStorage, new global::Sample.Storage.Storage(Pipeline, _endpoint, _storageApiVersion, _subscriptionId), null) ?? _cachedStorage)); } public virtual global::Sample.Compute.Compute GetComputeClient() { - return (global::System.Threading.Volatile.Read(ref _cachedCompute) ?? (global::System.Threading.Interlocked.CompareExchange(ref _cachedCompute, new global::Sample.Compute.Compute(Pipeline, _endpoint, _sampleComputeApiVersion, _subscriptionId), null) ?? _cachedCompute)); + return (global::System.Threading.Volatile.Read(ref _cachedCompute) ?? (global::System.Threading.Interlocked.CompareExchange(ref _cachedCompute, new global::Sample.Compute.Compute(Pipeline, _endpoint, _computeApiVersion, _subscriptionId), null) ?? _cachedCompute)); } } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/MultiServiceCombinedClient_GeneratesExpectedClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/MultiServiceCombinedClient_GeneratesExpectedClient.cs index cd29a07eb89..56c1c6cf460 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/MultiServiceCombinedClient_GeneratesExpectedClient.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/MultiServiceCombinedClient_GeneratesExpectedClient.cs @@ -13,8 +13,8 @@ namespace Sample public partial class TestClient { private readonly global::System.Uri _endpoint; - private readonly string _sampleServiceAApiVersion; - private readonly string _sampleServiceBApiVersion; + private readonly string _serviceAApiVersion; + private readonly string _serviceBApiVersion; protected TestClient() { @@ -39,8 +39,8 @@ internal TestClient(global::System.ClientModel.Primitives.AuthenticationPolicy a { Pipeline = global::System.ClientModel.Primitives.ClientPipeline.Create(options, Array.Empty(), new global::System.ClientModel.Primitives.PipelinePolicy[] { new global::System.ClientModel.Primitives.UserAgentPolicy(typeof(global::Sample.TestClient).Assembly) }, Array.Empty()); } - _sampleServiceAApiVersion = options.SampleServiceAApiVersion; - _sampleServiceBApiVersion = options.SampleServiceBApiVersion; + _serviceAApiVersion = options.ServiceAApiVersion; + _serviceBApiVersion = options.ServiceBApiVersion; } public TestClient(global::System.Uri endpoint, global::Sample.TestClientOptions options) : this(null, endpoint, options) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedClient.cs index f9684cf2336..7a3f23c4d82 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedClient.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedClient.cs @@ -13,9 +13,9 @@ namespace Sample public partial class TestClient { private readonly global::System.Uri _endpoint; - private readonly string _sampleComputeApiVersion; - private readonly string _sampleKeyVaultApiVersion; - private readonly string _sampleStorageApiVersion; + private readonly string _computeApiVersion; + private readonly string _keyVaultApiVersion; + private readonly string _storageApiVersion; protected TestClient() { @@ -40,9 +40,9 @@ internal TestClient(global::System.ClientModel.Primitives.AuthenticationPolicy a { Pipeline = global::System.ClientModel.Primitives.ClientPipeline.Create(options, Array.Empty(), new global::System.ClientModel.Primitives.PipelinePolicy[] { new global::System.ClientModel.Primitives.UserAgentPolicy(typeof(global::Sample.TestClient).Assembly) }, Array.Empty()); } - _sampleComputeApiVersion = options.SampleComputeApiVersion; - _sampleKeyVaultApiVersion = options.SampleKeyVaultApiVersion; - _sampleStorageApiVersion = options.SampleStorageApiVersion; + _computeApiVersion = options.ComputeApiVersion; + _keyVaultApiVersion = options.KeyVaultApiVersion; + _storageApiVersion = options.StorageApiVersion; } public TestClient(global::System.Uri endpoint, global::Sample.TestClientOptions options) : this(null, endpoint, options) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/MultiServiceCombinedClient_GeneratesExpectedRestClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/MultiServiceCombinedClient_GeneratesExpectedRestClient.cs index a0a9bd218e1..c083bf8f50e 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/MultiServiceCombinedClient_GeneratesExpectedRestClient.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/MultiServiceCombinedClient_GeneratesExpectedRestClient.cs @@ -16,7 +16,7 @@ public partial class TestClient { global::Sample.ClientUriBuilder uri = new global::Sample.ClientUriBuilder(); uri.Reset(_endpoint); - uri.AppendQuery("apiVersion", _sampleServiceAApiVersion, true); + uri.AppendQuery("apiVersion", _serviceAApiVersion, true); global::System.ClientModel.Primitives.PipelineMessage message = Pipeline.CreateMessage(uri.ToUri(), "GET", PipelineMessageClassifier200); global::System.ClientModel.Primitives.PipelineRequest request = message.Request; message.Apply(options); @@ -27,7 +27,7 @@ public partial class TestClient { global::Sample.ClientUriBuilder uri = new global::Sample.ClientUriBuilder(); uri.Reset(_endpoint); - uri.AppendQuery("apiVersion", _sampleServiceBApiVersion, true); + uri.AppendQuery("apiVersion", _serviceBApiVersion, true); global::System.ClientModel.Primitives.PipelineMessage message = Pipeline.CreateMessage(uri.ToUri(), "GET", PipelineMessageClassifier200); global::System.ClientModel.Primitives.PipelineRequest request = message.Request; message.Apply(options); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedRestClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedRestClient.cs index b11b9e12462..15cc22e0e14 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedRestClient.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedRestClient.cs @@ -16,7 +16,7 @@ public partial class TestClient { global::Sample.ClientUriBuilder uri = new global::Sample.ClientUriBuilder(); uri.Reset(_endpoint); - uri.AppendQuery("apiVersion", _sampleKeyVaultApiVersion, true); + uri.AppendQuery("apiVersion", _keyVaultApiVersion, true); global::System.ClientModel.Primitives.PipelineMessage message = Pipeline.CreateMessage(uri.ToUri(), "GET", PipelineMessageClassifier200); global::System.ClientModel.Primitives.PipelineRequest request = message.Request; message.Apply(options); @@ -27,7 +27,7 @@ public partial class TestClient { global::Sample.ClientUriBuilder uri = new global::Sample.ClientUriBuilder(); uri.Reset(_endpoint); - uri.AppendQuery("apiVersion", _sampleStorageApiVersion, true); + uri.AppendQuery("apiVersion", _storageApiVersion, true); global::System.ClientModel.Primitives.PipelineMessage message = Pipeline.CreateMessage(uri.ToUri(), "GET", PipelineMessageClassifier200); global::System.ClientModel.Primitives.PipelineRequest request = message.Request; message.Apply(options); @@ -38,7 +38,7 @@ public partial class TestClient { global::Sample.ClientUriBuilder uri = new global::Sample.ClientUriBuilder(); uri.Reset(_endpoint); - uri.AppendQuery("apiVersion", _sampleComputeApiVersion, true); + uri.AppendQuery("apiVersion", _computeApiVersion, true); global::System.ClientModel.Primitives.PipelineMessage message = Pipeline.CreateMessage(uri.ToUri(), "GET", PipelineMessageClassifier200); global::System.ClientModel.Primitives.PipelineRequest request = message.Request; message.Apply(options); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_GeneratesExpectedClientOptions.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_GeneratesExpectedClientOptions.cs index aea43de4818..1eb960fa71f 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_GeneratesExpectedClientOptions.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_GeneratesExpectedClientOptions.cs @@ -16,13 +16,13 @@ public partial class TestClientOptions : global::System.ClientModel.Primitives.C public TestClientOptions(global::Sample.TestClientOptions.ServiceAVersion serviceAVersion = LatestServiceAVersion, global::Sample.TestClientOptions.ServiceBVersion serviceBVersion = LatestServiceBVersion) { - SampleServiceAApiVersion = serviceAVersion switch + ServiceAApiVersion = serviceAVersion switch { global::Sample.TestClientOptions.ServiceAVersion.V1_0 => "1.0", global::Sample.TestClientOptions.ServiceAVersion.V2_0 => "2.0", _ => throw new global::System.NotSupportedException() }; - SampleServiceBApiVersion = serviceBVersion switch + ServiceBApiVersion = serviceBVersion switch { global::Sample.TestClientOptions.ServiceBVersion.V3_0 => "3.0", global::Sample.TestClientOptions.ServiceBVersion.V4_0 => "4.0", @@ -33,25 +33,25 @@ public TestClientOptions(global::Sample.TestClientOptions.ServiceAVersion servic [global::System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SCME0002")] internal TestClientOptions(global::Microsoft.Extensions.Configuration.IConfigurationSection section) : base(section) { - SampleServiceAApiVersion = "2.0"; - SampleServiceBApiVersion = "4.0"; + ServiceAApiVersion = "2.0"; + ServiceBApiVersion = "4.0"; if (((section is null) || !section.Exists())) { return; } - if ((section["SampleServiceAApiVersion"] is string sampleServiceAApiVersion)) + if ((section["ServiceAApiVersion"] is string serviceAApiVersion)) { - this.SampleServiceAApiVersion = sampleServiceAApiVersion; + this.ServiceAApiVersion = serviceAApiVersion; } - if ((section["SampleServiceBApiVersion"] is string sampleServiceBApiVersion)) + if ((section["ServiceBApiVersion"] is string serviceBApiVersion)) { - this.SampleServiceBApiVersion = sampleServiceBApiVersion; + this.ServiceBApiVersion = serviceBApiVersion; } } - internal string SampleServiceAApiVersion { get; } + internal string ServiceAApiVersion { get; } - internal string SampleServiceBApiVersion { get; } + internal string ServiceBApiVersion { get; } public enum ServiceAVersion { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_WithThreeServices_GeneratesExpectedClientOptions.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_WithThreeServices_GeneratesExpectedClientOptions.cs index ebba2f7aebd..448385c36db 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_WithThreeServices_GeneratesExpectedClientOptions.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_WithThreeServices_GeneratesExpectedClientOptions.cs @@ -11,25 +11,25 @@ namespace Sample { public partial class TestClientOptions : global::System.ClientModel.Primitives.ClientPipelineOptions { - private const global::Sample.TestClientOptions.ServiceComputeVersion LatestServiceComputeVersion = global::Sample.TestClientOptions.ServiceComputeVersion.V2024_07_01; - private const global::Sample.TestClientOptions.ServiceKeyVaultVersion LatestServiceKeyVaultVersion = global::Sample.TestClientOptions.ServiceKeyVaultVersion.V7_5; - private const global::Sample.TestClientOptions.ServiceStorageVersion LatestServiceStorageVersion = global::Sample.TestClientOptions.ServiceStorageVersion.V2024_01_01; + private const global::Sample.TestClientOptions.ServiceComputeVersion LatestComputeVersion = global::Sample.TestClientOptions.ServiceComputeVersion.V2024_07_01; + private const global::Sample.TestClientOptions.ServiceKeyVaultVersion LatestKeyVaultVersion = global::Sample.TestClientOptions.ServiceKeyVaultVersion.V7_5; + private const global::Sample.TestClientOptions.ServiceStorageVersion LatestStorageVersion = global::Sample.TestClientOptions.ServiceStorageVersion.V2024_01_01; - public TestClientOptions(global::Sample.TestClientOptions.ServiceKeyVaultVersion serviceKeyVaultVersion = LatestServiceKeyVaultVersion, global::Sample.TestClientOptions.ServiceStorageVersion serviceStorageVersion = LatestServiceStorageVersion, global::Sample.TestClientOptions.ServiceComputeVersion serviceComputeVersion = LatestServiceComputeVersion) + public TestClientOptions(global::Sample.TestClientOptions.ServiceKeyVaultVersion serviceKeyVaultVersion = LatestKeyVaultVersion, global::Sample.TestClientOptions.ServiceStorageVersion serviceStorageVersion = LatestStorageVersion, global::Sample.TestClientOptions.ServiceComputeVersion serviceComputeVersion = LatestComputeVersion) { - SampleKeyVaultApiVersion = serviceKeyVaultVersion switch + KeyVaultApiVersion = serviceKeyVaultVersion switch { global::Sample.TestClientOptions.ServiceKeyVaultVersion.V7_4 => "7.4", global::Sample.TestClientOptions.ServiceKeyVaultVersion.V7_5 => "7.5", _ => throw new global::System.NotSupportedException() }; - SampleStorageApiVersion = serviceStorageVersion switch + StorageApiVersion = serviceStorageVersion switch { global::Sample.TestClientOptions.ServiceStorageVersion.V2023_01_01 => "2023-01-01", global::Sample.TestClientOptions.ServiceStorageVersion.V2024_01_01 => "2024-01-01", _ => throw new global::System.NotSupportedException() }; - SampleComputeApiVersion = serviceComputeVersion switch + ComputeApiVersion = serviceComputeVersion switch { global::Sample.TestClientOptions.ServiceComputeVersion.V2023_07_01 => "2023-07-01", global::Sample.TestClientOptions.ServiceComputeVersion.V2024_03_01 => "2024-03-01", @@ -41,32 +41,32 @@ public TestClientOptions(global::Sample.TestClientOptions.ServiceKeyVaultVersion [global::System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SCME0002")] internal TestClientOptions(global::Microsoft.Extensions.Configuration.IConfigurationSection section) : base(section) { - SampleComputeApiVersion = "2024-07-01"; - SampleKeyVaultApiVersion = "7.5"; - SampleStorageApiVersion = "2024-01-01"; + ComputeApiVersion = "2024-07-01"; + KeyVaultApiVersion = "7.5"; + StorageApiVersion = "2024-01-01"; if (((section is null) || !section.Exists())) { return; } - if ((section["SampleComputeApiVersion"] is string sampleComputeApiVersion)) + if ((section["ComputeApiVersion"] is string computeApiVersion)) { - this.SampleComputeApiVersion = sampleComputeApiVersion; + this.ComputeApiVersion = computeApiVersion; } - if ((section["SampleKeyVaultApiVersion"] is string sampleKeyVaultApiVersion)) + if ((section["KeyVaultApiVersion"] is string keyVaultApiVersion)) { - this.SampleKeyVaultApiVersion = sampleKeyVaultApiVersion; + this.KeyVaultApiVersion = keyVaultApiVersion; } - if ((section["SampleStorageApiVersion"] is string sampleStorageApiVersion)) + if ((section["StorageApiVersion"] is string storageApiVersion)) { - this.SampleStorageApiVersion = sampleStorageApiVersion; + this.StorageApiVersion = storageApiVersion; } } - internal string SampleComputeApiVersion { get; } + internal string ComputeApiVersion { get; } - internal string SampleKeyVaultApiVersion { get; } + internal string KeyVaultApiVersion { get; } - internal string SampleStorageApiVersion { get; } + internal string StorageApiVersion { get; } public enum ServiceComputeVersion { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_GeneratesExpectedClientOptions.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_GeneratesExpectedClientOptions.cs index aea43de4818..1eb960fa71f 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_GeneratesExpectedClientOptions.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_GeneratesExpectedClientOptions.cs @@ -16,13 +16,13 @@ public partial class TestClientOptions : global::System.ClientModel.Primitives.C public TestClientOptions(global::Sample.TestClientOptions.ServiceAVersion serviceAVersion = LatestServiceAVersion, global::Sample.TestClientOptions.ServiceBVersion serviceBVersion = LatestServiceBVersion) { - SampleServiceAApiVersion = serviceAVersion switch + ServiceAApiVersion = serviceAVersion switch { global::Sample.TestClientOptions.ServiceAVersion.V1_0 => "1.0", global::Sample.TestClientOptions.ServiceAVersion.V2_0 => "2.0", _ => throw new global::System.NotSupportedException() }; - SampleServiceBApiVersion = serviceBVersion switch + ServiceBApiVersion = serviceBVersion switch { global::Sample.TestClientOptions.ServiceBVersion.V3_0 => "3.0", global::Sample.TestClientOptions.ServiceBVersion.V4_0 => "4.0", @@ -33,25 +33,25 @@ public TestClientOptions(global::Sample.TestClientOptions.ServiceAVersion servic [global::System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SCME0002")] internal TestClientOptions(global::Microsoft.Extensions.Configuration.IConfigurationSection section) : base(section) { - SampleServiceAApiVersion = "2.0"; - SampleServiceBApiVersion = "4.0"; + ServiceAApiVersion = "2.0"; + ServiceBApiVersion = "4.0"; if (((section is null) || !section.Exists())) { return; } - if ((section["SampleServiceAApiVersion"] is string sampleServiceAApiVersion)) + if ((section["ServiceAApiVersion"] is string serviceAApiVersion)) { - this.SampleServiceAApiVersion = sampleServiceAApiVersion; + this.ServiceAApiVersion = serviceAApiVersion; } - if ((section["SampleServiceBApiVersion"] is string sampleServiceBApiVersion)) + if ((section["ServiceBApiVersion"] is string serviceBApiVersion)) { - this.SampleServiceBApiVersion = sampleServiceBApiVersion; + this.ServiceBApiVersion = serviceBApiVersion; } } - internal string SampleServiceAApiVersion { get; } + internal string ServiceAApiVersion { get; } - internal string SampleServiceBApiVersion { get; } + internal string ServiceBApiVersion { get; } public enum ServiceAVersion { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedClientOptions.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedClientOptions.cs index ebba2f7aebd..448385c36db 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedClientOptions.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedClientOptions.cs @@ -11,25 +11,25 @@ namespace Sample { public partial class TestClientOptions : global::System.ClientModel.Primitives.ClientPipelineOptions { - private const global::Sample.TestClientOptions.ServiceComputeVersion LatestServiceComputeVersion = global::Sample.TestClientOptions.ServiceComputeVersion.V2024_07_01; - private const global::Sample.TestClientOptions.ServiceKeyVaultVersion LatestServiceKeyVaultVersion = global::Sample.TestClientOptions.ServiceKeyVaultVersion.V7_5; - private const global::Sample.TestClientOptions.ServiceStorageVersion LatestServiceStorageVersion = global::Sample.TestClientOptions.ServiceStorageVersion.V2024_01_01; + private const global::Sample.TestClientOptions.ServiceComputeVersion LatestComputeVersion = global::Sample.TestClientOptions.ServiceComputeVersion.V2024_07_01; + private const global::Sample.TestClientOptions.ServiceKeyVaultVersion LatestKeyVaultVersion = global::Sample.TestClientOptions.ServiceKeyVaultVersion.V7_5; + private const global::Sample.TestClientOptions.ServiceStorageVersion LatestStorageVersion = global::Sample.TestClientOptions.ServiceStorageVersion.V2024_01_01; - public TestClientOptions(global::Sample.TestClientOptions.ServiceKeyVaultVersion serviceKeyVaultVersion = LatestServiceKeyVaultVersion, global::Sample.TestClientOptions.ServiceStorageVersion serviceStorageVersion = LatestServiceStorageVersion, global::Sample.TestClientOptions.ServiceComputeVersion serviceComputeVersion = LatestServiceComputeVersion) + public TestClientOptions(global::Sample.TestClientOptions.ServiceKeyVaultVersion serviceKeyVaultVersion = LatestKeyVaultVersion, global::Sample.TestClientOptions.ServiceStorageVersion serviceStorageVersion = LatestStorageVersion, global::Sample.TestClientOptions.ServiceComputeVersion serviceComputeVersion = LatestComputeVersion) { - SampleKeyVaultApiVersion = serviceKeyVaultVersion switch + KeyVaultApiVersion = serviceKeyVaultVersion switch { global::Sample.TestClientOptions.ServiceKeyVaultVersion.V7_4 => "7.4", global::Sample.TestClientOptions.ServiceKeyVaultVersion.V7_5 => "7.5", _ => throw new global::System.NotSupportedException() }; - SampleStorageApiVersion = serviceStorageVersion switch + StorageApiVersion = serviceStorageVersion switch { global::Sample.TestClientOptions.ServiceStorageVersion.V2023_01_01 => "2023-01-01", global::Sample.TestClientOptions.ServiceStorageVersion.V2024_01_01 => "2024-01-01", _ => throw new global::System.NotSupportedException() }; - SampleComputeApiVersion = serviceComputeVersion switch + ComputeApiVersion = serviceComputeVersion switch { global::Sample.TestClientOptions.ServiceComputeVersion.V2023_07_01 => "2023-07-01", global::Sample.TestClientOptions.ServiceComputeVersion.V2024_03_01 => "2024-03-01", @@ -41,32 +41,32 @@ public TestClientOptions(global::Sample.TestClientOptions.ServiceKeyVaultVersion [global::System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SCME0002")] internal TestClientOptions(global::Microsoft.Extensions.Configuration.IConfigurationSection section) : base(section) { - SampleComputeApiVersion = "2024-07-01"; - SampleKeyVaultApiVersion = "7.5"; - SampleStorageApiVersion = "2024-01-01"; + ComputeApiVersion = "2024-07-01"; + KeyVaultApiVersion = "7.5"; + StorageApiVersion = "2024-01-01"; if (((section is null) || !section.Exists())) { return; } - if ((section["SampleComputeApiVersion"] is string sampleComputeApiVersion)) + if ((section["ComputeApiVersion"] is string computeApiVersion)) { - this.SampleComputeApiVersion = sampleComputeApiVersion; + this.ComputeApiVersion = computeApiVersion; } - if ((section["SampleKeyVaultApiVersion"] is string sampleKeyVaultApiVersion)) + if ((section["KeyVaultApiVersion"] is string keyVaultApiVersion)) { - this.SampleKeyVaultApiVersion = sampleKeyVaultApiVersion; + this.KeyVaultApiVersion = keyVaultApiVersion; } - if ((section["SampleStorageApiVersion"] is string sampleStorageApiVersion)) + if ((section["StorageApiVersion"] is string storageApiVersion)) { - this.SampleStorageApiVersion = sampleStorageApiVersion; + this.StorageApiVersion = storageApiVersion; } } - internal string SampleComputeApiVersion { get; } + internal string ComputeApiVersion { get; } - internal string SampleKeyVaultApiVersion { get; } + internal string KeyVaultApiVersion { get; } - internal string SampleStorageApiVersion { get; } + internal string StorageApiVersion { get; } public enum ServiceComputeVersion { From e81dc128504714e0b76d591a40ec0f33d84517e0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 20:04:48 +0000 Subject: [PATCH 7/8] test: add TestData validation to MultiServiceClient_SameLastSegment_ProducesUniqueVersionEnums Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> Agent-Logs-Url: https://github.com/microsoft/typespec/sessions/d68247ba-74e0-495e-9cd6-961dcb2cd21b --- .../Providers/ClientOptionsProviderTests.cs | 5 ++ ...eLastSegment_ProducesUniqueVersionEnums.cs | 68 +++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_SameLastSegment_ProducesUniqueVersionEnums.cs diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientOptionsProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientOptionsProviderTests.cs index f65378c270f..ec41b410935 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientOptionsProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientOptionsProviderTests.cs @@ -752,6 +752,11 @@ public void MultiServiceClient_SameLastSegment_ProducesUniqueVersionEnums() var nestedTypes = clientOptionsProvider!.NestedTypes; Assert.AreEqual(2, nestedTypes.Count); CollectionAssert.AllItemsAreUnique(nestedTypes.Select(t => t.Name).ToList()); + + var writer = new TypeProviderWriter(clientOptionsProvider!); + var file = writer.Write(); + + Assert.AreEqual(Helpers.GetExpectedFromFile(), file.Content); } [Test] diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_SameLastSegment_ProducesUniqueVersionEnums.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_SameLastSegment_ProducesUniqueVersionEnums.cs new file mode 100644 index 00000000000..5e24fd80aa3 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_SameLastSegment_ProducesUniqueVersionEnums.cs @@ -0,0 +1,68 @@ +// + +#nullable disable + +using System; +using System.ClientModel.Primitives; +using System.Diagnostics.CodeAnalysis; +using Microsoft.Extensions.Configuration; + +namespace Sample +{ + public partial class TestClientOptions : global::System.ClientModel.Primitives.ClientPipelineOptions + { + private const global::Sample.TestClientOptions.AzureServiceOneTestsVersion LatestAzureServiceOneTestsVersion = global::Sample.TestClientOptions.AzureServiceOneTestsVersion.V2_0; + private const global::Sample.TestClientOptions.AzureServiceTwoTestsVersion LatestAzureServiceTwoTestsVersion = global::Sample.TestClientOptions.AzureServiceTwoTestsVersion.V4_0; + + public TestClientOptions(global::Sample.TestClientOptions.AzureServiceOneTestsVersion azureServiceOneTestsVersion = LatestAzureServiceOneTestsVersion, global::Sample.TestClientOptions.AzureServiceTwoTestsVersion azureServiceTwoTestsVersion = LatestAzureServiceTwoTestsVersion) + { + AzureServiceOneTestsApiVersion = azureServiceOneTestsVersion switch + { + global::Sample.TestClientOptions.AzureServiceOneTestsVersion.V1_0 => "1.0", + global::Sample.TestClientOptions.AzureServiceOneTestsVersion.V2_0 => "2.0", + _ => throw new global::System.NotSupportedException() + }; + AzureServiceTwoTestsApiVersion = azureServiceTwoTestsVersion switch + { + global::Sample.TestClientOptions.AzureServiceTwoTestsVersion.V3_0 => "3.0", + global::Sample.TestClientOptions.AzureServiceTwoTestsVersion.V4_0 => "4.0", + _ => throw new global::System.NotSupportedException() + }; + } + + [global::System.Diagnostics.CodeAnalysis.ExperimentalAttribute("SCME0002")] + internal TestClientOptions(global::Microsoft.Extensions.Configuration.IConfigurationSection section) : base(section) + { + AzureServiceOneTestsApiVersion = "2.0"; + AzureServiceTwoTestsApiVersion = "4.0"; + if (((section is null) || !section.Exists())) + { + return; + } + if ((section["AzureServiceOneTestsApiVersion"] is string azureServiceOneTestsApiVersion)) + { + this.AzureServiceOneTestsApiVersion = azureServiceOneTestsApiVersion; + } + if ((section["AzureServiceTwoTestsApiVersion"] is string azureServiceTwoTestsApiVersion)) + { + this.AzureServiceTwoTestsApiVersion = azureServiceTwoTestsApiVersion; + } + } + + internal string AzureServiceOneTestsApiVersion { get; } + + internal string AzureServiceTwoTestsApiVersion { get; } + + public enum AzureServiceOneTestsVersion + { + V1_0 = 1, + V2_0 = 2 + } + + public enum AzureServiceTwoTestsVersion + { + V3_0 = 1, + V4_0 = 2 + } + } +} From 352b1dad9cd6512b130bfbe4d174b1fa92104366 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 20:32:28 +0000 Subject: [PATCH 8/8] refactor: change multi-service enum naming from ServiceXVersion to XServiceVersion Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> Agent-Logs-Url: https://github.com/microsoft/typespec/sessions/1abc462d-6e01-4045-857d-007426a4d797 --- ...ceClient_GeneratesExpectedClientOptions.cs | 22 ++++++------ ...Services_GeneratesExpectedClientOptions.cs | 34 +++++++++---------- ...edClient_GeneratesExpectedClientOptions.cs | 22 ++++++------ ...Services_GeneratesExpectedClientOptions.cs | 34 +++++++++---------- .../src/Providers/ApiVersionEnumProvider.cs | 2 +- .../ApiVersionEnumProviderTests.cs | 4 +-- 6 files changed, 59 insertions(+), 59 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_GeneratesExpectedClientOptions.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_GeneratesExpectedClientOptions.cs index 1eb960fa71f..cbb435387e8 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_GeneratesExpectedClientOptions.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_GeneratesExpectedClientOptions.cs @@ -11,21 +11,21 @@ namespace Sample { public partial class TestClientOptions : global::System.ClientModel.Primitives.ClientPipelineOptions { - private const global::Sample.TestClientOptions.ServiceAVersion LatestServiceAVersion = global::Sample.TestClientOptions.ServiceAVersion.V2_0; - private const global::Sample.TestClientOptions.ServiceBVersion LatestServiceBVersion = global::Sample.TestClientOptions.ServiceBVersion.V4_0; + private const global::Sample.TestClientOptions.ServiceAServiceVersion LatestServiceAVersion = global::Sample.TestClientOptions.ServiceAServiceVersion.V2_0; + private const global::Sample.TestClientOptions.ServiceBServiceVersion LatestServiceBVersion = global::Sample.TestClientOptions.ServiceBServiceVersion.V4_0; - public TestClientOptions(global::Sample.TestClientOptions.ServiceAVersion serviceAVersion = LatestServiceAVersion, global::Sample.TestClientOptions.ServiceBVersion serviceBVersion = LatestServiceBVersion) + public TestClientOptions(global::Sample.TestClientOptions.ServiceAServiceVersion serviceAServiceVersion = LatestServiceAVersion, global::Sample.TestClientOptions.ServiceBServiceVersion serviceBServiceVersion = LatestServiceBVersion) { - ServiceAApiVersion = serviceAVersion switch + ServiceAApiVersion = serviceAServiceVersion switch { - global::Sample.TestClientOptions.ServiceAVersion.V1_0 => "1.0", - global::Sample.TestClientOptions.ServiceAVersion.V2_0 => "2.0", + global::Sample.TestClientOptions.ServiceAServiceVersion.V1_0 => "1.0", + global::Sample.TestClientOptions.ServiceAServiceVersion.V2_0 => "2.0", _ => throw new global::System.NotSupportedException() }; - ServiceBApiVersion = serviceBVersion switch + ServiceBApiVersion = serviceBServiceVersion switch { - global::Sample.TestClientOptions.ServiceBVersion.V3_0 => "3.0", - global::Sample.TestClientOptions.ServiceBVersion.V4_0 => "4.0", + global::Sample.TestClientOptions.ServiceBServiceVersion.V3_0 => "3.0", + global::Sample.TestClientOptions.ServiceBServiceVersion.V4_0 => "4.0", _ => throw new global::System.NotSupportedException() }; } @@ -53,13 +53,13 @@ internal TestClientOptions(global::Microsoft.Extensions.Configuration.IConfigura internal string ServiceBApiVersion { get; } - public enum ServiceAVersion + public enum ServiceAServiceVersion { V1_0 = 1, V2_0 = 2 } - public enum ServiceBVersion + public enum ServiceBServiceVersion { V3_0 = 1, V4_0 = 2 diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_WithThreeServices_GeneratesExpectedClientOptions.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_WithThreeServices_GeneratesExpectedClientOptions.cs index 448385c36db..37011ea3530 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_WithThreeServices_GeneratesExpectedClientOptions.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceClient_WithThreeServices_GeneratesExpectedClientOptions.cs @@ -11,29 +11,29 @@ namespace Sample { public partial class TestClientOptions : global::System.ClientModel.Primitives.ClientPipelineOptions { - private const global::Sample.TestClientOptions.ServiceComputeVersion LatestComputeVersion = global::Sample.TestClientOptions.ServiceComputeVersion.V2024_07_01; - private const global::Sample.TestClientOptions.ServiceKeyVaultVersion LatestKeyVaultVersion = global::Sample.TestClientOptions.ServiceKeyVaultVersion.V7_5; - private const global::Sample.TestClientOptions.ServiceStorageVersion LatestStorageVersion = global::Sample.TestClientOptions.ServiceStorageVersion.V2024_01_01; + private const global::Sample.TestClientOptions.ComputeServiceVersion LatestComputeVersion = global::Sample.TestClientOptions.ComputeServiceVersion.V2024_07_01; + private const global::Sample.TestClientOptions.KeyVaultServiceVersion LatestKeyVaultVersion = global::Sample.TestClientOptions.KeyVaultServiceVersion.V7_5; + private const global::Sample.TestClientOptions.StorageServiceVersion LatestStorageVersion = global::Sample.TestClientOptions.StorageServiceVersion.V2024_01_01; - public TestClientOptions(global::Sample.TestClientOptions.ServiceKeyVaultVersion serviceKeyVaultVersion = LatestKeyVaultVersion, global::Sample.TestClientOptions.ServiceStorageVersion serviceStorageVersion = LatestStorageVersion, global::Sample.TestClientOptions.ServiceComputeVersion serviceComputeVersion = LatestComputeVersion) + public TestClientOptions(global::Sample.TestClientOptions.KeyVaultServiceVersion keyVaultServiceVersion = LatestKeyVaultVersion, global::Sample.TestClientOptions.StorageServiceVersion storageServiceVersion = LatestStorageVersion, global::Sample.TestClientOptions.ComputeServiceVersion computeServiceVersion = LatestComputeVersion) { - KeyVaultApiVersion = serviceKeyVaultVersion switch + KeyVaultApiVersion = keyVaultServiceVersion switch { - global::Sample.TestClientOptions.ServiceKeyVaultVersion.V7_4 => "7.4", - global::Sample.TestClientOptions.ServiceKeyVaultVersion.V7_5 => "7.5", + global::Sample.TestClientOptions.KeyVaultServiceVersion.V7_4 => "7.4", + global::Sample.TestClientOptions.KeyVaultServiceVersion.V7_5 => "7.5", _ => throw new global::System.NotSupportedException() }; - StorageApiVersion = serviceStorageVersion switch + StorageApiVersion = storageServiceVersion switch { - global::Sample.TestClientOptions.ServiceStorageVersion.V2023_01_01 => "2023-01-01", - global::Sample.TestClientOptions.ServiceStorageVersion.V2024_01_01 => "2024-01-01", + global::Sample.TestClientOptions.StorageServiceVersion.V2023_01_01 => "2023-01-01", + global::Sample.TestClientOptions.StorageServiceVersion.V2024_01_01 => "2024-01-01", _ => throw new global::System.NotSupportedException() }; - ComputeApiVersion = serviceComputeVersion switch + ComputeApiVersion = computeServiceVersion switch { - global::Sample.TestClientOptions.ServiceComputeVersion.V2023_07_01 => "2023-07-01", - global::Sample.TestClientOptions.ServiceComputeVersion.V2024_03_01 => "2024-03-01", - global::Sample.TestClientOptions.ServiceComputeVersion.V2024_07_01 => "2024-07-01", + global::Sample.TestClientOptions.ComputeServiceVersion.V2023_07_01 => "2023-07-01", + global::Sample.TestClientOptions.ComputeServiceVersion.V2024_03_01 => "2024-03-01", + global::Sample.TestClientOptions.ComputeServiceVersion.V2024_07_01 => "2024-07-01", _ => throw new global::System.NotSupportedException() }; } @@ -68,20 +68,20 @@ internal TestClientOptions(global::Microsoft.Extensions.Configuration.IConfigura internal string StorageApiVersion { get; } - public enum ServiceComputeVersion + public enum ComputeServiceVersion { V2023_07_01 = 1, V2024_03_01 = 2, V2024_07_01 = 3 } - public enum ServiceKeyVaultVersion + public enum KeyVaultServiceVersion { V7_4 = 1, V7_5 = 2 } - public enum ServiceStorageVersion + public enum StorageServiceVersion { V2023_01_01 = 1, V2024_01_01 = 2 diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_GeneratesExpectedClientOptions.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_GeneratesExpectedClientOptions.cs index 1eb960fa71f..cbb435387e8 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_GeneratesExpectedClientOptions.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_GeneratesExpectedClientOptions.cs @@ -11,21 +11,21 @@ namespace Sample { public partial class TestClientOptions : global::System.ClientModel.Primitives.ClientPipelineOptions { - private const global::Sample.TestClientOptions.ServiceAVersion LatestServiceAVersion = global::Sample.TestClientOptions.ServiceAVersion.V2_0; - private const global::Sample.TestClientOptions.ServiceBVersion LatestServiceBVersion = global::Sample.TestClientOptions.ServiceBVersion.V4_0; + private const global::Sample.TestClientOptions.ServiceAServiceVersion LatestServiceAVersion = global::Sample.TestClientOptions.ServiceAServiceVersion.V2_0; + private const global::Sample.TestClientOptions.ServiceBServiceVersion LatestServiceBVersion = global::Sample.TestClientOptions.ServiceBServiceVersion.V4_0; - public TestClientOptions(global::Sample.TestClientOptions.ServiceAVersion serviceAVersion = LatestServiceAVersion, global::Sample.TestClientOptions.ServiceBVersion serviceBVersion = LatestServiceBVersion) + public TestClientOptions(global::Sample.TestClientOptions.ServiceAServiceVersion serviceAServiceVersion = LatestServiceAVersion, global::Sample.TestClientOptions.ServiceBServiceVersion serviceBServiceVersion = LatestServiceBVersion) { - ServiceAApiVersion = serviceAVersion switch + ServiceAApiVersion = serviceAServiceVersion switch { - global::Sample.TestClientOptions.ServiceAVersion.V1_0 => "1.0", - global::Sample.TestClientOptions.ServiceAVersion.V2_0 => "2.0", + global::Sample.TestClientOptions.ServiceAServiceVersion.V1_0 => "1.0", + global::Sample.TestClientOptions.ServiceAServiceVersion.V2_0 => "2.0", _ => throw new global::System.NotSupportedException() }; - ServiceBApiVersion = serviceBVersion switch + ServiceBApiVersion = serviceBServiceVersion switch { - global::Sample.TestClientOptions.ServiceBVersion.V3_0 => "3.0", - global::Sample.TestClientOptions.ServiceBVersion.V4_0 => "4.0", + global::Sample.TestClientOptions.ServiceBServiceVersion.V3_0 => "3.0", + global::Sample.TestClientOptions.ServiceBServiceVersion.V4_0 => "4.0", _ => throw new global::System.NotSupportedException() }; } @@ -53,13 +53,13 @@ internal TestClientOptions(global::Microsoft.Extensions.Configuration.IConfigura internal string ServiceBApiVersion { get; } - public enum ServiceAVersion + public enum ServiceAServiceVersion { V1_0 = 1, V2_0 = 2 } - public enum ServiceBVersion + public enum ServiceBServiceVersion { V3_0 = 1, V4_0 = 2 diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedClientOptions.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedClientOptions.cs index 448385c36db..37011ea3530 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedClientOptions.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ClientOptionsProviderTests/MultiServiceCombinedClient_WithThreeServices_GeneratesExpectedClientOptions.cs @@ -11,29 +11,29 @@ namespace Sample { public partial class TestClientOptions : global::System.ClientModel.Primitives.ClientPipelineOptions { - private const global::Sample.TestClientOptions.ServiceComputeVersion LatestComputeVersion = global::Sample.TestClientOptions.ServiceComputeVersion.V2024_07_01; - private const global::Sample.TestClientOptions.ServiceKeyVaultVersion LatestKeyVaultVersion = global::Sample.TestClientOptions.ServiceKeyVaultVersion.V7_5; - private const global::Sample.TestClientOptions.ServiceStorageVersion LatestStorageVersion = global::Sample.TestClientOptions.ServiceStorageVersion.V2024_01_01; + private const global::Sample.TestClientOptions.ComputeServiceVersion LatestComputeVersion = global::Sample.TestClientOptions.ComputeServiceVersion.V2024_07_01; + private const global::Sample.TestClientOptions.KeyVaultServiceVersion LatestKeyVaultVersion = global::Sample.TestClientOptions.KeyVaultServiceVersion.V7_5; + private const global::Sample.TestClientOptions.StorageServiceVersion LatestStorageVersion = global::Sample.TestClientOptions.StorageServiceVersion.V2024_01_01; - public TestClientOptions(global::Sample.TestClientOptions.ServiceKeyVaultVersion serviceKeyVaultVersion = LatestKeyVaultVersion, global::Sample.TestClientOptions.ServiceStorageVersion serviceStorageVersion = LatestStorageVersion, global::Sample.TestClientOptions.ServiceComputeVersion serviceComputeVersion = LatestComputeVersion) + public TestClientOptions(global::Sample.TestClientOptions.KeyVaultServiceVersion keyVaultServiceVersion = LatestKeyVaultVersion, global::Sample.TestClientOptions.StorageServiceVersion storageServiceVersion = LatestStorageVersion, global::Sample.TestClientOptions.ComputeServiceVersion computeServiceVersion = LatestComputeVersion) { - KeyVaultApiVersion = serviceKeyVaultVersion switch + KeyVaultApiVersion = keyVaultServiceVersion switch { - global::Sample.TestClientOptions.ServiceKeyVaultVersion.V7_4 => "7.4", - global::Sample.TestClientOptions.ServiceKeyVaultVersion.V7_5 => "7.5", + global::Sample.TestClientOptions.KeyVaultServiceVersion.V7_4 => "7.4", + global::Sample.TestClientOptions.KeyVaultServiceVersion.V7_5 => "7.5", _ => throw new global::System.NotSupportedException() }; - StorageApiVersion = serviceStorageVersion switch + StorageApiVersion = storageServiceVersion switch { - global::Sample.TestClientOptions.ServiceStorageVersion.V2023_01_01 => "2023-01-01", - global::Sample.TestClientOptions.ServiceStorageVersion.V2024_01_01 => "2024-01-01", + global::Sample.TestClientOptions.StorageServiceVersion.V2023_01_01 => "2023-01-01", + global::Sample.TestClientOptions.StorageServiceVersion.V2024_01_01 => "2024-01-01", _ => throw new global::System.NotSupportedException() }; - ComputeApiVersion = serviceComputeVersion switch + ComputeApiVersion = computeServiceVersion switch { - global::Sample.TestClientOptions.ServiceComputeVersion.V2023_07_01 => "2023-07-01", - global::Sample.TestClientOptions.ServiceComputeVersion.V2024_03_01 => "2024-03-01", - global::Sample.TestClientOptions.ServiceComputeVersion.V2024_07_01 => "2024-07-01", + global::Sample.TestClientOptions.ComputeServiceVersion.V2023_07_01 => "2023-07-01", + global::Sample.TestClientOptions.ComputeServiceVersion.V2024_03_01 => "2024-03-01", + global::Sample.TestClientOptions.ComputeServiceVersion.V2024_07_01 => "2024-07-01", _ => throw new global::System.NotSupportedException() }; } @@ -68,20 +68,20 @@ internal TestClientOptions(global::Microsoft.Extensions.Configuration.IConfigura internal string StorageApiVersion { get; } - public enum ServiceComputeVersion + public enum ComputeServiceVersion { V2023_07_01 = 1, V2024_03_01 = 2, V2024_07_01 = 3 } - public enum ServiceKeyVaultVersion + public enum KeyVaultServiceVersion { V7_4 = 1, V7_5 = 2 } - public enum ServiceStorageVersion + public enum StorageServiceVersion { V2023_01_01 = 1, V2024_01_01 = 2 diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ApiVersionEnumProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ApiVersionEnumProvider.cs index cbcc6cd648e..47ef2e2b96a 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ApiVersionEnumProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ApiVersionEnumProvider.cs @@ -43,7 +43,7 @@ protected override string BuildName() // last segment; otherwise, use BuildNameForService with the last segment. return ClientHelper.HasLastSegmentCollision(serviceNamespace, _inputEnum, apiVersionEnums) ? $"{serviceNamespace.ToIdentifierName()}{VersionSuffix}" - : ClientHelper.BuildNameForService(serviceNamespace, ServicePrefix, VersionSuffix); + : ClientHelper.BuildNameForService(serviceNamespace, string.Empty, ApiVersionEnumName); } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/EnumProviders/ApiVersionEnumProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/EnumProviders/ApiVersionEnumProviderTests.cs index bde61723da4..5688137d9fd 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/EnumProviders/ApiVersionEnumProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/EnumProviders/ApiVersionEnumProviderTests.cs @@ -180,8 +180,8 @@ public void MultiServiceClient_WithMultipleApiVersionEnums_GeneratesCorrectEnumN var storageProvider = (ApiVersionEnumProvider)storageEnumType; // Verify enum names use BuildNameForService when there are no collisions - Assert.AreEqual("ServiceKeyVaultVersion", keyVaultProvider.Name); - Assert.AreEqual("ServiceStorageVersion", storageProvider.Name); + Assert.AreEqual("KeyVaultServiceVersion", keyVaultProvider.Name); + Assert.AreEqual("StorageServiceVersion", storageProvider.Name); } [Test]