From 43847f127a480ed52f1be0f71f153ddc92e0380a Mon Sep 17 00:00:00 2001 From: Dapeng Zhang Date: Mon, 2 Dec 2024 17:41:42 +0800 Subject: [PATCH 01/22] refactor test cases --- .../ApiKeyAuthClientProviderTests.cs | 457 +++++++++++++++ .../ClientProviders/ClientProviderTests.cs | 534 ++---------------- 2 files changed, 509 insertions(+), 482 deletions(-) create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ApiKeyAuthClientProviderTests.cs diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ApiKeyAuthClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ApiKeyAuthClientProviderTests.cs new file mode 100644 index 0000000000..5ff013dc82 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ApiKeyAuthClientProviderTests.cs @@ -0,0 +1,457 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Generator.CSharp.ClientModel.Providers; +using Microsoft.Generator.CSharp.Expressions; +using Microsoft.Generator.CSharp.Input; +using Microsoft.Generator.CSharp.Primitives; +using Microsoft.Generator.CSharp.Providers; +using Microsoft.Generator.CSharp.Snippets; +using Microsoft.Generator.CSharp.Statements; +using Microsoft.Generator.CSharp.Tests.Common; +using NUnit.Framework; +using static Microsoft.Generator.CSharp.Snippets.Snippet; + +namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders +{ + public class ApiKeyAuthClientProviderTests + { + private const string SubClientsCategory = "WithSubClients"; + private const string TestClientName = "TestClient"; + private static readonly InputClient _animalClient = new("animal", "AnimalClient description", [], [], TestClientName); + private static readonly InputClient _dogClient = new("dog", "DogClient description", [], [], _animalClient.Name); + private static readonly InputClient _huskyClient = new("husky", "HuskyClient description", [], [], _dogClient.Name); + + [SetUp] + public void SetUp() + { + var categories = TestContext.CurrentContext.Test?.Properties["Category"]; + bool containsSubClients = categories?.Contains(SubClientsCategory) ?? false; + + if (containsSubClients) + { + MockHelpers.LoadMockPlugin( + apiKeyAuth: () => new InputApiKeyAuth("mock", null), + clients: () => [_animalClient, _dogClient, _huskyClient]); + } + else + { + MockHelpers.LoadMockPlugin(apiKeyAuth: () => new InputApiKeyAuth("mock", null)); + } + } + + [Test] + public void TestBuildProperties() + { + var client = InputFactory.Client(TestClientName); + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + // validate the properties + var properties = clientProvider.Properties; + Assert.IsTrue(properties.Count > 0); + // there should be a pipeline property + Assert.AreEqual(1, properties.Count); + + var pipelineProperty = properties.First(); + Assert.AreEqual(typeof(ClientPipeline), pipelineProperty.Type.FrameworkType); + Assert.AreEqual("Pipeline", pipelineProperty.Name); + Assert.AreEqual(MethodSignatureModifiers.Public, pipelineProperty.Modifiers); + } + + [TestCaseSource(nameof(BuildFieldsTestCases))] + public void TestBuildFields(List inputParameters, bool containsAdditionalParams) + { + var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + // validate the fields + var fields = clientProvider.Fields; + if (containsAdditionalParams) + { + Assert.AreEqual(6, fields.Count); + + } + else + { + Assert.AreEqual(4, fields.Count); + } + + // validate the endpoint field + if (inputParameters.Any(p => p.IsEndpoint)) + { + var endpointField = fields.FirstOrDefault(f => f.Name == "_endpoint"); + Assert.IsNotNull(endpointField); + Assert.AreEqual(new CSharpType(typeof(Uri)), endpointField?.Type); + } + + // validate other parameters as fields + if (containsAdditionalParams) + { + var optionalParamField = fields.FirstOrDefault(f => f.Name == "_optionalNullableParam"); + Assert.IsNotNull(optionalParamField); + Assert.AreEqual(new CSharpType(typeof(string), isNullable: true), optionalParamField?.Type); + + var requiredParam2Field = fields.FirstOrDefault(f => f.Name == "_requiredParam2"); + Assert.IsNotNull(requiredParam2Field); + Assert.AreEqual(new CSharpType(typeof(string), isNullable: false), requiredParam2Field?.Type); + + var requiredParam3Field = fields.FirstOrDefault(f => f.Name == "_requiredParam3"); + Assert.IsNotNull(requiredParam3Field); + Assert.AreEqual(new CSharpType(typeof(long), isNullable: false), requiredParam3Field?.Type); + } + } + + // validates the fields are built correctly when a client has sub-clients + [TestCaseSource(nameof(SubClientTestCases), Category = SubClientsCategory)] + public void TestBuildFields_WithSubClients(InputClient client, bool hasSubClients) + { + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + // validate the fields + var fields = clientProvider.Fields; + + // validate the endpoint field + var endpointField = fields.FirstOrDefault(f => f.Name == "_endpoint"); + Assert.IsNotNull(endpointField); + Assert.AreEqual(new CSharpType(typeof(Uri)), endpointField?.Type); + + // there should be n number of caching client fields for every direct sub-client + endpoint field + auth fields + if (hasSubClients) + { + Assert.AreEqual(4, fields.Count); + var cachedClientFields = fields.Where(f => f.Name.StartsWith("_cached")); + Assert.AreEqual(1, cachedClientFields.Count()); + } + else + { + // The 3 fields are _endpoint, AuthorizationHeader, and _keyCredential + Assert.AreEqual(3, fields.Count); + } + } + + [TestCaseSource(nameof(BuildConstructorsTestCases))] + public void TestBuildConstructors_PrimaryConstructor(List inputParameters) + { + var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + var constructors = clientProvider.Constructors; + Assert.AreEqual(3, constructors.Count); + + var primaryPublicConstructor = constructors.FirstOrDefault( + c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); + ValidatePrimaryConstructor(primaryPublicConstructor, inputParameters); + } + + [TestCaseSource(nameof(BuildConstructorsTestCases))] + public void TestBuildConstructors_SecondaryConstructor(List inputParameters) + { + var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + var constructors = clientProvider.Constructors; + + Assert.AreEqual(3, constructors.Count); + var primaryPublicConstructor = constructors.FirstOrDefault( + c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); + + Assert.IsNotNull(primaryPublicConstructor); + + var secondaryPublicConstructor = constructors.FirstOrDefault( + c => c.Signature?.Initializer != null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); + ValidateSecondaryConstructor(primaryPublicConstructor, secondaryPublicConstructor, inputParameters); + } + + [Test] + public void TestBuildConstructors_ForSubClient() + { + var clientProvider = new ClientProvider(_animalClient); + + Assert.IsNotNull(clientProvider); + + var constructors = clientProvider.Constructors; + + Assert.AreEqual(2, constructors.Count); + var internalConstructor = constructors.FirstOrDefault( + c => c.Signature?.Modifiers == MethodSignatureModifiers.Internal); + Assert.IsNotNull(internalConstructor); + var ctorParams = internalConstructor?.Signature?.Parameters; + Assert.AreEqual(3, ctorParams?.Count); + + var mockingConstructor = constructors.FirstOrDefault( + c => c.Signature?.Modifiers == MethodSignatureModifiers.Protected); + Assert.IsNotNull(mockingConstructor); + } + + private static void ValidatePrimaryConstructor( + ConstructorProvider? primaryPublicConstructor, + List inputParameters) + { + Assert.IsNotNull(primaryPublicConstructor); + + var primaryCtorParams = primaryPublicConstructor?.Signature?.Parameters; + var expectedPrimaryCtorParamCount = 3; + + Assert.AreEqual(expectedPrimaryCtorParamCount, primaryCtorParams?.Count); + + // validate the order of the parameters (endpoint, credential, client options) + var endpointParam = primaryCtorParams?[0]; + Assert.AreEqual(KnownParameters.Endpoint.Name, endpointParam?.Name); + Assert.AreEqual("keyCredential", primaryCtorParams?[1].Name); + Assert.AreEqual("options", primaryCtorParams?[2].Name); + + if (endpointParam?.DefaultValue != null) + { + var inputEndpointParam = inputParameters.FirstOrDefault(p => p.IsEndpoint); + var parsedValue = inputEndpointParam?.DefaultValue?.Value; + Assert.AreEqual(Literal(parsedValue), endpointParam?.InitializationValue); + } + + // validate the body of the primary ctor + var primaryCtorBody = primaryPublicConstructor?.BodyStatements; + Assert.IsNotNull(primaryCtorBody); + } + + private void ValidateSecondaryConstructor( + ConstructorProvider? primaryConstructor, + ConstructorProvider? secondaryPublicConstructor, + List inputParameters) + { + Assert.IsNotNull(secondaryPublicConstructor); + var ctorParams = secondaryPublicConstructor?.Signature?.Parameters; + + // secondary ctor should consist of all required parameters + auth parameter + var requiredParams = inputParameters.Where(p => p.IsRequired).ToList(); + Assert.AreEqual(requiredParams.Count + 1, ctorParams?.Count); + var endpointParam = ctorParams?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); + + if (requiredParams.Count == 0) + { + // auth should be the only parameter if endpoint is optional + Assert.AreEqual("keyCredential", ctorParams?[0].Name); + } + else + { + // otherwise, it should only consist of the auth parameter + Assert.AreEqual(KnownParameters.Endpoint.Name, ctorParams?[0].Name); + Assert.AreEqual("keyCredential", ctorParams?[1].Name); + } + + Assert.AreEqual(MethodBodyStatement.Empty, secondaryPublicConstructor?.BodyStatements); + + // validate the initializer + var initializer = secondaryPublicConstructor?.Signature?.Initializer; + Assert.AreEqual(primaryConstructor?.Signature?.Parameters?.Count, initializer?.Arguments?.Count); + } + + [TestCaseSource(nameof(EndpointParamInitializationValueTestCases))] + public void EndpointInitializationValue(InputParameter endpointParameter, ValueExpression? expectedValue) + { + var client = InputFactory.Client(TestClientName, parameters: [endpointParameter]); + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + // find the endpoint parameter from the primary constructor + var primaryConstructor = clientProvider.Constructors.FirstOrDefault( + c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); + var endpoint = primaryConstructor?.Signature?.Parameters?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); + + Assert.IsNotNull(endpoint); + Assert.AreEqual(expectedValue?.GetType(), endpoint?.InitializationValue?.GetType()); + if (expectedValue != null) + { + Assert.IsTrue(endpoint?.InitializationValue is NewInstanceExpression); + } + } + + [TestCase(true)] + [TestCase(false)] + public void TestGetClientOptions(bool isSubClient) + { + string? parentClientName = null; + if (isSubClient) + { + parentClientName = "parent"; + } + + var client = InputFactory.Client(TestClientName, parent: parentClientName); + var clientProvider = new ClientProvider(client); + + if (isSubClient) + { + Assert.IsNull(clientProvider?.ClientOptions); + } + else + { + Assert.IsNotNull(clientProvider?.ClientOptions); + } + } + + [TestCaseSource(nameof(SubClientTestCases), Category = SubClientsCategory)] + public void TestSubClientAccessorFactoryMethods(InputClient client, bool hasSubClients) + { + var clientProvider = new ClientProvider(client); + Assert.IsNotNull(clientProvider); + + var methods = clientProvider.Methods; + List subClientAccessorFactoryMethods = []; + foreach (var method in methods) + { + var methodSignature = method.Signature; + if (methodSignature != null && + methodSignature.Name.StartsWith("Get") && + methodSignature.Modifiers.HasFlag(MethodSignatureModifiers.Public | MethodSignatureModifiers.Virtual)) + { + subClientAccessorFactoryMethods.Add(method); + } + } + + if (hasSubClients) + { + Assert.AreEqual(1, subClientAccessorFactoryMethods.Count); + var factoryMethod = subClientAccessorFactoryMethods[0]; + Assert.AreEqual(0, factoryMethod.Signature?.Parameters.Count); + + // method body should not be empty + Assert.AreNotEqual(MethodBodyStatement.Empty, factoryMethod.BodyStatements); + } + else + { + Assert.AreEqual(0, subClientAccessorFactoryMethods.Count); + } + } + + public static IEnumerable BuildFieldsTestCases + { + get + { + yield return new TestCaseData(new List + { + InputFactory.Parameter( + "optionalParam", + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client), + InputFactory.Parameter( + KnownParameters.Endpoint.Name, + InputPrimitiveType.String, + location:RequestLocation.None, + kind: InputOperationParameterKind.Client, + isEndpoint: true) + }, false); + yield return new TestCaseData(new List + { + // have to explicitly set isRequired because we now call CreateParameter in buildFields + InputFactory.Parameter( + "optionalNullableParam", + InputPrimitiveType.String, + location: RequestLocation.None, + defaultValue: InputFactory.Constant.String("someValue"), + kind: InputOperationParameterKind.Client, + isRequired: false), + InputFactory.Parameter( + "requiredParam2", + InputPrimitiveType.String, + location: RequestLocation.None, + defaultValue: InputFactory.Constant.String("someValue"), + kind: InputOperationParameterKind.Client, + isRequired: true), + InputFactory.Parameter( + "requiredParam3", + InputPrimitiveType.Int64, + location: RequestLocation.None, + defaultValue: InputFactory.Constant.Int64(2), + kind: InputOperationParameterKind.Client, + isRequired: true), + InputFactory.Parameter( + KnownParameters.Endpoint.Name, + InputPrimitiveType.String, + location: RequestLocation.None, + defaultValue: null, + kind: InputOperationParameterKind.Client, + isEndpoint: true) + }, true); + } + } + + public static IEnumerable SubClientTestCases + { + get + { + yield return new TestCaseData(InputFactory.Client(TestClientName), true); + yield return new TestCaseData(_animalClient, true); + yield return new TestCaseData(_dogClient, true); + yield return new TestCaseData(_huskyClient, false); + } + } + + public static IEnumerable BuildConstructorsTestCases + { + get + { + yield return new TestCaseData(new List + { + InputFactory.Parameter( + "optionalParam", + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client), + InputFactory.Parameter( + KnownParameters.Endpoint.Name, + InputPrimitiveType.String, + location: RequestLocation.None, + defaultValue: InputFactory.Constant.String("someValue"), + kind: InputOperationParameterKind.Client, + isEndpoint: true) + }); + // scenario where endpoint is required + yield return new TestCaseData(new List + { + InputFactory.Parameter( + KnownParameters.Endpoint.Name, + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client, + isRequired: true, + isEndpoint: true), + InputFactory.Parameter( + "optionalParam", + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client) + }); + } + } + + private static IEnumerable EndpointParamInitializationValueTestCases + { + get + { + // string primitive type + yield return new TestCaseData( + InputFactory.Parameter( + "param", + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client, + isEndpoint: true, + defaultValue: InputFactory.Constant.String("mockValue")), + New.Instance(KnownParameters.Endpoint.Type, Literal("mockvalue"))); + } + } + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs index cd6d805f74..2c2d472fc4 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs @@ -7,7 +7,6 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Generator.CSharp.ClientModel.Providers; -using Microsoft.Generator.CSharp.Expressions; using Microsoft.Generator.CSharp.Input; using Microsoft.Generator.CSharp.Primitives; using Microsoft.Generator.CSharp.Providers; @@ -15,17 +14,12 @@ using Microsoft.Generator.CSharp.Statements; using Microsoft.Generator.CSharp.Tests.Common; using NUnit.Framework; -using static Microsoft.Generator.CSharp.Snippets.Snippet; namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders { public class ClientProviderTests { - private const string SubClientsCategory = "WithSubClients"; private const string TestClientName = "TestClient"; - private static readonly InputClient _animalClient = new("animal", "AnimalClient description", [], [], TestClientName); - private static readonly InputClient _dogClient = new("dog", "DogClient description", [], [], _animalClient.Name); - private static readonly InputClient _huskyClient = new("husky", "HuskyClient description", [], [], _dogClient.Name); private static readonly InputModelType _spreadModel = InputFactory.Model( "spreadModel", usage: InputModelTypeUsage.Spread, @@ -34,316 +28,6 @@ public class ClientProviderTests InputFactory.Property("p1", InputPrimitiveType.String, isRequired: true), ]); - [SetUp] - public void SetUp() - { - var categories = TestContext.CurrentContext.Test?.Properties["Category"]; - bool containsSubClients = categories?.Contains(SubClientsCategory) ?? false; - - if (containsSubClients) - { - MockHelpers.LoadMockPlugin( - apiKeyAuth: () => new InputApiKeyAuth("mock", null), - clients: () => [_animalClient, _dogClient, _huskyClient]); - } - else - { - MockHelpers.LoadMockPlugin(apiKeyAuth: () => new InputApiKeyAuth("mock", null)); - } - } - - [Test] - public void TestBuildProperties() - { - var client = InputFactory.Client(TestClientName); - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - - // validate the properties - var properties = clientProvider.Properties; - Assert.IsTrue(properties.Count > 0); - // there should be a pipeline property - Assert.AreEqual(1, properties.Count); - - var pipelineProperty = properties.First(); - Assert.AreEqual(typeof(ClientPipeline), pipelineProperty.Type.FrameworkType); - Assert.AreEqual("Pipeline", pipelineProperty.Name); - Assert.AreEqual(MethodSignatureModifiers.Public, pipelineProperty.Modifiers); - } - - [TestCaseSource(nameof(BuildFieldsTestCases))] - public void TestBuildFields(List inputParameters, bool containsAdditionalParams) - { - var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - - // validate the fields - var fields = clientProvider.Fields; - if (containsAdditionalParams) - { - Assert.AreEqual(6, fields.Count); - - } - else - { - Assert.AreEqual(4, fields.Count); - } - - // validate the endpoint field - if (inputParameters.Any(p => p.IsEndpoint)) - { - var endpointField = fields.FirstOrDefault(f => f.Name == "_endpoint"); - Assert.IsNotNull(endpointField); - Assert.AreEqual(new CSharpType(typeof(Uri)), endpointField?.Type); - } - - // validate other parameters as fields - if (containsAdditionalParams) - { - var optionalParamField = fields.FirstOrDefault(f => f.Name == "_optionalNullableParam"); - Assert.IsNotNull(optionalParamField); - Assert.AreEqual(new CSharpType(typeof(string), isNullable: true), optionalParamField?.Type); - - var requiredParam2Field = fields.FirstOrDefault(f => f.Name == "_requiredParam2"); - Assert.IsNotNull(requiredParam2Field); - Assert.AreEqual(new CSharpType(typeof(string), isNullable: false), requiredParam2Field?.Type); - - var requiredParam3Field = fields.FirstOrDefault(f => f.Name == "_requiredParam3"); - Assert.IsNotNull(requiredParam3Field); - Assert.AreEqual(new CSharpType(typeof(long), isNullable: false), requiredParam3Field?.Type); - } - } - - // validates the fields are built correctly when a client has sub-clients - [TestCaseSource(nameof(SubClientTestCases), Category = SubClientsCategory)] - public void TestBuildFields_WithSubClients(InputClient client, bool hasSubClients) - { - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - - // validate the fields - var fields = clientProvider.Fields; - - // validate the endpoint field - var endpointField = fields.FirstOrDefault(f => f.Name == "_endpoint"); - Assert.IsNotNull(endpointField); - Assert.AreEqual(new CSharpType(typeof(Uri)), endpointField?.Type); - - // there should be n number of caching client fields for every direct sub-client + endpoint field + auth fields - if (hasSubClients) - { - Assert.AreEqual(4, fields.Count); - var cachedClientFields = fields.Where(f => f.Name.StartsWith("_cached")); - Assert.AreEqual(1, cachedClientFields.Count()); - } - else - { - // The 3 fields are _endpoint, AuthorizationHeader, and _keyCredential - Assert.AreEqual(3, fields.Count); - } - } - - [TestCaseSource(nameof(BuildConstructorsTestCases))] - public void TestBuildConstructors_PrimaryConstructor(List inputParameters) - { - var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - - var constructors = clientProvider.Constructors; - Assert.AreEqual(3, constructors.Count); - - var primaryPublicConstructor = constructors.FirstOrDefault( - c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); - ValidatePrimaryConstructor(primaryPublicConstructor, inputParameters); - } - - [TestCaseSource(nameof(BuildConstructorsTestCases))] - public void TestBuildConstructors_SecondaryConstructor(List inputParameters) - { - var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - - var constructors = clientProvider.Constructors; - - Assert.AreEqual(3, constructors.Count); - var primaryPublicConstructor = constructors.FirstOrDefault( - c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); - - Assert.IsNotNull(primaryPublicConstructor); - - var secondaryPublicConstructor = constructors.FirstOrDefault( - c => c.Signature?.Initializer != null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); - ValidateSecondaryConstructor(primaryPublicConstructor, secondaryPublicConstructor, inputParameters); - } - - [Test] - public void TestBuildConstructors_ForSubClient() - { - var clientProvider = new ClientProvider(_animalClient); - - Assert.IsNotNull(clientProvider); - - var constructors = clientProvider.Constructors; - - Assert.AreEqual(2, constructors.Count); - var internalConstructor = constructors.FirstOrDefault( - c => c.Signature?.Modifiers == MethodSignatureModifiers.Internal); - Assert.IsNotNull(internalConstructor); - var ctorParams = internalConstructor?.Signature?.Parameters; - Assert.AreEqual(3, ctorParams?.Count); - - var mockingConstructor = constructors.FirstOrDefault( - c => c.Signature?.Modifiers == MethodSignatureModifiers.Protected); - Assert.IsNotNull(mockingConstructor); - } - - private static void ValidatePrimaryConstructor( - ConstructorProvider? primaryPublicConstructor, - List inputParameters) - { - Assert.IsNotNull(primaryPublicConstructor); - - var primaryCtorParams = primaryPublicConstructor?.Signature?.Parameters; - var expectedPrimaryCtorParamCount = 3; - - Assert.AreEqual(expectedPrimaryCtorParamCount, primaryCtorParams?.Count); - - // validate the order of the parameters (endpoint, credential, client options) - var endpointParam = primaryCtorParams?[0]; - Assert.AreEqual(KnownParameters.Endpoint.Name, endpointParam?.Name); - Assert.AreEqual("keyCredential", primaryCtorParams?[1].Name); - Assert.AreEqual("options", primaryCtorParams?[2].Name); - - if (endpointParam?.DefaultValue != null) - { - var inputEndpointParam = inputParameters.FirstOrDefault(p => p.IsEndpoint); - var parsedValue = inputEndpointParam?.DefaultValue?.Value; - Assert.AreEqual(Literal(parsedValue), endpointParam?.InitializationValue); - } - - // validate the body of the primary ctor - var primaryCtorBody = primaryPublicConstructor?.BodyStatements; - Assert.IsNotNull(primaryCtorBody); - } - - private void ValidateSecondaryConstructor( - ConstructorProvider? primaryConstructor, - ConstructorProvider? secondaryPublicConstructor, - List inputParameters) - { - Assert.IsNotNull(secondaryPublicConstructor); - var ctorParams = secondaryPublicConstructor?.Signature?.Parameters; - - // secondary ctor should consist of all required parameters + auth parameter - var requiredParams = inputParameters.Where(p => p.IsRequired).ToList(); - Assert.AreEqual(requiredParams.Count + 1, ctorParams?.Count); - var endpointParam = ctorParams?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); - - if (requiredParams.Count == 0) - { - // auth should be the only parameter if endpoint is optional - Assert.AreEqual("keyCredential", ctorParams?[0].Name); - } - else - { - // otherwise, it should only consist of the auth parameter - Assert.AreEqual(KnownParameters.Endpoint.Name, ctorParams?[0].Name); - Assert.AreEqual("keyCredential", ctorParams?[1].Name); - } - - Assert.AreEqual(MethodBodyStatement.Empty, secondaryPublicConstructor?.BodyStatements); - - // validate the initializer - var initializer = secondaryPublicConstructor?.Signature?.Initializer; - Assert.AreEqual(primaryConstructor?.Signature?.Parameters?.Count, initializer?.Arguments?.Count); - } - - [TestCaseSource(nameof(EndpointParamInitializationValueTestCases))] - public void EndpointInitializationValue(InputParameter endpointParameter, ValueExpression? expectedValue) - { - var client = InputFactory.Client(TestClientName, parameters: [endpointParameter]); - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - // find the endpoint parameter from the primary constructor - var primaryConstructor = clientProvider.Constructors.FirstOrDefault( - c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); - var endpoint = primaryConstructor?.Signature?.Parameters?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); - - Assert.IsNotNull(endpoint); - Assert.AreEqual(expectedValue?.GetType(), endpoint?.InitializationValue?.GetType()); - if (expectedValue != null) - { - Assert.IsTrue(endpoint?.InitializationValue is NewInstanceExpression); - } - } - - [TestCase(true)] - [TestCase(false)] - public void TestGetClientOptions(bool isSubClient) - { - string? parentClientName = null; - if (isSubClient) - { - parentClientName = "parent"; - } - - var client = InputFactory.Client(TestClientName, parent: parentClientName); - var clientProvider = new ClientProvider(client); - - if (isSubClient) - { - Assert.IsNull(clientProvider?.ClientOptions); - } - else - { - Assert.IsNotNull(clientProvider?.ClientOptions); - } - } - - [TestCaseSource(nameof(SubClientTestCases), Category = SubClientsCategory)] - public void TestSubClientAccessorFactoryMethods(InputClient client, bool hasSubClients) - { - var clientProvider = new ClientProvider(client); - Assert.IsNotNull(clientProvider); - - var methods = clientProvider.Methods; - List subClientAccessorFactoryMethods = []; - foreach (var method in methods) - { - var methodSignature = method.Signature; - if (methodSignature != null && - methodSignature.Name.StartsWith("Get") && - methodSignature.Modifiers.HasFlag(MethodSignatureModifiers.Public | MethodSignatureModifiers.Virtual)) - { - subClientAccessorFactoryMethods.Add(method); - } - } - - if (hasSubClients) - { - Assert.AreEqual(1, subClientAccessorFactoryMethods.Count); - var factoryMethod = subClientAccessorFactoryMethods[0]; - Assert.AreEqual(0, factoryMethod.Signature?.Parameters.Count); - - // method body should not be empty - Assert.AreNotEqual(MethodBodyStatement.Empty, factoryMethod.BodyStatements); - } - else - { - Assert.AreEqual(0, subClientAccessorFactoryMethods.Count); - } - - } - [Test] public void ValidateQueryParamDiff() { @@ -426,7 +110,6 @@ public void ValidateClientWithSpread(InputClient inputClient) Assert.AreEqual(new CSharpType(typeof(string)), convenienceMethods[0].Signature.Parameters[0].Type); Assert.AreEqual("p1", convenienceMethods[0].Signature.Parameters[0].Name); - } [TestCaseSource(nameof(RequestOptionsParameterInSignatureTestCases))] @@ -597,70 +280,6 @@ protected override MethodProvider[] BuildMethods() protected override PropertyProvider[] BuildProperties() => []; } - public static IEnumerable BuildFieldsTestCases - { - get - { - yield return new TestCaseData(new List - { - InputFactory.Parameter( - "optionalParam", - InputPrimitiveType.String, - location: RequestLocation.None, - kind: InputOperationParameterKind.Client), - InputFactory.Parameter( - KnownParameters.Endpoint.Name, - InputPrimitiveType.String, - location:RequestLocation.None, - kind: InputOperationParameterKind.Client, - isEndpoint: true) - }, false); - yield return new TestCaseData(new List - { - // have to explicitly set isRequired because we now call CreateParameter in buildFields - InputFactory.Parameter( - "optionalNullableParam", - InputPrimitiveType.String, - location: RequestLocation.None, - defaultValue: InputFactory.Constant.String("someValue"), - kind: InputOperationParameterKind.Client, - isRequired: false), - InputFactory.Parameter( - "requiredParam2", - InputPrimitiveType.String, - location: RequestLocation.None, - defaultValue: InputFactory.Constant.String("someValue"), - kind: InputOperationParameterKind.Client, - isRequired: true), - InputFactory.Parameter( - "requiredParam3", - InputPrimitiveType.Int64, - location: RequestLocation.None, - defaultValue: InputFactory.Constant.Int64(2), - kind: InputOperationParameterKind.Client, - isRequired: true), - InputFactory.Parameter( - KnownParameters.Endpoint.Name, - InputPrimitiveType.String, - location: RequestLocation.None, - defaultValue: null, - kind: InputOperationParameterKind.Client, - isEndpoint: true) - }, true); - } - } - - public static IEnumerable SubClientTestCases - { - get - { - yield return new TestCaseData(InputFactory.Client(TestClientName), true); - yield return new TestCaseData(_animalClient, true); - yield return new TestCaseData(_dogClient, true); - yield return new TestCaseData(_huskyClient, false); - } - } - public static IEnumerable ValidateClientWithSpreadTestCases { get @@ -684,44 +303,6 @@ public static IEnumerable ValidateClientWithSpreadTestCases } } - public static IEnumerable BuildConstructorsTestCases - { - get - { - yield return new TestCaseData(new List - { - InputFactory.Parameter( - "optionalParam", - InputPrimitiveType.String, - location: RequestLocation.None, - kind: InputOperationParameterKind.Client), - InputFactory.Parameter( - KnownParameters.Endpoint.Name, - InputPrimitiveType.String, - location: RequestLocation.None, - defaultValue: InputFactory.Constant.String("someValue"), - kind: InputOperationParameterKind.Client, - isEndpoint: true) - }); - // scenario where endpoint is required - yield return new TestCaseData(new List - { - InputFactory.Parameter( - KnownParameters.Endpoint.Name, - InputPrimitiveType.String, - location: RequestLocation.None, - kind: InputOperationParameterKind.Client, - isRequired: true, - isEndpoint: true), - InputFactory.Parameter( - "optionalParam", - InputPrimitiveType.String, - location: RequestLocation.None, - kind: InputOperationParameterKind.Client) - }); - } - } - public static IEnumerable RequestOptionsParameterInSignatureTestCases { get @@ -841,83 +422,72 @@ public static IEnumerable RequestOptionsParameterInSignatureTestCa } } - private static IEnumerable EndpointParamInitializationValueTestCases() + private static IEnumerable ValidateApiVersionPathParameterTestCases { - // string primitive type - yield return new TestCaseData( - InputFactory.Parameter( - "param", + get + { + InputParameter endpointParameter = InputFactory.Parameter( + "endpoint", InputPrimitiveType.String, - location: RequestLocation.None, + location: RequestLocation.Uri, + isRequired: true, kind: InputOperationParameterKind.Client, isEndpoint: true, - defaultValue: InputFactory.Constant.String("mockValue")), - New.Instance(KnownParameters.Endpoint.Type, Literal("mockvalue"))); - } + isApiVersion: false); - private static IEnumerable ValidateApiVersionPathParameterTestCases() - { - InputParameter endpointParameter = InputFactory.Parameter( - "endpoint", - InputPrimitiveType.String, - location: RequestLocation.Uri, - isRequired: true, - kind: InputOperationParameterKind.Client, - isEndpoint: true, - isApiVersion: false); - - InputParameter stringApiVersionParameter = InputFactory.Parameter( - "apiVersion", - InputPrimitiveType.String, - location: RequestLocation.Uri, - isRequired: true, - kind: InputOperationParameterKind.Client, - isApiVersion: true); - - InputParameter enumApiVersionParameter = InputFactory.Parameter( - "apiVersion", - InputFactory.Enum( - "InputEnum", + InputParameter stringApiVersionParameter = InputFactory.Parameter( + "apiVersion", InputPrimitiveType.String, - usage: InputModelTypeUsage.Input, - isExtensible: true, - values: - [ - InputFactory.EnumMember.String("value1", "value1"), + location: RequestLocation.Uri, + isRequired: true, + kind: InputOperationParameterKind.Client, + isApiVersion: true); + + InputParameter enumApiVersionParameter = InputFactory.Parameter( + "apiVersion", + InputFactory.Enum( + "InputEnum", + InputPrimitiveType.String, + usage: InputModelTypeUsage.Input, + isExtensible: true, + values: + [ + InputFactory.EnumMember.String("value1", "value1"), InputFactory.EnumMember.String("value2", "value2") - ]), - location: RequestLocation.Uri, - isRequired: true, - kind: InputOperationParameterKind.Client, - isApiVersion: true); - - yield return new TestCaseData( - InputFactory.Client( - "TestClient", - operations: - [ - InputFactory.Operation( + ]), + location: RequestLocation.Uri, + isRequired: true, + kind: InputOperationParameterKind.Client, + isApiVersion: true); + + yield return new TestCaseData( + InputFactory.Client( + "TestClient", + operations: + [ + InputFactory.Operation( "TestOperation", uri: "{endpoint}/{apiVersion}") - ], - parameters: [ - endpointParameter, + ], + parameters: [ + endpointParameter, stringApiVersionParameter - ])); + ])); - yield return new TestCaseData( - InputFactory.Client( - "TestClient", - operations: - [ - InputFactory.Operation( + yield return new TestCaseData( + InputFactory.Client( + "TestClient", + operations: + [ + InputFactory.Operation( "TestOperation", uri: "{endpoint}/{apiVersion}") - ], - parameters: [ - endpointParameter, + ], + parameters: [ + endpointParameter, enumApiVersionParameter - ])); + ])); + } } } } From 66d4083f7dfdb6aa3559679623fb256de96b7dea Mon Sep 17 00:00:00 2001 From: Dapeng Zhang Date: Tue, 3 Dec 2024 12:52:38 +0800 Subject: [PATCH 02/22] rename and move back a test --- ...ts.cs => ClientProviderApiKeyAuthTests.cs} | 25 +------------------ .../ClientProviders/ClientProviderTests.cs | 23 +++++++++++++++++ 2 files changed, 24 insertions(+), 24 deletions(-) rename packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/{ApiKeyAuthClientProviderTests.cs => ClientProviderApiKeyAuthTests.cs} (96%) diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ApiKeyAuthClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderApiKeyAuthTests.cs similarity index 96% rename from packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ApiKeyAuthClientProviderTests.cs rename to packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderApiKeyAuthTests.cs index 5ff013dc82..7ee3dfc044 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ApiKeyAuthClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderApiKeyAuthTests.cs @@ -18,7 +18,7 @@ namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders { - public class ApiKeyAuthClientProviderTests + public class ClientProviderApiKeyAuthTests { private const string SubClientsCategory = "WithSubClients"; private const string TestClientName = "TestClient"; @@ -278,29 +278,6 @@ public void EndpointInitializationValue(InputParameter endpointParameter, ValueE } } - [TestCase(true)] - [TestCase(false)] - public void TestGetClientOptions(bool isSubClient) - { - string? parentClientName = null; - if (isSubClient) - { - parentClientName = "parent"; - } - - var client = InputFactory.Client(TestClientName, parent: parentClientName); - var clientProvider = new ClientProvider(client); - - if (isSubClient) - { - Assert.IsNull(clientProvider?.ClientOptions); - } - else - { - Assert.IsNotNull(clientProvider?.ClientOptions); - } - } - [TestCaseSource(nameof(SubClientTestCases), Category = SubClientsCategory)] public void TestSubClientAccessorFactoryMethods(InputClient client, bool hasSubClients) { diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs index 2c2d472fc4..6e3d908499 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs @@ -28,6 +28,29 @@ public class ClientProviderTests InputFactory.Property("p1", InputPrimitiveType.String, isRequired: true), ]); + [TestCase(true)] + [TestCase(false)] + public void TestGetClientOptions(bool isSubClient) + { + string? parentClientName = null; + if (isSubClient) + { + parentClientName = "parent"; + } + + var client = InputFactory.Client(TestClientName, parent: parentClientName); + var clientProvider = new ClientProvider(client); + + if (isSubClient) + { + Assert.IsNull(clientProvider?.ClientOptions); + } + else + { + Assert.IsNotNull(clientProvider?.ClientOptions); + } + } + [Test] public void ValidateQueryParamDiff() { From 795834619fb7f361bb3f36c859331409012a09f2 Mon Sep 17 00:00:00 2001 From: Dapeng Zhang Date: Tue, 3 Dec 2024 12:53:21 +0800 Subject: [PATCH 03/22] clean up empty line --- .../Providers/ClientProviders/ClientProviderApiKeyAuthTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderApiKeyAuthTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderApiKeyAuthTests.cs index 7ee3dfc044..c935091fd6 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderApiKeyAuthTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderApiKeyAuthTests.cs @@ -77,7 +77,6 @@ public void TestBuildFields(List inputParameters, bool containsA if (containsAdditionalParams) { Assert.AreEqual(6, fields.Count); - } else { From 77c6afef3b53a56275dc4ae33cb4b4864edf40cf Mon Sep 17 00:00:00 2001 From: Dapeng Zhang Date: Tue, 3 Dec 2024 13:02:57 +0800 Subject: [PATCH 04/22] move another test case --- .../ClientProviderApiKeyAuthTests.cs | 20 ------------------- .../ClientProviders/ClientProviderTests.cs | 20 +++++++++++++++++++ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderApiKeyAuthTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderApiKeyAuthTests.cs index c935091fd6..5fe28b9673 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderApiKeyAuthTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderApiKeyAuthTests.cs @@ -44,26 +44,6 @@ public void SetUp() } } - [Test] - public void TestBuildProperties() - { - var client = InputFactory.Client(TestClientName); - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - - // validate the properties - var properties = clientProvider.Properties; - Assert.IsTrue(properties.Count > 0); - // there should be a pipeline property - Assert.AreEqual(1, properties.Count); - - var pipelineProperty = properties.First(); - Assert.AreEqual(typeof(ClientPipeline), pipelineProperty.Type.FrameworkType); - Assert.AreEqual("Pipeline", pipelineProperty.Name); - Assert.AreEqual(MethodSignatureModifiers.Public, pipelineProperty.Modifiers); - } - [TestCaseSource(nameof(BuildFieldsTestCases))] public void TestBuildFields(List inputParameters, bool containsAdditionalParams) { diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs index 6e3d908499..f2f9b451b6 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs @@ -28,6 +28,26 @@ public class ClientProviderTests InputFactory.Property("p1", InputPrimitiveType.String, isRequired: true), ]); + [Test] + public void TestBuildProperties() + { + var client = InputFactory.Client(TestClientName); + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + // validate the properties + var properties = clientProvider.Properties; + Assert.IsTrue(properties.Count > 0); + // there should be a pipeline property + Assert.AreEqual(1, properties.Count); + + var pipelineProperty = properties.First(); + Assert.AreEqual(typeof(ClientPipeline), pipelineProperty.Type.FrameworkType); + Assert.AreEqual("Pipeline", pipelineProperty.Name); + Assert.AreEqual(MethodSignatureModifiers.Public, pipelineProperty.Modifiers); + } + [TestCase(true)] [TestCase(false)] public void TestGetClientOptions(bool isSubClient) From 7a63acd1b8735bde1cba53cead2c1adcb4b85cac Mon Sep 17 00:00:00 2001 From: Dapeng Zhang Date: Wed, 4 Dec 2024 08:26:34 +0800 Subject: [PATCH 05/22] refactor test cases --- ...uthTests.cs => ClientProviderAuthTests.cs} | 113 +++++++-------- .../ClientProviders/ClientProviderTests.cs | 137 ++++++++++++++++++ .../ClientProviderTestsUtils.cs | 102 +++++++++++++ 3 files changed, 289 insertions(+), 63 deletions(-) rename packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/{ClientProviderApiKeyAuthTests.cs => ClientProviderAuthTests.cs} (83%) create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTestsUtils.cs diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderApiKeyAuthTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderAuthTests.cs similarity index 83% rename from packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderApiKeyAuthTests.cs rename to packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderAuthTests.cs index 5fe28b9673..b589360937 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderApiKeyAuthTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderAuthTests.cs @@ -2,7 +2,7 @@ // Licensed under the MIT License. using System; -using System.ClientModel.Primitives; +using System.ClientModel; using System.Collections.Generic; using System.Linq; using Microsoft.Generator.CSharp.ClientModel.Providers; @@ -14,11 +14,12 @@ using Microsoft.Generator.CSharp.Statements; using Microsoft.Generator.CSharp.Tests.Common; using NUnit.Framework; +using static Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders.ClientProviderTestsUtils; using static Microsoft.Generator.CSharp.Snippets.Snippet; namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders { - public class ClientProviderApiKeyAuthTests + public class ClientProviderAuthTests { private const string SubClientsCategory = "WithSubClients"; private const string TestClientName = "TestClient"; @@ -45,77 +46,25 @@ public void SetUp() } [TestCaseSource(nameof(BuildFieldsTestCases))] - public void TestBuildFields(List inputParameters, bool containsAdditionalParams) + public void TestBuildFields(List inputParameters, List expectedFields) { var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); var clientProvider = new ClientProvider(client); Assert.IsNotNull(clientProvider); - // validate the fields - var fields = clientProvider.Fields; - if (containsAdditionalParams) - { - Assert.AreEqual(6, fields.Count); - } - else - { - Assert.AreEqual(4, fields.Count); - } - - // validate the endpoint field - if (inputParameters.Any(p => p.IsEndpoint)) - { - var endpointField = fields.FirstOrDefault(f => f.Name == "_endpoint"); - Assert.IsNotNull(endpointField); - Assert.AreEqual(new CSharpType(typeof(Uri)), endpointField?.Type); - } - - // validate other parameters as fields - if (containsAdditionalParams) - { - var optionalParamField = fields.FirstOrDefault(f => f.Name == "_optionalNullableParam"); - Assert.IsNotNull(optionalParamField); - Assert.AreEqual(new CSharpType(typeof(string), isNullable: true), optionalParamField?.Type); - - var requiredParam2Field = fields.FirstOrDefault(f => f.Name == "_requiredParam2"); - Assert.IsNotNull(requiredParam2Field); - Assert.AreEqual(new CSharpType(typeof(string), isNullable: false), requiredParam2Field?.Type); - - var requiredParam3Field = fields.FirstOrDefault(f => f.Name == "_requiredParam3"); - Assert.IsNotNull(requiredParam3Field); - Assert.AreEqual(new CSharpType(typeof(long), isNullable: false), requiredParam3Field?.Type); - } + AssertHasFields(clientProvider, expectedFields); } // validates the fields are built correctly when a client has sub-clients - [TestCaseSource(nameof(SubClientTestCases), Category = SubClientsCategory)] - public void TestBuildFields_WithSubClients(InputClient client, bool hasSubClients) + [TestCaseSource(nameof(SubClientFieldsTestCases), Category = SubClientsCategory)] + public void TestBuildFields_WithSubClients(InputClient client, List expectedFields) { var clientProvider = new ClientProvider(client); Assert.IsNotNull(clientProvider); - // validate the fields - var fields = clientProvider.Fields; - - // validate the endpoint field - var endpointField = fields.FirstOrDefault(f => f.Name == "_endpoint"); - Assert.IsNotNull(endpointField); - Assert.AreEqual(new CSharpType(typeof(Uri)), endpointField?.Type); - - // there should be n number of caching client fields for every direct sub-client + endpoint field + auth fields - if (hasSubClients) - { - Assert.AreEqual(4, fields.Count); - var cachedClientFields = fields.Where(f => f.Name.StartsWith("_cached")); - Assert.AreEqual(1, cachedClientFields.Count()); - } - else - { - // The 3 fields are _endpoint, AuthorizationHeader, and _keyCredential - Assert.AreEqual(3, fields.Count); - } + AssertHasFields(clientProvider, expectedFields); } [TestCaseSource(nameof(BuildConstructorsTestCases))] @@ -257,7 +206,7 @@ public void EndpointInitializationValue(InputParameter endpointParameter, ValueE } } - [TestCaseSource(nameof(SubClientTestCases), Category = SubClientsCategory)] + [TestCaseSource(nameof(SubClientFactoryMethodTestCases), Category = SubClientsCategory)] public void TestSubClientAccessorFactoryMethods(InputClient client, bool hasSubClients) { var clientProvider = new ClientProvider(client); @@ -308,7 +257,13 @@ public static IEnumerable BuildFieldsTestCases location:RequestLocation.None, kind: InputOperationParameterKind.Client, isEndpoint: true) - }, false); + }, + new List + { + new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string)), "AuthorizationHeader"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(ApiKeyCredential)), "_keyCredential"), + } + ); yield return new TestCaseData(new List { // have to explicitly set isRequired because we now call CreateParameter in buildFields @@ -340,11 +295,43 @@ public static IEnumerable BuildFieldsTestCases defaultValue: null, kind: InputOperationParameterKind.Client, isEndpoint: true) - }, true); + }, + new List + { + new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string)), "AuthorizationHeader"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(ApiKeyCredential)), "_keyCredential"), + }); + } + } + + public static IEnumerable SubClientFieldsTestCases + { + get + { + yield return new TestCaseData(InputFactory.Client(TestClientName), new List + { + new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string)), "AuthorizationHeader"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(ApiKeyCredential)), "_keyCredential") + }); + yield return new TestCaseData(_animalClient, new List + { + new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string)), "AuthorizationHeader"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(ApiKeyCredential)), "_keyCredential") + }); + yield return new TestCaseData(_dogClient, new List + { + new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string)), "AuthorizationHeader"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(ApiKeyCredential)), "_keyCredential") + }); + yield return new TestCaseData(_huskyClient, new List + { + new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string)), "AuthorizationHeader"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(ApiKeyCredential)), "_keyCredential") + }); } } - public static IEnumerable SubClientTestCases + public static IEnumerable SubClientFactoryMethodTestCases { get { diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs index f2f9b451b6..70107bd71c 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs @@ -14,12 +14,17 @@ using Microsoft.Generator.CSharp.Statements; using Microsoft.Generator.CSharp.Tests.Common; using NUnit.Framework; +using static Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders.ClientProviderTestsUtils; namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders { public class ClientProviderTests { + private const string SubClientsCategory = "WithSubClients"; private const string TestClientName = "TestClient"; + private static readonly InputClient _animalClient = new("animal", "AnimalClient description", [], [], TestClientName); + private static readonly InputClient _dogClient = new("dog", "DogClient description", [], [], _animalClient.Name); + private static readonly InputClient _huskyClient = new("husky", "HuskyClient description", [], [], _dogClient.Name); private static readonly InputModelType _spreadModel = InputFactory.Model( "spreadModel", usage: InputModelTypeUsage.Spread, @@ -28,6 +33,46 @@ public class ClientProviderTests InputFactory.Property("p1", InputPrimitiveType.String, isRequired: true), ]); + [SetUp] + public void SetUp() + { + var categories = TestContext.CurrentContext.Test?.Properties["Category"]; + bool containsSubClients = categories?.Contains(SubClientsCategory) ?? false; + + if (containsSubClients) + { + MockHelpers.LoadMockPlugin( + apiKeyAuth: () => new InputApiKeyAuth("mock", null), + clients: () => [_animalClient, _dogClient, _huskyClient]); + } + else + { + MockHelpers.LoadMockPlugin(apiKeyAuth: () => new InputApiKeyAuth("mock", null)); + } + } + + [TestCaseSource(nameof(BuildFieldsTestCases))] + public void TestBuildFields(List inputParameters, List expectedFields) + { + var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + AssertHasFields(clientProvider, expectedFields); + } + + // validates the fields are built correctly when a client has sub-clients + [TestCaseSource(nameof(SubClientFieldsTestCases), Category = SubClientsCategory)] + public void TestBuildFields_WithSubClients(InputClient client, List expectedFields) + { + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + AssertHasFields(clientProvider, expectedFields); + } + [Test] public void TestBuildProperties() { @@ -273,6 +318,98 @@ public void TestApiVersionPathParameterOfClient(InputClient inputClient) Assert.IsNull(method?.Signature.Parameters.FirstOrDefault(p => p.Name.Equals("apiVersion"))); } + public static IEnumerable BuildFieldsTestCases + { + get + { + yield return new TestCaseData(new List + { + InputFactory.Parameter( + "optionalParam", + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client), + InputFactory.Parameter( + KnownParameters.Endpoint.Name, + InputPrimitiveType.String, + location:RequestLocation.None, + kind: InputOperationParameterKind.Client, + isEndpoint: true) + }, + new List + { + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), true), "_optionalParam") + } + ); + yield return new TestCaseData(new List + { + // have to explicitly set isRequired because we now call CreateParameter in buildFields + InputFactory.Parameter( + "optionalNullableParam", + InputPrimitiveType.String, + location: RequestLocation.None, + defaultValue: InputFactory.Constant.String("someValue"), + kind: InputOperationParameterKind.Client, + isRequired: false), + InputFactory.Parameter( + "requiredParam2", + InputPrimitiveType.String, + location: RequestLocation.None, + defaultValue: InputFactory.Constant.String("someValue"), + kind: InputOperationParameterKind.Client, + isRequired: true), + InputFactory.Parameter( + "requiredParam3", + InputPrimitiveType.Int64, + location: RequestLocation.None, + defaultValue: InputFactory.Constant.Int64(2), + kind: InputOperationParameterKind.Client, + isRequired: true), + InputFactory.Parameter( + KnownParameters.Endpoint.Name, + InputPrimitiveType.String, + location: RequestLocation.None, + defaultValue: null, + kind: InputOperationParameterKind.Client, + isEndpoint: true) + }, + new List + { + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), true), "_optionalNullableParam"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), false), "_requiredParam2"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(long), false), "_requiredParam3") + }); + } + } + + public static IEnumerable SubClientFieldsTestCases + { + get + { + yield return new TestCaseData(InputFactory.Client(TestClientName), new List + { + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + new(FieldModifiers.Private, new ExpectedCSharpType("Animal", "Sample", false), "_cachedAnimal"), + }); + yield return new TestCaseData(_animalClient, new List + { + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + new(FieldModifiers.Private, new ExpectedCSharpType("Dog", "Sample", false), "_cachedDog"), + }); + yield return new TestCaseData(_dogClient, new List + { + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + new(FieldModifiers.Private, new ExpectedCSharpType("Husky", "Sample", false), "_cachedHusky"), + }); + yield return new TestCaseData(_huskyClient, new List + { + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint") + }); + } + } + private static InputClient GetEnumQueryParamClient() => InputFactory.Client( TestClientName, diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTestsUtils.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTestsUtils.cs new file mode 100644 index 0000000000..09c0e61b7e --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTestsUtils.cs @@ -0,0 +1,102 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Generator.CSharp.Primitives; +using Microsoft.Generator.CSharp.Providers; +using NUnit.Framework; + +namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders +{ + public static class ClientProviderTestsUtils + { + public record ExpectedCSharpType + { + public string Name { get; } + + public string Namespace { get; } + + public bool IsFrameworkType { get; } + + public Type FrameworkType => _frameworkType ?? throw new InvalidOperationException(); + + public bool IsNullable { get; } + + private readonly Type? _frameworkType; + + public ExpectedCSharpType(Type frameworkType, bool isNullable) + { + _frameworkType = frameworkType; + IsFrameworkType = true; + IsNullable = isNullable; + Name = frameworkType.Name; + Namespace = frameworkType.Namespace!; + } + + public ExpectedCSharpType(string name, string ns, bool isNullable) + { + IsFrameworkType = false; + IsNullable = isNullable; + Name = name; + Namespace = ns; + } + + public static implicit operator ExpectedCSharpType(CSharpType type) + { + if (type.IsFrameworkType) + { + return new(type.FrameworkType, type.IsNullable); + } + else + { + return new(type.Name, type.Namespace, type.IsNullable); + } + } + } + + public record ExpectedFieldProvider(FieldModifiers Modifiers, ExpectedCSharpType Type, string Name); + + internal static void AssertCSharpTypeAreEqual(ExpectedCSharpType expected, CSharpType type) + { + if (expected.IsFrameworkType) + { + Assert.IsTrue(type.IsFrameworkType); + Assert.AreEqual(expected.FrameworkType, type.FrameworkType); + } + else + { + Assert.IsFalse(type.IsFrameworkType); + Assert.AreEqual(expected.Name, type.Name); + Assert.AreEqual(expected.Namespace, type.Namespace); + } + Assert.AreEqual(expected.IsNullable, type.IsNullable); + } + + internal static void AssertFieldAreEqual(ExpectedFieldProvider expected, FieldProvider field) + { + Assert.AreEqual(expected.Name, field.Name); + AssertCSharpTypeAreEqual(expected.Type, field.Type); + Assert.AreEqual(expected.Modifiers, field.Modifiers); + } + + internal static void AssertHasFields(TypeProvider provider, IReadOnlyList expectedFields) + { + var fields = provider.Fields; + + // validate the length of the result + Assert.GreaterOrEqual(fields.Count, expectedFields.Count); + + // validate each of them + var fieldDict = fields.ToDictionary(f => f.Name); + for (int i = 0; i < expectedFields.Count; i++) + { + var expected = expectedFields[i]; + + Assert.IsTrue(fieldDict.TryGetValue(expected.Name, out var actual), $"Field {expected.Name} not present"); + AssertFieldAreEqual(expected, actual!); + } + } + } +} From 8839bf1805fdd3bd99be15c64462cdcabfefef0a Mon Sep 17 00:00:00 2001 From: Dapeng Zhang Date: Wed, 4 Dec 2024 14:06:48 +0800 Subject: [PATCH 06/22] change the order of test methods back --- .../ClientProviders/ClientProviderTests.cs | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs index 70107bd71c..ae65813a4b 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs @@ -51,21 +51,30 @@ public void SetUp() } } - [TestCaseSource(nameof(BuildFieldsTestCases))] - public void TestBuildFields(List inputParameters, List expectedFields) + [Test] + public void TestBuildProperties() { - var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); + var client = InputFactory.Client(TestClientName); var clientProvider = new ClientProvider(client); Assert.IsNotNull(clientProvider); - AssertHasFields(clientProvider, expectedFields); + // validate the properties + var properties = clientProvider.Properties; + Assert.IsTrue(properties.Count > 0); + // there should be a pipeline property + Assert.AreEqual(1, properties.Count); + + var pipelineProperty = properties.First(); + Assert.AreEqual(typeof(ClientPipeline), pipelineProperty.Type.FrameworkType); + Assert.AreEqual("Pipeline", pipelineProperty.Name); + Assert.AreEqual(MethodSignatureModifiers.Public, pipelineProperty.Modifiers); } - // validates the fields are built correctly when a client has sub-clients - [TestCaseSource(nameof(SubClientFieldsTestCases), Category = SubClientsCategory)] - public void TestBuildFields_WithSubClients(InputClient client, List expectedFields) + [TestCaseSource(nameof(BuildFieldsTestCases))] + public void TestBuildFields(List inputParameters, List expectedFields) { + var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); var clientProvider = new ClientProvider(client); Assert.IsNotNull(clientProvider); @@ -73,24 +82,15 @@ public void TestBuildFields_WithSubClients(InputClient client, List expectedFields) { - var client = InputFactory.Client(TestClientName); var clientProvider = new ClientProvider(client); Assert.IsNotNull(clientProvider); - // validate the properties - var properties = clientProvider.Properties; - Assert.IsTrue(properties.Count > 0); - // there should be a pipeline property - Assert.AreEqual(1, properties.Count); - - var pipelineProperty = properties.First(); - Assert.AreEqual(typeof(ClientPipeline), pipelineProperty.Type.FrameworkType); - Assert.AreEqual("Pipeline", pipelineProperty.Name); - Assert.AreEqual(MethodSignatureModifiers.Public, pipelineProperty.Modifiers); + AssertHasFields(clientProvider, expectedFields); } [TestCase(true)] From 9c59c44340753c564acbc5861c0bad969eb0d932 Mon Sep 17 00:00:00 2001 From: Dapeng Zhang Date: Wed, 4 Dec 2024 14:08:50 +0800 Subject: [PATCH 07/22] more effort to reduce the amount of changes --- .../ClientProviders/ClientProviderTests.cs | 100 +++++++++--------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs index ae65813a4b..7da0bd144d 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs @@ -318,6 +318,56 @@ public void TestApiVersionPathParameterOfClient(InputClient inputClient) Assert.IsNull(method?.Signature.Parameters.FirstOrDefault(p => p.Name.Equals("apiVersion"))); } + private static InputClient GetEnumQueryParamClient() + => InputFactory.Client( + TestClientName, + operations: + [ + InputFactory.Operation( + "Operation", + parameters: + [ + InputFactory.Parameter( + "queryParam", + InputFactory.Enum( + "InputEnum", + InputPrimitiveType.String, + usage: InputModelTypeUsage.Input, + isExtensible: true, + values: + [ + InputFactory.EnumMember.String("value1", "value1"), + InputFactory.EnumMember.String("value2", "value2") + ]), + isRequired: true, + location: RequestLocation.Query) + ]) + ]); + + private class ValidateQueryParamDiffClientProvider : ClientProvider + { + private readonly bool _isAsync; + + public ValidateQueryParamDiffClientProvider(InputClient client, bool isAsync = false) + : base(client) + { + _isAsync = isAsync; + } + + protected override MethodProvider[] BuildMethods() + { + var method = base.BuildMethods().First(m => m.Signature.Parameters.Any(p => + p is { Name: "queryParam", Type.Name: "InputEnum" } && + ((_isAsync && m.Signature.Name.EndsWith("Async")) || (!_isAsync && !m.Signature.Name.EndsWith("Async"))))); + method.Update(xmlDocProvider: new XmlDocProvider()); // null out the docs + return [method]; + } + + protected override FieldProvider[] BuildFields() => []; + protected override ConstructorProvider[] BuildConstructors() => []; + protected override PropertyProvider[] BuildProperties() => []; + } + public static IEnumerable BuildFieldsTestCases { get @@ -410,56 +460,6 @@ public static IEnumerable SubClientFieldsTestCases } } - private static InputClient GetEnumQueryParamClient() - => InputFactory.Client( - TestClientName, - operations: - [ - InputFactory.Operation( - "Operation", - parameters: - [ - InputFactory.Parameter( - "queryParam", - InputFactory.Enum( - "InputEnum", - InputPrimitiveType.String, - usage: InputModelTypeUsage.Input, - isExtensible: true, - values: - [ - InputFactory.EnumMember.String("value1", "value1"), - InputFactory.EnumMember.String("value2", "value2") - ]), - isRequired: true, - location: RequestLocation.Query) - ]) - ]); - - private class ValidateQueryParamDiffClientProvider : ClientProvider - { - private readonly bool _isAsync; - - public ValidateQueryParamDiffClientProvider(InputClient client, bool isAsync = false) - : base(client) - { - _isAsync = isAsync; - } - - protected override MethodProvider[] BuildMethods() - { - var method = base.BuildMethods().First(m => m.Signature.Parameters.Any(p => - p is { Name: "queryParam", Type.Name: "InputEnum" } && - ((_isAsync && m.Signature.Name.EndsWith("Async")) || (!_isAsync && !m.Signature.Name.EndsWith("Async"))))); - method.Update(xmlDocProvider: new XmlDocProvider()); // null out the docs - return [method]; - } - - protected override FieldProvider[] BuildFields() => []; - protected override ConstructorProvider[] BuildConstructors() => []; - protected override PropertyProvider[] BuildProperties() => []; - } - public static IEnumerable ValidateClientWithSpreadTestCases { get From 385c4b976b255444e319a547899037cb17e2fabc Mon Sep 17 00:00:00 2001 From: Dapeng Zhang Date: Wed, 4 Dec 2024 14:24:20 +0800 Subject: [PATCH 08/22] implement the feature of tokencredential --- .../src/Primitives/ScmKnownParameters.cs | 2 - .../Abstractions/ClientPipelineApi.cs | 5 +- .../Abstractions/IClientPipelineApi.cs | 3 + .../src/Providers/ClientPipelineProvider.cs | 19 +- .../src/Providers/ClientProvider.cs | 219 ++++++--- .../src/Providers/RestClientProvider.cs | 4 +- .../src/ScmTypeFactory.cs | 9 - .../OutputTypes/ScmKnownParametersTests.cs | 10 - .../Abstractions/ClientPipelineApiTests.cs | 11 +- .../ClientProviderAuthTests.cs | 44 +- .../ClientProviderNoAuthTests.cs | 415 ++++++++++++++++ .../ClientProviderOAuth2AuthTests.cs | 459 ++++++++++++++++++ .../ClientProviders/ClientProviderTests.cs | 18 - .../test/TestHelpers/MockHelpers.cs | 9 +- 14 files changed, 1082 insertions(+), 145 deletions(-) create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderNoAuthTests.cs create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderOAuth2AuthTests.cs diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Primitives/ScmKnownParameters.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Primitives/ScmKnownParameters.cs index fe2737a59a..00fa78fc93 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Primitives/ScmKnownParameters.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Primitives/ScmKnownParameters.cs @@ -30,8 +30,6 @@ internal static class ScmKnownParameters public static readonly ParameterProvider Data = new("data", FormattableStringHelpers.Empty, typeof(BinaryData)); public static ParameterProvider ClientOptions(CSharpType clientOptionsType) => new("options", $"The options for configuring the client.", clientOptionsType.WithNullable(true), initializationValue: New.Instance(clientOptionsType.WithNullable(true))); - public static readonly ParameterProvider KeyAuth = new("keyCredential", $"The token credential to copy", ClientModelPlugin.Instance.TypeFactory.KeyCredentialType); - public static readonly ParameterProvider MatchConditionsParameter = new("matchConditions", $"The content to send as the request conditions of the request.", ClientModelPlugin.Instance.TypeFactory.MatchConditionsType, DefaultOf(ClientModelPlugin.Instance.TypeFactory.MatchConditionsType)); public static readonly ParameterProvider OptionalRequestOptions = new( ClientModelPlugin.Instance.TypeFactory.HttpRequestOptionsApi.ParameterName, $"The request options, which can override default behaviors of the client pipeline on a per-call basis.", diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/Abstractions/ClientPipelineApi.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/Abstractions/ClientPipelineApi.cs index 627f5c90d5..9806d92915 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/Abstractions/ClientPipelineApi.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/Abstractions/ClientPipelineApi.cs @@ -14,6 +14,8 @@ public abstract record ClientPipelineApi : ScopedApi, IClientPipelineApi public abstract CSharpType ClientPipelineType { get; } public abstract CSharpType ClientPipelineOptionsType { get; } public abstract CSharpType PipelinePolicyType { get; } + public abstract CSharpType? KeyCredentialType { get; } + public abstract CSharpType? TokenCredentialType { get; } protected ClientPipelineApi(Type type, ValueExpression original) : base(type, original) { @@ -26,7 +28,8 @@ protected ClientPipelineApi(Type type, ValueExpression original) : base(type, or public abstract ValueExpression Create(ValueExpression options, ValueExpression perRetryPolicies); - public abstract ValueExpression AuthorizationPolicy(params ValueExpression[] arguments); + public abstract ValueExpression ConsumeKeyAuth(ValueExpression credential, ValueExpression headerName, ValueExpression? keyPrefix = null); + public abstract ValueExpression ConsumeOAuth2Auth(ValueExpression credential, ValueExpression scopes); public abstract ClientPipelineApi FromExpression(ValueExpression expression); public abstract ClientPipelineApi ToExpression(); } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/Abstractions/IClientPipelineApi.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/Abstractions/IClientPipelineApi.cs index 85f51aa1ee..dca1ebc635 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/Abstractions/IClientPipelineApi.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/Abstractions/IClientPipelineApi.cs @@ -10,5 +10,8 @@ public interface IClientPipelineApi : IExpressionApi CSharpType ClientPipelineType { get; } CSharpType ClientPipelineOptionsType { get; } CSharpType PipelinePolicyType { get; } + + CSharpType? KeyCredentialType { get; } + CSharpType? TokenCredentialType { get; } } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientPipelineProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientPipelineProvider.cs index 283861da85..39b9f6e82d 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientPipelineProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientPipelineProvider.cs @@ -7,6 +7,7 @@ using Microsoft.Generator.CSharp.Statements; using Microsoft.Generator.CSharp.Snippets; using static Microsoft.Generator.CSharp.Snippets.Snippet; +using System.ClientModel; namespace Microsoft.Generator.CSharp.ClientModel.Providers { @@ -25,6 +26,10 @@ public ClientPipelineProvider(ValueExpression original) : base(typeof(ClientPipe public override CSharpType PipelinePolicyType => typeof(PipelinePolicy); + public override CSharpType KeyCredentialType => typeof(ApiKeyCredential); + + public override CSharpType? TokenCredentialType => null; // Scm library does not support token credentials yet. + public override ValueExpression Create(ValueExpression options, ValueExpression perRetryPolicies) => Static().Invoke(nameof(ClientPipeline.Create), [options, New.Array(ClientModelPlugin.Instance.TypeFactory.ClientPipelineApi.PipelinePolicyType), perRetryPolicies, New.Array(ClientModelPlugin.Instance.TypeFactory.ClientPipelineApi.PipelinePolicyType)]).As(); @@ -34,8 +39,18 @@ public override ValueExpression CreateMessage(HttpRequestOptionsApi requestOptio public override ClientPipelineApi FromExpression(ValueExpression expression) => new ClientPipelineProvider(expression); - public override ValueExpression AuthorizationPolicy(params ValueExpression[] arguments) - => Static().Invoke(nameof(ApiKeyAuthenticationPolicy.CreateHeaderApiKeyPolicy), arguments).As(); + public override ValueExpression ConsumeKeyAuth(ValueExpression credential, ValueExpression headerName, ValueExpression? keyPrefix = null) + { + ValueExpression[] arguments = keyPrefix == null ? [credential, headerName] : [credential, headerName, keyPrefix]; + return Static().Invoke(nameof(ApiKeyAuthenticationPolicy.CreateHeaderApiKeyPolicy), arguments).As(); + } + + public override ValueExpression ConsumeOAuth2Auth(ValueExpression credential, ValueExpression scopes) + { + // Scm library does not support token credentials yet. The throw here is intentional. + // For a plugin that supports token credentials, they could override this implementation as well as the above TokenCredentialType property. + throw new System.NotImplementedException(); + } public override ClientPipelineApi ToExpression() => this; diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientProvider.cs index 6ea60345e8..b90ac04099 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientProvider.cs @@ -22,6 +22,8 @@ public class ClientProvider : TypeProvider private const string AuthorizationHeaderConstName = "AuthorizationHeader"; private const string AuthorizationApiKeyPrefixConstName = "AuthorizationApiKeyPrefix"; private const string ApiKeyCredentialFieldName = "_keyCredential"; + private const string TokenCredentialScopesFieldName = "AuthorizationScopes"; + private const string TokenCredentialFieldName = "_tokenCredential"; private const string EndpointFieldName = "_endpoint"; private const string ClientSuffix = "Client"; private readonly FormattableString _publicCtorDescription; @@ -29,11 +31,16 @@ public class ClientProvider : TypeProvider private readonly InputAuth? _inputAuth; private readonly ParameterProvider _endpointParameter; private readonly FieldProvider? _clientCachingField; + + #region credential fields private readonly FieldProvider? _apiKeyAuthField; private readonly FieldProvider? _authorizationHeaderConstant; private readonly FieldProvider? _authorizationApiKeyPrefixConstant; + private readonly FieldProvider? _tokenCredentialField; + private readonly FieldProvider? _tokenCredentialScopesField; + #endregion private FieldProvider? _apiVersionField; - private readonly List _subClientInternalConstructorParams; + private readonly Lazy> _subClientInternalConstructorParams; private IReadOnlyList>? _subClients; private ParameterProvider? _clientOptionsParameter; private ClientOptionsProvider? _clientOptions; @@ -61,24 +68,55 @@ public ClientProvider(InputClient inputClient) _publicCtorDescription = $"Initializes a new instance of {Name}."; var apiKey = _inputAuth?.ApiKey; - _apiKeyAuthField = apiKey != null ? new FieldProvider( - FieldModifiers.Private | FieldModifiers.ReadOnly, - ClientModelPlugin.Instance.TypeFactory.KeyCredentialType, - ApiKeyCredentialFieldName, - this, - description: $"A credential used to authenticate to the service.") : null; - _authorizationHeaderConstant = apiKey?.Name != null ? new( - FieldModifiers.Private | FieldModifiers.Const, - typeof(string), - AuthorizationHeaderConstName, - this, - initializationValue: Literal(apiKey.Name)) : null; - _authorizationApiKeyPrefixConstant = apiKey?.Prefix != null ? new( - FieldModifiers.Private | FieldModifiers.Const, - typeof(string), - AuthorizationApiKeyPrefixConstName, - this, - initializationValue: Literal(apiKey.Prefix)) : null; + var keyCredentialType = ClientModelPlugin.Instance.TypeFactory.ClientPipelineApi.KeyCredentialType; + if (apiKey != null && keyCredentialType != null) + { + _apiKeyAuthField = new FieldProvider( + FieldModifiers.Private | FieldModifiers.ReadOnly, + keyCredentialType, + ApiKeyCredentialFieldName, + this, + description: $"A credential used to authenticate to the service."); + if (apiKey.Name != null) + { + _authorizationHeaderConstant = new FieldProvider( + FieldModifiers.Private | FieldModifiers.Const, + typeof(string), + AuthorizationHeaderConstName, + this, + initializationValue: Literal(apiKey.Name)); + } + if (apiKey.Prefix != null) + { + _authorizationApiKeyPrefixConstant = new FieldProvider( + FieldModifiers.Private | FieldModifiers.Const, + typeof(string), + AuthorizationApiKeyPrefixConstName, + this, + initializationValue: Literal(apiKey.Prefix)); + } + } + // in this plugin, the type of TokenCredential is null therefore these code will never be executed, but it should be invoked in other plugins that could support it. + var tokenAuth = _inputAuth?.OAuth2; + var tokenCredentialType = ClientModelPlugin.Instance.TypeFactory.ClientPipelineApi.TokenCredentialType; + if (tokenAuth != null && tokenCredentialType != null) + { + _tokenCredentialField = new FieldProvider( + FieldModifiers.Private | FieldModifiers.ReadOnly, + tokenCredentialType, + TokenCredentialFieldName, + this, + description: $"A credential used to authenticate to the service."); + if (tokenAuth.Scopes != null) + { + _tokenCredentialScopesField = new FieldProvider( + FieldModifiers.Private | FieldModifiers.Const, + typeof(string[]), + TokenCredentialScopesFieldName, + this, + initializationValue: New.Array(typeof(string), tokenAuth.Scopes.Select(s => Literal(s)).ToArray())); + } + } EndpointField = new( FieldModifiers.Private | FieldModifiers.ReadOnly, typeof(Uri), @@ -92,10 +130,6 @@ public ClientProvider(InputClient inputClient) body: new AutoPropertyBody(false), enclosingType: this); - _subClientInternalConstructorParams = _apiKeyAuthField != null - ? [PipelineProperty.AsParameter, _apiKeyAuthField.AsParameter, _endpointParameter] - : [PipelineProperty.AsParameter, _endpointParameter]; - if (_inputClient.Parent != null) { // _clientCachingField will only have subClients (children) @@ -108,23 +142,43 @@ public ClientProvider(InputClient inputClient) } _endpointParameterName = new(GetEndpointParameterName); - _additionalClientFields = new Lazy>(() => BuildAdditionalClientFields()); + _additionalClientFields = new(BuildAdditionalClientFields); _allClientParameters = _inputClient.Parameters.Concat(_inputClient.Operations.SelectMany(op => op.Parameters).Where(p => p.Kind == InputOperationParameterKind.Client)).DistinctBy(p => p.Name).ToArray(); + _subClientInternalConstructorParams = new(GetSubClientInternalConstructorParameters); + _clientParameters = new(GetClientParameters); + } - foreach (var field in _additionalClientFields.Value) + private IReadOnlyList GetSubClientInternalConstructorParameters() + { + var subClientParameters = new List + { + PipelineProperty.AsParameter + }; + + if (_apiKeyAuthField != null) + { + subClientParameters.Add(_apiKeyAuthField.AsParameter); + } + if (_tokenCredentialField != null) { - _subClientInternalConstructorParams.Add(field.AsParameter); + subClientParameters.Add(_tokenCredentialField.AsParameter); } + subClientParameters.Add(_endpointParameter); + subClientParameters.AddRange(ClientParameters); + + return subClientParameters; } - private List? _clientParameters; - internal IReadOnlyList GetClientParameters() + private Lazy> _clientParameters; + internal IReadOnlyList ClientParameters => _clientParameters.Value; + private IReadOnlyList GetClientParameters() { - if (_clientParameters is null) + var parameters = new List(_additionalClientFields.Value.Count); + foreach (var field in _additionalClientFields.Value) { - _ = Constructors; + parameters.Add(field.AsParameter); } - return _clientParameters ?? []; + return parameters; } private Lazy _endpointParameterName; @@ -170,6 +224,15 @@ protected override FieldProvider[] BuildFields() } } + if (_tokenCredentialField != null) + { + fields.Add(_tokenCredentialField); + } + if (_tokenCredentialScopesField != null) + { + fields.Add(_tokenCredentialScopesField); + } + fields.AddRange(_additionalClientFields.Value); // add sub-client caching fields @@ -225,46 +288,71 @@ protected override ConstructorProvider[] BuildConstructors() // handle sub-client constructors if (ClientOptionsParameter is null) { - _clientParameters = _subClientInternalConstructorParams; - List body = new(3) { EndpointField.Assign(_endpointParameter).Terminate() }; - foreach (var p in _subClientInternalConstructorParams) - { - var assignment = p.Field?.Assign(p).Terminate() ?? p.Property?.Assign(p).Terminate(); - if (assignment != null) + List body = new(3) { EndpointField.Assign(_endpointParameter).Terminate() }; + foreach (var p in _subClientInternalConstructorParams.Value) { - body.Add(assignment); + var assignment = p.Field?.Assign(p).Terminate() ?? p.Property?.Assign(p).Terminate(); + if (assignment != null) + { + body.Add(assignment); + } } - } - var subClientConstructor = new ConstructorProvider( - new ConstructorSignature(Type, _publicCtorDescription, MethodSignatureModifiers.Internal, _subClientInternalConstructorParams), - body, - this); + var subClientConstructor = new ConstructorProvider( + new ConstructorSignature(Type, _publicCtorDescription, MethodSignatureModifiers.Internal, _subClientInternalConstructorParams.Value), + body, + this); return [mockingConstructor, subClientConstructor]; } - var requiredParameters = GetRequiredParameters(); - ParameterProvider[] primaryConstructorParameters = [_endpointParameter, .. requiredParameters, ClientOptionsParameter]; - var primaryConstructor = new ConstructorProvider( - new ConstructorSignature(Type, _publicCtorDescription, MethodSignatureModifiers.Public, primaryConstructorParameters), - BuildPrimaryConstructorBody(primaryConstructorParameters), - this); + // we need to construct two sets of constructors for both auth we supported if any. + var primaryConstructors = new List(); + var secondaryConstructors = new List(); - // If the endpoint parameter contains an initialization value, it is not required. - ParameterProvider[] secondaryConstructorParameters = _endpointParameter.InitializationValue is null - ? [_endpointParameter, .. requiredParameters] - : [.. requiredParameters]; - var secondaryConstructor = BuildSecondaryConstructor(secondaryConstructorParameters, primaryConstructorParameters); - var shouldIncludeMockingConstructor = secondaryConstructorParameters.Length > 0 || _apiKeyAuthField != null; + // if there is key auth + if (_apiKeyAuthField != null) + { + AppendConstructors(_apiKeyAuthField, primaryConstructors, secondaryConstructors); + } + // if there is oauth2 auth + if (_tokenCredentialField != null) + { + AppendConstructors(_tokenCredentialField, primaryConstructors, secondaryConstructors); + } + // if there is no auth + if (_apiKeyAuthField == null && _tokenCredentialField == null) + { + AppendConstructors(null, primaryConstructors, secondaryConstructors); + } + var shouldIncludeMockingConstructor = secondaryConstructors.All(c => c.Signature.Parameters.Count > 0); return shouldIncludeMockingConstructor - ? [ConstructorProviderHelper.BuildMockingConstructor(this), secondaryConstructor, primaryConstructor] - : [secondaryConstructor, primaryConstructor]; + ? [ConstructorProviderHelper.BuildMockingConstructor(this), .. secondaryConstructors, .. primaryConstructors] + : [.. secondaryConstructors, .. primaryConstructors]; + + void AppendConstructors(FieldProvider? authField, List primaryConstructors, List secondaryConstructors) + { + var requiredParameters = GetRequiredParameters(authField); + ParameterProvider[] primaryConstructorParameters = [_endpointParameter, .. requiredParameters, ClientOptionsParameter]; + var primaryConstructor = new ConstructorProvider( + new ConstructorSignature(Type, _publicCtorDescription, MethodSignatureModifiers.Public, primaryConstructorParameters), + BuildPrimaryConstructorBody(primaryConstructorParameters), + this); + + primaryConstructors.Add(primaryConstructor); + + // If the endpoint parameter contains an initialization value, it is not required. + ParameterProvider[] secondaryConstructorParameters = _endpointParameter.InitializationValue is null + ? [_endpointParameter, .. requiredParameters] + : [.. requiredParameters]; + var secondaryConstructor = BuildSecondaryConstructor(secondaryConstructorParameters, primaryConstructorParameters); + + secondaryConstructors.Add(secondaryConstructor); + } } - private IReadOnlyList GetRequiredParameters() + private IReadOnlyList GetRequiredParameters(FieldProvider? authField) { List requiredParameters = []; - _clientParameters = []; ParameterProvider? currentParam = null; foreach (var parameter in _allClientParameters) @@ -275,11 +363,10 @@ private IReadOnlyList GetRequiredParameters() currentParam = CreateParameter(parameter); requiredParameters.Add(currentParam); } - _clientParameters.Add(currentParam ?? CreateParameter(parameter)); } - if (_apiKeyAuthField is not null) - requiredParameters.Add(_apiKeyAuthField.AsParameter); + if (authField is not null) + requiredParameters.Add(authField.AsParameter); return requiredParameters; } @@ -318,10 +405,8 @@ private MethodBodyStatement[] BuildPrimaryConstructorBody(IReadOnlyList().AuthorizationPolicy(authorizationPolicyArgs)); + ValueExpression? keyPrefix = _authorizationApiKeyPrefixConstant != null ? (ValueExpression)_authorizationApiKeyPrefixConstant : null; + perRetryPolicies = New.Array(ClientModelPlugin.Instance.TypeFactory.ClientPipelineApi.PipelinePolicyType, isInline: true, This.ToApi().ConsumeKeyAuth(_apiKeyAuthField, _authorizationHeaderConstant, keyPrefix)); } body.Add(PipelineProperty.Assign(This.ToApi().Create(ClientOptionsParameter, perRetryPolicies)).Terminate()); @@ -410,7 +495,7 @@ protected override MethodProvider[] BuildMethods() List subClientConstructorArgs = new(3); // Populate constructor arguments - foreach (var param in subClientInstance._subClientInternalConstructorParams) + foreach (var param in subClientInstance._subClientInternalConstructorParams.Value) { if (parentClientProperties.TryGetValue(param.Name, out var parentProperty)) { diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/RestClientProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/RestClientProvider.cs index 232e030537..65c737b876 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/RestClientProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/RestClientProvider.cs @@ -97,7 +97,7 @@ private MethodProvider BuildCreateRequestMethod(InputOperation operation) [.. parameters, options]); var paramMap = new Dictionary(signature.Parameters.ToDictionary(p => p.Name)); - foreach (var param in ClientProvider.GetClientParameters()) + foreach (var param in ClientProvider.ClientParameters) { paramMap[param.Name] = param; } @@ -356,7 +356,7 @@ private void AddUriSegments( /* when the parameter is in operation.uri, it is client parameter * It is not operation parameter and not in inputParamHash list. */ - var isClientParameter = ClientProvider.GetClientParameters().Any(p => p.Name == paramName); + var isClientParameter = ClientProvider.ClientParameters.Any(p => p.Name == paramName); CSharpType? type; string? format; ValueExpression valueExpression; diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/ScmTypeFactory.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/ScmTypeFactory.cs index 18364b2d46..3a63e2614b 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/ScmTypeFactory.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/ScmTypeFactory.cs @@ -2,21 +2,16 @@ // Licensed under the MIT License. using System; -using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; -using System.IO; -using System.Net; using System.Text.Json; using Microsoft.Generator.CSharp.ClientModel.Providers; -using Microsoft.Generator.CSharp.ClientModel.Snippets; using Microsoft.Generator.CSharp.Expressions; using Microsoft.Generator.CSharp.Input; using Microsoft.Generator.CSharp.Primitives; using Microsoft.Generator.CSharp.Providers; using Microsoft.Generator.CSharp.Snippets; using Microsoft.Generator.CSharp.Statements; -using static Microsoft.Generator.CSharp.Snippets.Snippet; namespace Microsoft.Generator.CSharp.ClientModel { @@ -27,10 +22,6 @@ public class ScmTypeFactory : TypeFactory public virtual CSharpType MatchConditionsType => typeof(PipelineMessageClassifier); - public virtual CSharpType KeyCredentialType => typeof(ApiKeyCredential); - - public virtual CSharpType TokenCredentialType => throw new NotImplementedException("Token credential is not supported in Scm libraries yet"); - public virtual IClientResponseApi ClientResponseApi => ClientResultProvider.Instance; public virtual IHttpResponseApi HttpResponseApi => PipelineResponseProvider.Instance; diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/OutputTypes/ScmKnownParametersTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/OutputTypes/ScmKnownParametersTests.cs index 091102c8de..063aa6c659 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/OutputTypes/ScmKnownParametersTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/OutputTypes/ScmKnownParametersTests.cs @@ -8,16 +8,6 @@ namespace Microsoft.Generator.CSharp.ClientModel.Tests.OutputTypes { internal class ScmKnownParametersTests { - [Test] - public void TestTokenAuth() - { - MockHelpers.LoadMockPlugin(keyCredentialType: () => typeof(int)); - - var result = ClientModelPlugin.Instance.TypeFactory.KeyCredentialType; - Assert.IsNotNull(result); - Assert.AreEqual(new CSharpType(typeof(int)), result); - } - [TestCase] public void TestMatchConditionsParameter() { diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/Abstractions/ClientPipelineApiTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/Abstractions/ClientPipelineApiTests.cs index f7e5bd92c9..80b68173bb 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/Abstractions/ClientPipelineApiTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/Abstractions/ClientPipelineApiTests.cs @@ -55,6 +55,10 @@ public TestClientPipelineApi(ValueExpression original) : base(typeof(string), or public override CSharpType PipelinePolicyType => typeof(string); + public override CSharpType KeyCredentialType => typeof(object); + + public override CSharpType TokenCredentialType => typeof(object); + public override ValueExpression Create(ValueExpression options, ValueExpression perRetryPolicies) => Original.Invoke("GetFakeCreate", [options, perRetryPolicies]); @@ -64,8 +68,11 @@ public override ValueExpression CreateMessage(HttpRequestOptionsApi requestOptio public override ClientPipelineApi FromExpression(ValueExpression expression) => new TestClientPipelineApi(expression); - public override ValueExpression AuthorizationPolicy(params ValueExpression[] arguments) - => Original.Invoke("GetFakeAuthorizationPolicy", arguments); + public override ValueExpression ConsumeKeyAuth(ValueExpression credential, ValueExpression headerName, ValueExpression? keyPrefix = null) + => Original.Invoke("GetFakeAuthorizationPolicy", keyPrefix == null ? [credential, headerName] : [credential, headerName, keyPrefix]); + + public override ValueExpression ConsumeOAuth2Auth(ValueExpression credential, ValueExpression scopes) + => Original.Invoke("GetFakeTokenAuthorizationPolicy", [credential, scopes]); public override ClientPipelineApi ToExpression() => this; diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderAuthTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderAuthTests.cs index b589360937..50b01e993e 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderAuthTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderAuthTests.cs @@ -22,6 +22,8 @@ namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders public class ClientProviderAuthTests { private const string SubClientsCategory = "WithSubClients"; + private const string KeyAuthCategory = "KeyAuth"; + private const string OAuth2Category = "OAuth2"; private const string TestClientName = "TestClient"; private static readonly InputClient _animalClient = new("animal", "AnimalClient description", [], [], TestClientName); private static readonly InputClient _dogClient = new("dog", "DogClient description", [], [], _animalClient.Name); @@ -32,27 +34,30 @@ public void SetUp() { var categories = TestContext.CurrentContext.Test?.Properties["Category"]; bool containsSubClients = categories?.Contains(SubClientsCategory) ?? false; - - if (containsSubClients) - { - MockHelpers.LoadMockPlugin( - apiKeyAuth: () => new InputApiKeyAuth("mock", null), - clients: () => [_animalClient, _dogClient, _huskyClient]); - } - else - { - MockHelpers.LoadMockPlugin(apiKeyAuth: () => new InputApiKeyAuth("mock", null)); - } + bool hasKeyAuth = categories?.Contains(KeyAuthCategory) ?? false; + bool hasOAuth2 = categories?.Contains(OAuth2Category) ?? false; + + Func>? clients = containsSubClients ? + () => [_animalClient, _dogClient, _huskyClient] : + null; + Func? apiKeyAuth = hasKeyAuth ? () => new InputApiKeyAuth("mock", null) : null; + Func? oauth2Auth = hasOAuth2 ? () => new InputOAuth2Auth(["mock"]) : null; + MockHelpers.LoadMockPlugin( + apiKeyAuth: apiKeyAuth, + oauth2Auth: oauth2Auth, + clients: clients); } - [TestCaseSource(nameof(BuildFieldsTestCases))] - public void TestBuildFields(List inputParameters, List expectedFields) + [TestCaseSource(nameof(BuildFieldsTestCases), Category = KeyAuthCategory)] + public void TestBuildFields(List inputParameters) { var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); var clientProvider = new ClientProvider(client); Assert.IsNotNull(clientProvider); + // key auth should have the following fields: AuthorizationHeader, _keyCredential + AssertHasFields(clientProvider, expectedFields); } @@ -257,13 +262,7 @@ public static IEnumerable BuildFieldsTestCases location:RequestLocation.None, kind: InputOperationParameterKind.Client, isEndpoint: true) - }, - new List - { - new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string)), "AuthorizationHeader"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(ApiKeyCredential)), "_keyCredential"), - } - ); + }); yield return new TestCaseData(new List { // have to explicitly set isRequired because we now call CreateParameter in buildFields @@ -295,11 +294,6 @@ public static IEnumerable BuildFieldsTestCases defaultValue: null, kind: InputOperationParameterKind.Client, isEndpoint: true) - }, - new List - { - new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string)), "AuthorizationHeader"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(ApiKeyCredential)), "_keyCredential"), }); } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderNoAuthTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderNoAuthTests.cs new file mode 100644 index 0000000000..79072a1dab --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderNoAuthTests.cs @@ -0,0 +1,415 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Generator.CSharp.ClientModel.Providers; +using Microsoft.Generator.CSharp.Expressions; +using Microsoft.Generator.CSharp.Input; +using Microsoft.Generator.CSharp.Primitives; +using Microsoft.Generator.CSharp.Providers; +using Microsoft.Generator.CSharp.Snippets; +using Microsoft.Generator.CSharp.Statements; +using Microsoft.Generator.CSharp.Tests.Common; +using NUnit.Framework; +using static Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders.ClientProviderTestsUtils; +using static Microsoft.Generator.CSharp.Snippets.Snippet; + +namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders +{ + public class ClientProviderNoAuthTests + { + private const string SubClientsCategory = "WithSubClients"; + private const string TestClientName = "TestClient"; + private static readonly InputClient _animalClient = new("animal", "AnimalClient description", [], [], TestClientName); + private static readonly InputClient _dogClient = new("dog", "DogClient description", [], [], _animalClient.Name); + private static readonly InputClient _huskyClient = new("husky", "HuskyClient description", [], [], _dogClient.Name); + + [SetUp] + public void SetUp() + { + var categories = TestContext.CurrentContext.Test?.Properties["Category"]; + bool containsSubClients = categories?.Contains(SubClientsCategory) ?? false; + + if (containsSubClients) + { + MockHelpers.LoadMockPlugin( + clients: () => [_animalClient, _dogClient, _huskyClient]); + } + else + { + MockHelpers.LoadMockPlugin(); + } + } + + [Test] + public void TestBuildProperties() + { + var client = InputFactory.Client(TestClientName); + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + // validate the properties + var properties = clientProvider.Properties; + Assert.IsTrue(properties.Count > 0); + // there should be a pipeline property + Assert.AreEqual(1, properties.Count); + + var pipelineProperty = properties[0]; + Assert.AreEqual(typeof(ClientPipeline), pipelineProperty.Type.FrameworkType); + Assert.AreEqual("Pipeline", pipelineProperty.Name); + Assert.AreEqual(MethodSignatureModifiers.Public, pipelineProperty.Modifiers); + } + + [TestCaseSource(nameof(BuildFieldsTestCases))] + public void TestBuildFields(List inputParameters, List expectedFields) + { + var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + AssertClientFields(clientProvider, expectedFields); + } + + // validates the fields are built correctly when a client has sub-clients + [TestCaseSource(nameof(SubClientFieldsTestCases), Category = SubClientsCategory)] + public void TestBuildFields_WithSubClients(InputClient client, List expectedFields) + { + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + AssertClientFields(clientProvider, expectedFields); + } + + [TestCaseSource(nameof(BuildConstructorsTestCases))] + public void TestBuildConstructors_PrimaryConstructor(List inputParameters, int expectedCount) + { + var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + var constructors = clientProvider.Constructors; + Assert.AreEqual(expectedCount, constructors.Count); + + var primaryPublicConstructor = constructors.FirstOrDefault( + c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); + ValidatePrimaryConstructor(primaryPublicConstructor, inputParameters); + } + + [TestCaseSource(nameof(BuildConstructorsTestCases))] + public void TestBuildConstructors_SecondaryConstructor(List inputParameters, int expectedCount) + { + var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + var constructors = clientProvider.Constructors; + + Assert.AreEqual(expectedCount, constructors.Count); + var primaryPublicConstructor = constructors.FirstOrDefault( + c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); + + Assert.IsNotNull(primaryPublicConstructor); + + var secondaryPublicConstructor = constructors.FirstOrDefault( + c => c.Signature?.Initializer != null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); + ValidateSecondaryConstructor(primaryPublicConstructor, secondaryPublicConstructor, inputParameters); + } + + [Test] + public void TestBuildConstructors_ForSubClient() + { + var clientProvider = new ClientProvider(_animalClient); + + Assert.IsNotNull(clientProvider); + + var constructors = clientProvider.Constructors; + + Assert.AreEqual(2, constructors.Count); + var internalConstructor = constructors.FirstOrDefault( + c => c.Signature?.Modifiers == MethodSignatureModifiers.Internal); + Assert.IsNotNull(internalConstructor); + var ctorParams = internalConstructor?.Signature?.Parameters; + Assert.AreEqual(2, ctorParams?.Count); // only 2 because there is no credential parameter + + var mockingConstructor = constructors.FirstOrDefault( + c => c.Signature?.Modifiers == MethodSignatureModifiers.Protected); + Assert.IsNotNull(mockingConstructor); + } + + private static void ValidatePrimaryConstructor( + ConstructorProvider? primaryPublicConstructor, + List inputParameters) + { + Assert.IsNotNull(primaryPublicConstructor); + + var primaryCtorParams = primaryPublicConstructor?.Signature?.Parameters; + + Assert.AreEqual(2, primaryCtorParams?.Count); // only 2 because there is no credential parameter + + // validate the order of the parameters (endpoint, credential, client options) + var endpointParam = primaryCtorParams?[0]; + Assert.AreEqual(KnownParameters.Endpoint.Name, endpointParam?.Name); + Assert.AreEqual("options", primaryCtorParams?[1].Name); + + if (endpointParam?.DefaultValue != null) + { + var inputEndpointParam = inputParameters.FirstOrDefault(p => p.IsEndpoint); + var parsedValue = inputEndpointParam?.DefaultValue?.Value; + Assert.AreEqual(Literal(parsedValue), endpointParam?.InitializationValue); + } + + // validate the body of the primary ctor + var primaryCtorBody = primaryPublicConstructor?.BodyStatements; + Assert.IsNotNull(primaryCtorBody); + } + + private void ValidateSecondaryConstructor( + ConstructorProvider? primaryConstructor, + ConstructorProvider? secondaryPublicConstructor, + List inputParameters) + { + Assert.IsNotNull(secondaryPublicConstructor); + var ctorParams = secondaryPublicConstructor?.Signature?.Parameters; + + // secondary ctor should consist of all required parameters + auth parameter, but here we do not have auth, therefore they should be the same + var requiredParams = inputParameters.Where(p => p.IsRequired).ToList(); + Assert.AreEqual(requiredParams.Count, ctorParams?.Count); + var endpointParam = ctorParams?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); + + if (requiredParams.Count == 0) + { + // there should be no parameter if endpoint is optional and we do not have an auth + Assert.AreEqual(0, ctorParams?.Count); + } + else + { + // otherwise, it should only consist of the endpoint parameter + Assert.AreEqual(KnownParameters.Endpoint.Name, ctorParams?[0].Name); + } + + Assert.AreEqual(MethodBodyStatement.Empty, secondaryPublicConstructor?.BodyStatements); + + // validate the initializer + var initializer = secondaryPublicConstructor?.Signature?.Initializer; + Assert.AreEqual(primaryConstructor?.Signature?.Parameters?.Count, initializer?.Arguments?.Count); + } + + [TestCaseSource(nameof(EndpointParamInitializationValueTestCases))] + public void EndpointInitializationValue(InputParameter endpointParameter, ValueExpression? expectedValue) + { + var client = InputFactory.Client(TestClientName, parameters: [endpointParameter]); + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + // find the endpoint parameter from the primary constructor + var primaryConstructor = clientProvider.Constructors.FirstOrDefault( + c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); + var endpoint = primaryConstructor?.Signature?.Parameters?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); + + Assert.IsNotNull(endpoint); + Assert.AreEqual(expectedValue?.GetType(), endpoint?.InitializationValue?.GetType()); + if (expectedValue != null) + { + Assert.IsTrue(endpoint?.InitializationValue is NewInstanceExpression); + } + } + + [TestCaseSource(nameof(SubClientFactoryMethodTestCases), Category = SubClientsCategory)] + public void TestSubClientAccessorFactoryMethods(InputClient client, bool hasSubClients) + { + var clientProvider = new ClientProvider(client); + Assert.IsNotNull(clientProvider); + + var methods = clientProvider.Methods; + List subClientAccessorFactoryMethods = []; + foreach (var method in methods) + { + var methodSignature = method.Signature; + if (methodSignature != null && + methodSignature.Name.StartsWith("Get") && + methodSignature.Modifiers.HasFlag(MethodSignatureModifiers.Public | MethodSignatureModifiers.Virtual)) + { + subClientAccessorFactoryMethods.Add(method); + } + } + + if (hasSubClients) + { + Assert.AreEqual(1, subClientAccessorFactoryMethods.Count); + var factoryMethod = subClientAccessorFactoryMethods[0]; + Assert.AreEqual(0, factoryMethod.Signature?.Parameters.Count); + + // method body should not be empty + Assert.AreNotEqual(MethodBodyStatement.Empty, factoryMethod.BodyStatements); + } + else + { + Assert.AreEqual(0, subClientAccessorFactoryMethods.Count); + } + } + + public static IEnumerable BuildFieldsTestCases + { + get + { + yield return new TestCaseData(new List + { + InputFactory.Parameter( + "optionalParam", + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client), + InputFactory.Parameter( + KnownParameters.Endpoint.Name, + InputPrimitiveType.String, + location:RequestLocation.None, + kind: InputOperationParameterKind.Client, + isEndpoint: true) + }, + new List + { + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), true), "_optionalParam") + } + ); + yield return new TestCaseData(new List + { + // have to explicitly set isRequired because we now call CreateParameter in buildFields + InputFactory.Parameter( + "optionalNullableParam", + InputPrimitiveType.String, + location: RequestLocation.None, + defaultValue: InputFactory.Constant.String("someValue"), + kind: InputOperationParameterKind.Client, + isRequired: false), + InputFactory.Parameter( + "requiredParam2", + InputPrimitiveType.String, + location: RequestLocation.None, + defaultValue: InputFactory.Constant.String("someValue"), + kind: InputOperationParameterKind.Client, + isRequired: true), + InputFactory.Parameter( + "requiredParam3", + InputPrimitiveType.Int64, + location: RequestLocation.None, + defaultValue: InputFactory.Constant.Int64(2), + kind: InputOperationParameterKind.Client, + isRequired: true), + InputFactory.Parameter( + KnownParameters.Endpoint.Name, + InputPrimitiveType.String, + location: RequestLocation.None, + defaultValue: null, + kind: InputOperationParameterKind.Client, + isEndpoint: true) + }, + new List + { + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), true), "_optionalNullableParam"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), false), "_requiredParam2"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(long), false), "_requiredParam3") + }); + } + } + + public static IEnumerable SubClientFieldsTestCases + { + get + { + yield return new TestCaseData(InputFactory.Client(TestClientName), new List + { + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + new(FieldModifiers.Private, new ExpectedCSharpType("Animal", "Sample", true), "_cachedAnimal"), + }); + yield return new TestCaseData(_animalClient, new List + { + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + new(FieldModifiers.Private, new ExpectedCSharpType("Dog", "Sample", true), "_cachedDog"), + }); + yield return new TestCaseData(_dogClient, new List + { + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + new(FieldModifiers.Private, new ExpectedCSharpType("Husky", "Sample", true), "_cachedHusky"), + }); + yield return new TestCaseData(_huskyClient, new List + { + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + }); + } + } + + public static IEnumerable SubClientFactoryMethodTestCases + { + get + { + yield return new TestCaseData(InputFactory.Client(TestClientName), true); + yield return new TestCaseData(_animalClient, true); + yield return new TestCaseData(_dogClient, true); + yield return new TestCaseData(_huskyClient, false); + } + } + + public static IEnumerable BuildConstructorsTestCases + { + get + { + yield return new TestCaseData(new List + { + InputFactory.Parameter( + "optionalParam", + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client), + InputFactory.Parameter( + KnownParameters.Endpoint.Name, + InputPrimitiveType.String, + location: RequestLocation.None, + defaultValue: InputFactory.Constant.String("someValue"), + kind: InputOperationParameterKind.Client, + isEndpoint: true) + }, 2); // in this case, the secondary ctor has the same ctor list as the protected ctor + // scenario where endpoint is required + yield return new TestCaseData(new List + { + InputFactory.Parameter( + KnownParameters.Endpoint.Name, + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client, + isRequired: true, + isEndpoint: true), + InputFactory.Parameter( + "optionalParam", + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client) + }, 3); + } + } + + private static IEnumerable EndpointParamInitializationValueTestCases() + { + // string primitive type + yield return new TestCaseData( + InputFactory.Parameter( + "param", + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client, + isEndpoint: true, + defaultValue: InputFactory.Constant.String("mockValue")), + New.Instance(KnownParameters.Endpoint.Type, Literal("mockvalue"))); + } + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderOAuth2AuthTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderOAuth2AuthTests.cs new file mode 100644 index 0000000000..efbb7d254d --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderOAuth2AuthTests.cs @@ -0,0 +1,459 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Generator.CSharp.ClientModel.Providers; +using Microsoft.Generator.CSharp.Expressions; +using Microsoft.Generator.CSharp.Input; +using Microsoft.Generator.CSharp.Primitives; +using Microsoft.Generator.CSharp.Providers; +using Microsoft.Generator.CSharp.Snippets; +using Microsoft.Generator.CSharp.Statements; +using Microsoft.Generator.CSharp.Tests.Common; +using NUnit.Framework; +using static Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders.ClientProviderTestsUtils; +using static Microsoft.Generator.CSharp.Snippets.Snippet; + +namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders +{ + public class ClientProviderOAuth2AuthTests + { + private const string SubClientsCategory = "WithSubClients"; + private const string TestClientName = "TestClient"; + private static readonly InputClient _animalClient = new("animal", "AnimalClient description", [], [], TestClientName); + private static readonly InputClient _dogClient = new("dog", "DogClient description", [], [], _animalClient.Name); + private static readonly InputClient _huskyClient = new("husky", "HuskyClient description", [], [], _dogClient.Name); + + [SetUp] + public void SetUp() + { + var categories = TestContext.CurrentContext.Test?.Properties["Category"]; + bool containsSubClients = categories?.Contains(SubClientsCategory) ?? false; + + if (containsSubClients) + { + MockHelpers.LoadMockPlugin( + oauth2Auth: () => new InputOAuth2Auth(["mock"]), + clients: () => [_animalClient, _dogClient, _huskyClient], + clientPipelineApi: TestClientPipelineApi.Instance); + } + else + { + MockHelpers.LoadMockPlugin( + oauth2Auth: () => new InputOAuth2Auth(["mock"]), + clientPipelineApi: TestClientPipelineApi.Instance); + } + } + + [TestCaseSource(nameof(BuildFieldsTestCases))] + public void TestBuildFields(List inputParameters, List expectedFields) + { + var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + AssertClientFields(clientProvider, expectedFields); + } + + // validates the fields are built correctly when a client has sub-clients + [TestCaseSource(nameof(SubClientFieldsTestCases), Category = SubClientsCategory)] + public void TestBuildFields_WithSubClients(InputClient client, List expectedFields) + { + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + AssertClientFields(clientProvider, expectedFields); + } + + [TestCaseSource(nameof(BuildConstructorsTestCases))] + public void TestBuildConstructors_PrimaryConstructor(List inputParameters) + { + var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + var constructors = clientProvider.Constructors; + Assert.AreEqual(3, constructors.Count); + + var primaryPublicConstructor = constructors.FirstOrDefault( + c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); + ValidatePrimaryConstructor(primaryPublicConstructor, inputParameters); + } + + [TestCaseSource(nameof(BuildConstructorsTestCases))] + public void TestBuildConstructors_SecondaryConstructor(List inputParameters) + { + var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + var constructors = clientProvider.Constructors; + + Assert.AreEqual(3, constructors.Count); + var primaryPublicConstructor = constructors.FirstOrDefault( + c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); + + Assert.IsNotNull(primaryPublicConstructor); + + var secondaryPublicConstructor = constructors.FirstOrDefault( + c => c.Signature?.Initializer != null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); + ValidateSecondaryConstructor(primaryPublicConstructor, secondaryPublicConstructor, inputParameters); + } + + [Test] + public void TestBuildConstructors_ForSubClient() + { + var clientProvider = new ClientProvider(_animalClient); + + Assert.IsNotNull(clientProvider); + + var constructors = clientProvider.Constructors; + + Assert.AreEqual(2, constructors.Count); + var internalConstructor = constructors.FirstOrDefault( + c => c.Signature?.Modifiers == MethodSignatureModifiers.Internal); + Assert.IsNotNull(internalConstructor); + var ctorParams = internalConstructor?.Signature?.Parameters; + Assert.AreEqual(3, ctorParams?.Count); + + var mockingConstructor = constructors.FirstOrDefault( + c => c.Signature?.Modifiers == MethodSignatureModifiers.Protected); + Assert.IsNotNull(mockingConstructor); + } + + private static void ValidatePrimaryConstructor( + ConstructorProvider? primaryPublicConstructor, + List inputParameters) + { + Assert.IsNotNull(primaryPublicConstructor); + + var primaryCtorParams = primaryPublicConstructor?.Signature?.Parameters; + var expectedPrimaryCtorParamCount = 3; + + Assert.AreEqual(expectedPrimaryCtorParamCount, primaryCtorParams?.Count); + + // validate the order of the parameters (endpoint, credential, client options) + var endpointParam = primaryCtorParams?[0]; + Assert.AreEqual(KnownParameters.Endpoint.Name, endpointParam?.Name); + Assert.AreEqual("tokenCredential", primaryCtorParams?[1].Name); + Assert.AreEqual("options", primaryCtorParams?[2].Name); + + if (endpointParam?.DefaultValue != null) + { + var inputEndpointParam = inputParameters.FirstOrDefault(p => p.IsEndpoint); + var parsedValue = inputEndpointParam?.DefaultValue?.Value; + Assert.AreEqual(Literal(parsedValue), endpointParam?.InitializationValue); + } + + // validate the body of the primary ctor + var primaryCtorBody = primaryPublicConstructor?.BodyStatements; + Assert.IsNotNull(primaryCtorBody); + } + + private void ValidateSecondaryConstructor( + ConstructorProvider? primaryConstructor, + ConstructorProvider? secondaryPublicConstructor, + List inputParameters) + { + Assert.IsNotNull(secondaryPublicConstructor); + var ctorParams = secondaryPublicConstructor?.Signature?.Parameters; + + // secondary ctor should consist of all required parameters + auth parameter + var requiredParams = inputParameters.Where(p => p.IsRequired).ToList(); + Assert.AreEqual(requiredParams.Count + 1, ctorParams?.Count); + var endpointParam = ctorParams?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); + + if (requiredParams.Count == 0) + { + // auth should be the only parameter if endpoint is optional + Assert.AreEqual("tokenCredential", ctorParams?[0].Name); + } + else + { + // otherwise, it should only consist of the auth parameter + Assert.AreEqual(KnownParameters.Endpoint.Name, ctorParams?[0].Name); + Assert.AreEqual("tokenCredential", ctorParams?[1].Name); + } + + Assert.AreEqual(MethodBodyStatement.Empty, secondaryPublicConstructor?.BodyStatements); + + // validate the initializer + var initializer = secondaryPublicConstructor?.Signature?.Initializer; + Assert.AreEqual(primaryConstructor?.Signature?.Parameters?.Count, initializer?.Arguments?.Count); + } + + [TestCaseSource(nameof(EndpointParamInitializationValueTestCases))] + public void EndpointInitializationValue(InputParameter endpointParameter, ValueExpression? expectedValue) + { + var client = InputFactory.Client(TestClientName, parameters: [endpointParameter]); + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + // find the endpoint parameter from the primary constructor + var primaryConstructor = clientProvider.Constructors.FirstOrDefault( + c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); + var endpoint = primaryConstructor?.Signature?.Parameters?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); + + Assert.IsNotNull(endpoint); + Assert.AreEqual(expectedValue?.GetType(), endpoint?.InitializationValue?.GetType()); + if (expectedValue != null) + { + Assert.IsTrue(endpoint?.InitializationValue is NewInstanceExpression); + } + } + + [TestCaseSource(nameof(SubClientFactoryMethodTestCases), Category = SubClientsCategory)] + public void TestSubClientAccessorFactoryMethods(InputClient client, bool hasSubClients) + { + var clientProvider = new ClientProvider(client); + Assert.IsNotNull(clientProvider); + + var methods = clientProvider.Methods; + List subClientAccessorFactoryMethods = []; + foreach (var method in methods) + { + var methodSignature = method.Signature; + if (methodSignature != null && + methodSignature.Name.StartsWith("Get") && + methodSignature.Modifiers.HasFlag(MethodSignatureModifiers.Public | MethodSignatureModifiers.Virtual)) + { + subClientAccessorFactoryMethods.Add(method); + } + } + + if (hasSubClients) + { + Assert.AreEqual(1, subClientAccessorFactoryMethods.Count); + var factoryMethod = subClientAccessorFactoryMethods[0]; + Assert.AreEqual(0, factoryMethod.Signature?.Parameters.Count); + + // method body should not be empty + Assert.AreNotEqual(MethodBodyStatement.Empty, factoryMethod.BodyStatements); + } + else + { + Assert.AreEqual(0, subClientAccessorFactoryMethods.Count); + } + } + + public static IEnumerable BuildFieldsTestCases + { + get + { + yield return new TestCaseData(new List + { + InputFactory.Parameter( + "optionalParam", + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client), + InputFactory.Parameter( + KnownParameters.Endpoint.Name, + InputPrimitiveType.String, + location:RequestLocation.None, + kind: InputOperationParameterKind.Client, + isEndpoint: true) + }, + new List + { + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), true), "_optionalParam") + } + ); + yield return new TestCaseData(new List + { + // have to explicitly set isRequired because we now call CreateParameter in buildFields + InputFactory.Parameter( + "optionalNullableParam", + InputPrimitiveType.String, + location: RequestLocation.None, + defaultValue: InputFactory.Constant.String("someValue"), + kind: InputOperationParameterKind.Client, + isRequired: false), + InputFactory.Parameter( + "requiredParam2", + InputPrimitiveType.String, + location: RequestLocation.None, + defaultValue: InputFactory.Constant.String("someValue"), + kind: InputOperationParameterKind.Client, + isRequired: true), + InputFactory.Parameter( + "requiredParam3", + InputPrimitiveType.Int64, + location: RequestLocation.None, + defaultValue: InputFactory.Constant.Int64(2), + kind: InputOperationParameterKind.Client, + isRequired: true), + InputFactory.Parameter( + KnownParameters.Endpoint.Name, + InputPrimitiveType.String, + location: RequestLocation.None, + defaultValue: null, + kind: InputOperationParameterKind.Client, + isEndpoint: true) + }, + new List + { + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), true), "_optionalNullableParam"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), false), "_requiredParam2"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(long), false), "_requiredParam3") + }); + } + } + + public static IEnumerable SubClientFieldsTestCases + { + get + { + yield return new TestCaseData(InputFactory.Client(TestClientName), new List + { + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), + new(FieldModifiers.Private, new ExpectedCSharpType("Animal", "Sample", true), "_cachedAnimal"), + }); + yield return new TestCaseData(_animalClient, new List + { + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), + new(FieldModifiers.Private, new ExpectedCSharpType("Dog", "Sample", true), "_cachedDog"), + }); + yield return new TestCaseData(_dogClient, new List + { + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), + new(FieldModifiers.Private, new ExpectedCSharpType("Husky", "Sample", true), "_cachedHusky"), + }); + yield return new TestCaseData(_huskyClient, new List + { + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential") + }); + } + } + + public static IEnumerable SubClientFactoryMethodTestCases + { + get + { + yield return new TestCaseData(InputFactory.Client(TestClientName), true); + yield return new TestCaseData(_animalClient, true); + yield return new TestCaseData(_dogClient, true); + yield return new TestCaseData(_huskyClient, false); + } + } + + public static IEnumerable BuildConstructorsTestCases + { + get + { + yield return new TestCaseData(new List + { + InputFactory.Parameter( + "optionalParam", + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client), + InputFactory.Parameter( + KnownParameters.Endpoint.Name, + InputPrimitiveType.String, + location: RequestLocation.None, + defaultValue: InputFactory.Constant.String("someValue"), + kind: InputOperationParameterKind.Client, + isEndpoint: true) + }); + // scenario where endpoint is required + yield return new TestCaseData(new List + { + InputFactory.Parameter( + KnownParameters.Endpoint.Name, + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client, + isRequired: true, + isEndpoint: true), + InputFactory.Parameter( + "optionalParam", + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client) + }); + } + } + + private static IEnumerable EndpointParamInitializationValueTestCases() + { + // string primitive type + yield return new TestCaseData( + InputFactory.Parameter( + "param", + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client, + isEndpoint: true, + defaultValue: InputFactory.Constant.String("mockValue")), + New.Instance(KnownParameters.Endpoint.Type, Literal("mockvalue"))); + } + + private record TestClientPipelineApi : ClientPipelineApi + { + private static ClientPipelineApi? _instance; + internal static ClientPipelineApi Instance => _instance ??= new TestClientPipelineApi(Empty); + + public TestClientPipelineApi(ValueExpression original) : base(typeof(string), original) + { + } + + public override CSharpType ClientPipelineType => typeof(string); + + public override CSharpType ClientPipelineOptionsType => typeof(string); + + public override CSharpType PipelinePolicyType => typeof(string); + + public override CSharpType? KeyCredentialType => null; + + public override CSharpType TokenCredentialType => typeof(TestTokenCredential); + + public override ValueExpression Create(ValueExpression options, ValueExpression perRetryPolicies) + => Original.Invoke("GetFakeCreate", [options, perRetryPolicies]); + + public override ValueExpression CreateMessage(HttpRequestOptionsApi requestOptions, ValueExpression responseClassifier) + => Original.Invoke("GetFakeCreateMessage", [requestOptions, responseClassifier]); + + public override ClientPipelineApi FromExpression(ValueExpression expression) + => new TestClientPipelineApi(expression); + + public override ValueExpression ConsumeKeyAuth(ValueExpression credential, ValueExpression headerName, ValueExpression? keyPrefix = null) + => throw new InvalidOperationException("ApiKey is not supported in this test"); + + public override ValueExpression ConsumeOAuth2Auth(ValueExpression credential, ValueExpression scopes) + => Original.Invoke("GetFakeTokenAuthorizationPolicy", [credential, scopes]); + + public override ClientPipelineApi ToExpression() => this; + + public override MethodBodyStatement[] ProcessMessage(HttpMessageApi message, HttpRequestOptionsApi options) + => [Original.Invoke("GetFakeProcessMessage", [message, options]).Terminate()]; + + public override MethodBodyStatement[] ProcessMessageAsync(HttpMessageApi message, HttpRequestOptionsApi options) + => [Original.Invoke("GetFakeProcessMessageAsync", [message, options]).Terminate()]; + } + + internal class TestTokenCredential { } + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs index 7da0bd144d..62f863574c 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs @@ -33,24 +33,6 @@ public class ClientProviderTests InputFactory.Property("p1", InputPrimitiveType.String, isRequired: true), ]); - [SetUp] - public void SetUp() - { - var categories = TestContext.CurrentContext.Test?.Properties["Category"]; - bool containsSubClients = categories?.Contains(SubClientsCategory) ?? false; - - if (containsSubClients) - { - MockHelpers.LoadMockPlugin( - apiKeyAuth: () => new InputApiKeyAuth("mock", null), - clients: () => [_animalClient, _dogClient, _huskyClient]); - } - else - { - MockHelpers.LoadMockPlugin(apiKeyAuth: () => new InputApiKeyAuth("mock", null)); - } - } - [Test] public void TestBuildProperties() { diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/TestHelpers/MockHelpers.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/TestHelpers/MockHelpers.cs index dc80039dca..d699ff9921 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/TestHelpers/MockHelpers.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/TestHelpers/MockHelpers.cs @@ -47,9 +47,9 @@ public static Mock LoadMockPlugin( Func>? createSerializationsCore = null, Func? createCSharpTypeCore = null, Func? matchConditionsType = null, - Func? keyCredentialType = null, Func? createParameterCore = null, Func? apiKeyAuth = null, + Func? oauth2Auth = null, Func>? apiVersions = null, Func>? inputEnums = null, Func>? inputModels = null, @@ -65,7 +65,7 @@ public static Mock LoadMockPlugin( IReadOnlyList inputNsEnums = inputEnums?.Invoke() ?? []; IReadOnlyList inputNsClients = clients?.Invoke() ?? []; IReadOnlyList inputNsModels = inputModels?.Invoke() ?? []; - InputAuth inputNsAuth = apiKeyAuth != null ? new InputAuth(apiKeyAuth(), null) : new InputAuth(); + InputAuth inputNsAuth = new InputAuth(apiKeyAuth?.Invoke(), oauth2Auth?.Invoke()); var mockTypeFactory = new Mock() { CallBase = true }; var mockInputNs = new Mock( string.Empty, @@ -82,11 +82,6 @@ public static Mock LoadMockPlugin( mockTypeFactory.Setup(p => p.MatchConditionsType).Returns(matchConditionsType); } - if (keyCredentialType is not null) - { - mockTypeFactory.Setup(p => p.KeyCredentialType).Returns(keyCredentialType); - } - if (createParameterCore is not null) { mockTypeFactory.Protected().Setup("CreateParameterCore", ItExpr.IsAny()).Returns(createParameterCore); From cf3a23eee5ae6c8399a0cd295a3c159b66594b0c Mon Sep 17 00:00:00 2001 From: Dapeng Zhang Date: Wed, 4 Dec 2024 15:45:22 +0800 Subject: [PATCH 09/22] refine those test cases --- .../ClientProviderAuthTests.cs | 339 +++++-- .../ClientProviderNoAuthTests.cs | 784 ++++++++-------- .../ClientProviderOAuth2AuthTests.cs | 872 +++++++++--------- .../ClientProviders/ClientProviderTests.cs | 17 + 4 files changed, 1120 insertions(+), 892 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderAuthTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderAuthTests.cs index 50b01e993e..27ca430fe9 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderAuthTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderAuthTests.cs @@ -29,50 +29,136 @@ public class ClientProviderAuthTests private static readonly InputClient _dogClient = new("dog", "DogClient description", [], [], _animalClient.Name); private static readonly InputClient _huskyClient = new("husky", "HuskyClient description", [], [], _dogClient.Name); + private bool _containsSubClients; + private bool _hasKeyAuth; + private bool _hasOAuth2; + private bool _hasAuth; + [SetUp] public void SetUp() { var categories = TestContext.CurrentContext.Test?.Properties["Category"]; - bool containsSubClients = categories?.Contains(SubClientsCategory) ?? false; - bool hasKeyAuth = categories?.Contains(KeyAuthCategory) ?? false; - bool hasOAuth2 = categories?.Contains(OAuth2Category) ?? false; + _containsSubClients = categories?.Contains(SubClientsCategory) ?? false; + _hasKeyAuth = categories?.Contains(KeyAuthCategory) ?? false; + _hasOAuth2 = categories?.Contains(OAuth2Category) ?? false; + _hasAuth = _hasKeyAuth || _hasOAuth2; - Func>? clients = containsSubClients ? + Func>? clients = _containsSubClients ? () => [_animalClient, _dogClient, _huskyClient] : null; - Func? apiKeyAuth = hasKeyAuth ? () => new InputApiKeyAuth("mock", null) : null; - Func? oauth2Auth = hasOAuth2 ? () => new InputOAuth2Auth(["mock"]) : null; + Func? apiKeyAuth = _hasKeyAuth ? () => new InputApiKeyAuth("mock", null) : null; + Func? oauth2Auth = _hasOAuth2 ? () => new InputOAuth2Auth(["mock"]) : null; MockHelpers.LoadMockPlugin( apiKeyAuth: apiKeyAuth, oauth2Auth: oauth2Auth, - clients: clients); + clients: clients, + clientPipelineApi: TestClientPipelineApi.Instance); } [TestCaseSource(nameof(BuildFieldsTestCases), Category = KeyAuthCategory)] - public void TestBuildFields(List inputParameters) + public void TestBuildFields_WithAuth(List inputParameters) + { + var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + if (_hasKeyAuth) + { + // key auth should have the following fields: AuthorizationHeader, _keyCredential + AssertHasFields(clientProvider, new List + { + new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string)), "AuthorizationHeader"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(ApiKeyCredential)), "_keyCredential") + }); + } + if (_hasOAuth2) + { + // oauth2 auth should have the following fields: AuthorizationScopes, _tokenCredential + AssertHasFields(clientProvider, new List + { + new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), + }); + } + } + + [TestCaseSource(nameof(BuildFieldsTestCases))] + public void TestBuildFields_NoAuth(List inputParameters) { var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); var clientProvider = new ClientProvider(client); Assert.IsNotNull(clientProvider); - // key auth should have the following fields: AuthorizationHeader, _keyCredential + // fields here should not have anything related with auth + bool authFieldFound = false; + foreach (var field in clientProvider.Fields) + { + if (field.Name.EndsWith("Credential") || field.Name.Contains("Authorization")) + { + authFieldFound = true; + } + } - AssertHasFields(clientProvider, expectedFields); + Assert.IsFalse(authFieldFound); } - // validates the fields are built correctly when a client has sub-clients + // validates the credential fields are built correctly when a client has sub-clients [TestCaseSource(nameof(SubClientFieldsTestCases), Category = SubClientsCategory)] - public void TestBuildFields_WithSubClients(InputClient client, List expectedFields) + public void TestBuildFields_WithSubClients_NoAuth(InputClient client) { var clientProvider = new ClientProvider(client); Assert.IsNotNull(clientProvider); - AssertHasFields(clientProvider, expectedFields); + // fields here should not have anything related with auth + bool authFieldFound = false; + foreach (var field in clientProvider.Fields) + { + if (field.Name.EndsWith("Credential") || field.Name.Contains("Authorization")) + { + authFieldFound = true; + } + } + + Assert.IsFalse(authFieldFound); + } + + // validates the credential fields are built correctly when a client has sub-clients + [TestCaseSource(nameof(SubClientFieldsTestCases), Category = $"{SubClientsCategory},{KeyAuthCategory}")] + [TestCaseSource(nameof(SubClientFieldsTestCases), Category = $"{SubClientsCategory},{OAuth2Category}")] + [TestCaseSource(nameof(SubClientFieldsTestCases), Category = $"{SubClientsCategory},{KeyAuthCategory},{OAuth2Category}")] + public void TestBuildFields_WithSubClients_WithAuth(InputClient client) + { + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + if (_hasKeyAuth) + { + // key auth should have the following fields: AuthorizationHeader, _keyCredential + AssertHasFields(clientProvider, new List + { + new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string)), "AuthorizationHeader"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(ApiKeyCredential)), "_keyCredential") + }); + } + if (_hasOAuth2) + { + // oauth2 auth should have the following fields: AuthorizationScopes, _tokenCredential + AssertHasFields(clientProvider, new List + { + new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), + }); + } } [TestCaseSource(nameof(BuildConstructorsTestCases))] + [TestCaseSource(nameof(BuildConstructorsTestCases), Category = KeyAuthCategory)] + [TestCaseSource(nameof(BuildConstructorsTestCases), Category = OAuth2Category)] + [TestCaseSource(nameof(BuildConstructorsTestCases), Category = $"{KeyAuthCategory},{OAuth2Category}")] public void TestBuildConstructors_PrimaryConstructor(List inputParameters) { var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); @@ -81,14 +167,25 @@ public void TestBuildConstructors_PrimaryConstructor(List inputP Assert.IsNotNull(clientProvider); var constructors = clientProvider.Constructors; - Assert.AreEqual(3, constructors.Count); - var primaryPublicConstructor = constructors.FirstOrDefault( - c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); - ValidatePrimaryConstructor(primaryPublicConstructor, inputParameters); + var primaryPublicConstructors = constructors.Where( + c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public).ToArray(); + + // for no auth or one auth case, this should be 1 + // for both auth case, this should be 2 + var expectedPrimaryCtorCount = _hasKeyAuth && _hasOAuth2 ? 2 : 1; + Assert.AreEqual(expectedPrimaryCtorCount, primaryPublicConstructors.Length); + + foreach (var primaryCtor in primaryPublicConstructors) + { + ValidatePrimaryConstructor(primaryCtor, inputParameters); + } } [TestCaseSource(nameof(BuildConstructorsTestCases))] + [TestCaseSource(nameof(BuildConstructorsTestCases), Category = KeyAuthCategory)] + [TestCaseSource(nameof(BuildConstructorsTestCases), Category = OAuth2Category)] + [TestCaseSource(nameof(BuildConstructorsTestCases), Category = $"{KeyAuthCategory},{OAuth2Category}")] public void TestBuildConstructors_SecondaryConstructor(List inputParameters) { var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); @@ -98,19 +195,46 @@ public void TestBuildConstructors_SecondaryConstructor(List inpu var constructors = clientProvider.Constructors; - Assert.AreEqual(3, constructors.Count); - var primaryPublicConstructor = constructors.FirstOrDefault( - c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); + var primaryPublicConstructors = constructors.Where( + c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public).ToArray(); + var secondaryPublicConstructors = constructors.Where( + c => c.Signature?.Initializer != null && c.Signature?.Modifiers == MethodSignatureModifiers.Public).ToArray(); - Assert.IsNotNull(primaryPublicConstructor); + // for no auth or one auth case, this should be 1 + // for both auth case, this should be 2 + var expectedSecondaryCtorCount = _hasKeyAuth && _hasOAuth2 ? 2 : 1; + Assert.AreEqual(expectedSecondaryCtorCount, secondaryPublicConstructors.Length); + foreach (var secondaryPublicConstructor in secondaryPublicConstructors) + { + ValidateSecondaryConstructor(primaryPublicConstructors, secondaryPublicConstructor, inputParameters); + } + } - var secondaryPublicConstructor = constructors.FirstOrDefault( - c => c.Signature?.Initializer != null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); - ValidateSecondaryConstructor(primaryPublicConstructor, secondaryPublicConstructor, inputParameters); + [TestCase] + public void TestBuildConstructors_ForSubClient_NoAuth() + { + var clientProvider = new ClientProvider(_animalClient); + + Assert.IsNotNull(clientProvider); + + var constructors = clientProvider.Constructors; + + Assert.AreEqual(2, constructors.Count); + var internalConstructor = constructors.FirstOrDefault( + c => c.Signature?.Modifiers == MethodSignatureModifiers.Internal); + Assert.IsNotNull(internalConstructor); + // in the no auth case, the ctor no longer has the credentail parameter therefore here we expect 2 parameters. + var ctorParams = internalConstructor?.Signature?.Parameters; + Assert.AreEqual(2, ctorParams?.Count); + + var mockingConstructor = constructors.FirstOrDefault( + c => c.Signature?.Modifiers == MethodSignatureModifiers.Protected); + Assert.IsNotNull(mockingConstructor); } - [Test] - public void TestBuildConstructors_ForSubClient() + [TestCase(Category = KeyAuthCategory)] + [TestCase(Category = OAuth2Category)] + public void TestBuildConstructors_ForSubClient_KeyAuthOrOAuth2Auth() { var clientProvider = new ClientProvider(_animalClient); @@ -122,6 +246,7 @@ public void TestBuildConstructors_ForSubClient() var internalConstructor = constructors.FirstOrDefault( c => c.Signature?.Modifiers == MethodSignatureModifiers.Internal); Assert.IsNotNull(internalConstructor); + // when there is only one approach of auth, we have 3 parameters in the ctor. var ctorParams = internalConstructor?.Signature?.Parameters; Assert.AreEqual(3, ctorParams?.Count); @@ -130,22 +255,43 @@ public void TestBuildConstructors_ForSubClient() Assert.IsNotNull(mockingConstructor); } - private static void ValidatePrimaryConstructor( - ConstructorProvider? primaryPublicConstructor, - List inputParameters) + [TestCase(Category = $"{KeyAuthCategory},{OAuth2Category}")] + public void TestBuildConstructors_ForSubClient_BothAuth() { - Assert.IsNotNull(primaryPublicConstructor); + var clientProvider = new ClientProvider(_animalClient); + + Assert.IsNotNull(clientProvider); + + var constructors = clientProvider.Constructors; + + Assert.AreEqual(2, constructors.Count); + var internalConstructor = constructors.FirstOrDefault( + c => c.Signature?.Modifiers == MethodSignatureModifiers.Internal); + Assert.IsNotNull(internalConstructor); + // when we have both auths, we have 4 parameters in the ctor, because now we should have two credential parameters + var ctorParams = internalConstructor?.Signature?.Parameters; + Assert.AreEqual(4, ctorParams?.Count); + var mockingConstructor = constructors.FirstOrDefault( + c => c.Signature?.Modifiers == MethodSignatureModifiers.Protected); + Assert.IsNotNull(mockingConstructor); + } + + private void ValidatePrimaryConstructor( + ConstructorProvider primaryPublicConstructor, + List inputParameters) + { var primaryCtorParams = primaryPublicConstructor?.Signature?.Parameters; - var expectedPrimaryCtorParamCount = 3; + // in no auth case, the ctor only have two parameters: endpoint and options + // in other cases, the ctor should have three parameters: endpoint, credential, options + // specifically, in both auth cases, we should have two ctors corresponding to each credential type as the second parameter + var expectedPrimaryCtorParamCount = !_hasKeyAuth && !_hasOAuth2 ? 2 : 3; Assert.AreEqual(expectedPrimaryCtorParamCount, primaryCtorParams?.Count); - // validate the order of the parameters (endpoint, credential, client options) + // the first should be endpoint var endpointParam = primaryCtorParams?[0]; Assert.AreEqual(KnownParameters.Endpoint.Name, endpointParam?.Name); - Assert.AreEqual("keyCredential", primaryCtorParams?[1].Name); - Assert.AreEqual("options", primaryCtorParams?[2].Name); if (endpointParam?.DefaultValue != null) { @@ -154,41 +300,76 @@ private static void ValidatePrimaryConstructor( Assert.AreEqual(Literal(parsedValue), endpointParam?.InitializationValue); } + // the last parameter should be the options + var optionsParam = primaryCtorParams?[^1]; + Assert.AreEqual("options", optionsParam?.Name); + + if (_hasAuth) + { + // when there is any auth, the second should be auth parameter + var authParam = primaryCtorParams?[1]; + Assert.IsNotNull(authParam); + if (authParam?.Name == "keyCredential") + { + Assert.AreEqual(new CSharpType(typeof(ApiKeyCredential)), authParam?.Type); + } + else if (authParam?.Name == "tokenCredential") + { + Assert.AreEqual(new CSharpType(typeof(TestTokenCredential)), authParam?.Type); + } + else + { + Assert.Fail("Unexpected auth parameter"); + } + } + // validate the body of the primary ctor var primaryCtorBody = primaryPublicConstructor?.BodyStatements; Assert.IsNotNull(primaryCtorBody); } private void ValidateSecondaryConstructor( - ConstructorProvider? primaryConstructor, - ConstructorProvider? secondaryPublicConstructor, + IReadOnlyList primaryConstructors, + ConstructorProvider secondaryPublicConstructor, List inputParameters) { - Assert.IsNotNull(secondaryPublicConstructor); - var ctorParams = secondaryPublicConstructor?.Signature?.Parameters; + var ctorParams = secondaryPublicConstructor.Signature?.Parameters; - // secondary ctor should consist of all required parameters + auth parameter + // secondary ctor should consist of all required parameters + auth parameter (when present) var requiredParams = inputParameters.Where(p => p.IsRequired).ToList(); - Assert.AreEqual(requiredParams.Count + 1, ctorParams?.Count); + var authParameterCount = _hasAuth ? 1 : 0; + Assert.AreEqual(requiredParams.Count + authParameterCount, ctorParams?.Count); var endpointParam = ctorParams?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); if (requiredParams.Count == 0) { - // auth should be the only parameter if endpoint is optional - Assert.AreEqual("keyCredential", ctorParams?[0].Name); + // auth should be the only parameter if endpoint is optional when there is auth + if (_hasAuth) + { + Assert.IsTrue(ctorParams?[0].Name.EndsWith("Credential")); + } + else + { + // when there is no auth, the ctor should not have parameters + Assert.AreEqual(0, ctorParams?.Count); + } } else { // otherwise, it should only consist of the auth parameter Assert.AreEqual(KnownParameters.Endpoint.Name, ctorParams?[0].Name); - Assert.AreEqual("keyCredential", ctorParams?[1].Name); + if (_hasAuth) + { + Assert.IsTrue(ctorParams?[1].Name.EndsWith("Credential")); + } } Assert.AreEqual(MethodBodyStatement.Empty, secondaryPublicConstructor?.BodyStatements); // validate the initializer var initializer = secondaryPublicConstructor?.Signature?.Initializer; - Assert.AreEqual(primaryConstructor?.Signature?.Parameters?.Count, initializer?.Arguments?.Count); + Assert.NotNull(initializer); + Assert.IsTrue(primaryConstructors.Any(pc => pc.Signature.Parameters.Count == initializer?.Arguments.Count)); } [TestCaseSource(nameof(EndpointParamInitializationValueTestCases))] @@ -302,26 +483,10 @@ public static IEnumerable SubClientFieldsTestCases { get { - yield return new TestCaseData(InputFactory.Client(TestClientName), new List - { - new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string)), "AuthorizationHeader"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(ApiKeyCredential)), "_keyCredential") - }); - yield return new TestCaseData(_animalClient, new List - { - new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string)), "AuthorizationHeader"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(ApiKeyCredential)), "_keyCredential") - }); - yield return new TestCaseData(_dogClient, new List - { - new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string)), "AuthorizationHeader"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(ApiKeyCredential)), "_keyCredential") - }); - yield return new TestCaseData(_huskyClient, new List - { - new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string)), "AuthorizationHeader"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(ApiKeyCredential)), "_keyCredential") - }); + yield return new TestCaseData(InputFactory.Client(TestClientName)); + yield return new TestCaseData(_animalClient); + yield return new TestCaseData(_dogClient); + yield return new TestCaseData(_huskyClient); } } @@ -390,5 +555,51 @@ private static IEnumerable EndpointParamInitializationValueTestCas New.Instance(KnownParameters.Endpoint.Type, Literal("mockvalue"))); } } + + // TODO -- this is temporary here before System.ClientModel officially supports OAuth2 auth + private record TestClientPipelineApi : ClientPipelineApi + { + private static ClientPipelineApi? _instance; + internal static ClientPipelineApi Instance => _instance ??= new TestClientPipelineApi(Empty); + + public TestClientPipelineApi(ValueExpression original) : base(typeof(string), original) + { + } + + public override CSharpType ClientPipelineType => typeof(string); + + public override CSharpType ClientPipelineOptionsType => typeof(string); + + public override CSharpType PipelinePolicyType => typeof(string); + + public override CSharpType KeyCredentialType => typeof(ApiKeyCredential); + + public override CSharpType TokenCredentialType => typeof(TestTokenCredential); + + public override ValueExpression Create(ValueExpression options, ValueExpression perRetryPolicies) + => Original.Invoke("GetFakeCreate", [options, perRetryPolicies]); + + public override ValueExpression CreateMessage(HttpRequestOptionsApi requestOptions, ValueExpression responseClassifier) + => Original.Invoke("GetFakeCreateMessage", [requestOptions, responseClassifier]); + + public override ClientPipelineApi FromExpression(ValueExpression expression) + => new TestClientPipelineApi(expression); + + public override ValueExpression ConsumeKeyAuth(ValueExpression credential, ValueExpression headerName, ValueExpression? keyPrefix = null) + => Original.Invoke("GetFakeApiKeyAuthorizationPolicy", keyPrefix != null ? [credential, headerName, keyPrefix] : [credential, headerName]); + + public override ValueExpression ConsumeOAuth2Auth(ValueExpression credential, ValueExpression scopes) + => Original.Invoke("GetFakeTokenAuthorizationPolicy", [credential, scopes]); + + public override ClientPipelineApi ToExpression() => this; + + public override MethodBodyStatement[] ProcessMessage(HttpMessageApi message, HttpRequestOptionsApi options) + => [Original.Invoke("GetFakeProcessMessage", [message, options]).Terminate()]; + + public override MethodBodyStatement[] ProcessMessageAsync(HttpMessageApi message, HttpRequestOptionsApi options) + => [Original.Invoke("GetFakeProcessMessageAsync", [message, options]).Terminate()]; + } + + internal class TestTokenCredential { } } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderNoAuthTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderNoAuthTests.cs index 79072a1dab..6ec27a48bc 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderNoAuthTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderNoAuthTests.cs @@ -20,396 +20,396 @@ namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders { - public class ClientProviderNoAuthTests - { - private const string SubClientsCategory = "WithSubClients"; - private const string TestClientName = "TestClient"; - private static readonly InputClient _animalClient = new("animal", "AnimalClient description", [], [], TestClientName); - private static readonly InputClient _dogClient = new("dog", "DogClient description", [], [], _animalClient.Name); - private static readonly InputClient _huskyClient = new("husky", "HuskyClient description", [], [], _dogClient.Name); - - [SetUp] - public void SetUp() - { - var categories = TestContext.CurrentContext.Test?.Properties["Category"]; - bool containsSubClients = categories?.Contains(SubClientsCategory) ?? false; - - if (containsSubClients) - { - MockHelpers.LoadMockPlugin( - clients: () => [_animalClient, _dogClient, _huskyClient]); - } - else - { - MockHelpers.LoadMockPlugin(); - } - } - - [Test] - public void TestBuildProperties() - { - var client = InputFactory.Client(TestClientName); - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - - // validate the properties - var properties = clientProvider.Properties; - Assert.IsTrue(properties.Count > 0); - // there should be a pipeline property - Assert.AreEqual(1, properties.Count); - - var pipelineProperty = properties[0]; - Assert.AreEqual(typeof(ClientPipeline), pipelineProperty.Type.FrameworkType); - Assert.AreEqual("Pipeline", pipelineProperty.Name); - Assert.AreEqual(MethodSignatureModifiers.Public, pipelineProperty.Modifiers); - } - - [TestCaseSource(nameof(BuildFieldsTestCases))] - public void TestBuildFields(List inputParameters, List expectedFields) - { - var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - - AssertClientFields(clientProvider, expectedFields); - } - - // validates the fields are built correctly when a client has sub-clients - [TestCaseSource(nameof(SubClientFieldsTestCases), Category = SubClientsCategory)] - public void TestBuildFields_WithSubClients(InputClient client, List expectedFields) - { - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - - AssertClientFields(clientProvider, expectedFields); - } - - [TestCaseSource(nameof(BuildConstructorsTestCases))] - public void TestBuildConstructors_PrimaryConstructor(List inputParameters, int expectedCount) - { - var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - - var constructors = clientProvider.Constructors; - Assert.AreEqual(expectedCount, constructors.Count); - - var primaryPublicConstructor = constructors.FirstOrDefault( - c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); - ValidatePrimaryConstructor(primaryPublicConstructor, inputParameters); - } - - [TestCaseSource(nameof(BuildConstructorsTestCases))] - public void TestBuildConstructors_SecondaryConstructor(List inputParameters, int expectedCount) - { - var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - - var constructors = clientProvider.Constructors; - - Assert.AreEqual(expectedCount, constructors.Count); - var primaryPublicConstructor = constructors.FirstOrDefault( - c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); - - Assert.IsNotNull(primaryPublicConstructor); - - var secondaryPublicConstructor = constructors.FirstOrDefault( - c => c.Signature?.Initializer != null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); - ValidateSecondaryConstructor(primaryPublicConstructor, secondaryPublicConstructor, inputParameters); - } - - [Test] - public void TestBuildConstructors_ForSubClient() - { - var clientProvider = new ClientProvider(_animalClient); - - Assert.IsNotNull(clientProvider); - - var constructors = clientProvider.Constructors; - - Assert.AreEqual(2, constructors.Count); - var internalConstructor = constructors.FirstOrDefault( - c => c.Signature?.Modifiers == MethodSignatureModifiers.Internal); - Assert.IsNotNull(internalConstructor); - var ctorParams = internalConstructor?.Signature?.Parameters; - Assert.AreEqual(2, ctorParams?.Count); // only 2 because there is no credential parameter - - var mockingConstructor = constructors.FirstOrDefault( - c => c.Signature?.Modifiers == MethodSignatureModifiers.Protected); - Assert.IsNotNull(mockingConstructor); - } - - private static void ValidatePrimaryConstructor( - ConstructorProvider? primaryPublicConstructor, - List inputParameters) - { - Assert.IsNotNull(primaryPublicConstructor); - - var primaryCtorParams = primaryPublicConstructor?.Signature?.Parameters; - - Assert.AreEqual(2, primaryCtorParams?.Count); // only 2 because there is no credential parameter - - // validate the order of the parameters (endpoint, credential, client options) - var endpointParam = primaryCtorParams?[0]; - Assert.AreEqual(KnownParameters.Endpoint.Name, endpointParam?.Name); - Assert.AreEqual("options", primaryCtorParams?[1].Name); - - if (endpointParam?.DefaultValue != null) - { - var inputEndpointParam = inputParameters.FirstOrDefault(p => p.IsEndpoint); - var parsedValue = inputEndpointParam?.DefaultValue?.Value; - Assert.AreEqual(Literal(parsedValue), endpointParam?.InitializationValue); - } - - // validate the body of the primary ctor - var primaryCtorBody = primaryPublicConstructor?.BodyStatements; - Assert.IsNotNull(primaryCtorBody); - } - - private void ValidateSecondaryConstructor( - ConstructorProvider? primaryConstructor, - ConstructorProvider? secondaryPublicConstructor, - List inputParameters) - { - Assert.IsNotNull(secondaryPublicConstructor); - var ctorParams = secondaryPublicConstructor?.Signature?.Parameters; - - // secondary ctor should consist of all required parameters + auth parameter, but here we do not have auth, therefore they should be the same - var requiredParams = inputParameters.Where(p => p.IsRequired).ToList(); - Assert.AreEqual(requiredParams.Count, ctorParams?.Count); - var endpointParam = ctorParams?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); - - if (requiredParams.Count == 0) - { - // there should be no parameter if endpoint is optional and we do not have an auth - Assert.AreEqual(0, ctorParams?.Count); - } - else - { - // otherwise, it should only consist of the endpoint parameter - Assert.AreEqual(KnownParameters.Endpoint.Name, ctorParams?[0].Name); - } - - Assert.AreEqual(MethodBodyStatement.Empty, secondaryPublicConstructor?.BodyStatements); - - // validate the initializer - var initializer = secondaryPublicConstructor?.Signature?.Initializer; - Assert.AreEqual(primaryConstructor?.Signature?.Parameters?.Count, initializer?.Arguments?.Count); - } - - [TestCaseSource(nameof(EndpointParamInitializationValueTestCases))] - public void EndpointInitializationValue(InputParameter endpointParameter, ValueExpression? expectedValue) - { - var client = InputFactory.Client(TestClientName, parameters: [endpointParameter]); - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - // find the endpoint parameter from the primary constructor - var primaryConstructor = clientProvider.Constructors.FirstOrDefault( - c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); - var endpoint = primaryConstructor?.Signature?.Parameters?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); - - Assert.IsNotNull(endpoint); - Assert.AreEqual(expectedValue?.GetType(), endpoint?.InitializationValue?.GetType()); - if (expectedValue != null) - { - Assert.IsTrue(endpoint?.InitializationValue is NewInstanceExpression); - } - } - - [TestCaseSource(nameof(SubClientFactoryMethodTestCases), Category = SubClientsCategory)] - public void TestSubClientAccessorFactoryMethods(InputClient client, bool hasSubClients) - { - var clientProvider = new ClientProvider(client); - Assert.IsNotNull(clientProvider); - - var methods = clientProvider.Methods; - List subClientAccessorFactoryMethods = []; - foreach (var method in methods) - { - var methodSignature = method.Signature; - if (methodSignature != null && - methodSignature.Name.StartsWith("Get") && - methodSignature.Modifiers.HasFlag(MethodSignatureModifiers.Public | MethodSignatureModifiers.Virtual)) - { - subClientAccessorFactoryMethods.Add(method); - } - } - - if (hasSubClients) - { - Assert.AreEqual(1, subClientAccessorFactoryMethods.Count); - var factoryMethod = subClientAccessorFactoryMethods[0]; - Assert.AreEqual(0, factoryMethod.Signature?.Parameters.Count); - - // method body should not be empty - Assert.AreNotEqual(MethodBodyStatement.Empty, factoryMethod.BodyStatements); - } - else - { - Assert.AreEqual(0, subClientAccessorFactoryMethods.Count); - } - } - - public static IEnumerable BuildFieldsTestCases - { - get - { - yield return new TestCaseData(new List - { - InputFactory.Parameter( - "optionalParam", - InputPrimitiveType.String, - location: RequestLocation.None, - kind: InputOperationParameterKind.Client), - InputFactory.Parameter( - KnownParameters.Endpoint.Name, - InputPrimitiveType.String, - location:RequestLocation.None, - kind: InputOperationParameterKind.Client, - isEndpoint: true) - }, - new List - { - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), true), "_optionalParam") - } - ); - yield return new TestCaseData(new List - { - // have to explicitly set isRequired because we now call CreateParameter in buildFields - InputFactory.Parameter( - "optionalNullableParam", - InputPrimitiveType.String, - location: RequestLocation.None, - defaultValue: InputFactory.Constant.String("someValue"), - kind: InputOperationParameterKind.Client, - isRequired: false), - InputFactory.Parameter( - "requiredParam2", - InputPrimitiveType.String, - location: RequestLocation.None, - defaultValue: InputFactory.Constant.String("someValue"), - kind: InputOperationParameterKind.Client, - isRequired: true), - InputFactory.Parameter( - "requiredParam3", - InputPrimitiveType.Int64, - location: RequestLocation.None, - defaultValue: InputFactory.Constant.Int64(2), - kind: InputOperationParameterKind.Client, - isRequired: true), - InputFactory.Parameter( - KnownParameters.Endpoint.Name, - InputPrimitiveType.String, - location: RequestLocation.None, - defaultValue: null, - kind: InputOperationParameterKind.Client, - isEndpoint: true) - }, - new List - { - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), true), "_optionalNullableParam"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), false), "_requiredParam2"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(long), false), "_requiredParam3") - }); - } - } - - public static IEnumerable SubClientFieldsTestCases - { - get - { - yield return new TestCaseData(InputFactory.Client(TestClientName), new List - { - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), - new(FieldModifiers.Private, new ExpectedCSharpType("Animal", "Sample", true), "_cachedAnimal"), - }); - yield return new TestCaseData(_animalClient, new List - { - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), - new(FieldModifiers.Private, new ExpectedCSharpType("Dog", "Sample", true), "_cachedDog"), - }); - yield return new TestCaseData(_dogClient, new List - { - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), - new(FieldModifiers.Private, new ExpectedCSharpType("Husky", "Sample", true), "_cachedHusky"), - }); - yield return new TestCaseData(_huskyClient, new List - { - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), - }); - } - } - - public static IEnumerable SubClientFactoryMethodTestCases - { - get - { - yield return new TestCaseData(InputFactory.Client(TestClientName), true); - yield return new TestCaseData(_animalClient, true); - yield return new TestCaseData(_dogClient, true); - yield return new TestCaseData(_huskyClient, false); - } - } - - public static IEnumerable BuildConstructorsTestCases - { - get - { - yield return new TestCaseData(new List - { - InputFactory.Parameter( - "optionalParam", - InputPrimitiveType.String, - location: RequestLocation.None, - kind: InputOperationParameterKind.Client), - InputFactory.Parameter( - KnownParameters.Endpoint.Name, - InputPrimitiveType.String, - location: RequestLocation.None, - defaultValue: InputFactory.Constant.String("someValue"), - kind: InputOperationParameterKind.Client, - isEndpoint: true) - }, 2); // in this case, the secondary ctor has the same ctor list as the protected ctor - // scenario where endpoint is required - yield return new TestCaseData(new List - { - InputFactory.Parameter( - KnownParameters.Endpoint.Name, - InputPrimitiveType.String, - location: RequestLocation.None, - kind: InputOperationParameterKind.Client, - isRequired: true, - isEndpoint: true), - InputFactory.Parameter( - "optionalParam", - InputPrimitiveType.String, - location: RequestLocation.None, - kind: InputOperationParameterKind.Client) - }, 3); - } - } - - private static IEnumerable EndpointParamInitializationValueTestCases() - { - // string primitive type - yield return new TestCaseData( - InputFactory.Parameter( - "param", - InputPrimitiveType.String, - location: RequestLocation.None, - kind: InputOperationParameterKind.Client, - isEndpoint: true, - defaultValue: InputFactory.Constant.String("mockValue")), - New.Instance(KnownParameters.Endpoint.Type, Literal("mockvalue"))); - } - } + //public class ClientProviderNoAuthTests + //{ + // private const string SubClientsCategory = "WithSubClients"; + // private const string TestClientName = "TestClient"; + // private static readonly InputClient _animalClient = new("animal", "AnimalClient description", [], [], TestClientName); + // private static readonly InputClient _dogClient = new("dog", "DogClient description", [], [], _animalClient.Name); + // private static readonly InputClient _huskyClient = new("husky", "HuskyClient description", [], [], _dogClient.Name); + + // [SetUp] + // public void SetUp() + // { + // var categories = TestContext.CurrentContext.Test?.Properties["Category"]; + // bool containsSubClients = categories?.Contains(SubClientsCategory) ?? false; + + // if (containsSubClients) + // { + // MockHelpers.LoadMockPlugin( + // clients: () => [_animalClient, _dogClient, _huskyClient]); + // } + // else + // { + // MockHelpers.LoadMockPlugin(); + // } + // } + + // [Test] + // public void TestBuildProperties() + // { + // var client = InputFactory.Client(TestClientName); + // var clientProvider = new ClientProvider(client); + + // Assert.IsNotNull(clientProvider); + + // // validate the properties + // var properties = clientProvider.Properties; + // Assert.IsTrue(properties.Count > 0); + // // there should be a pipeline property + // Assert.AreEqual(1, properties.Count); + + // var pipelineProperty = properties[0]; + // Assert.AreEqual(typeof(ClientPipeline), pipelineProperty.Type.FrameworkType); + // Assert.AreEqual("Pipeline", pipelineProperty.Name); + // Assert.AreEqual(MethodSignatureModifiers.Public, pipelineProperty.Modifiers); + // } + + // [TestCaseSource(nameof(BuildFieldsTestCases))] + // public void TestBuildFields(List inputParameters, List expectedFields) + // { + // var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); + // var clientProvider = new ClientProvider(client); + + // Assert.IsNotNull(clientProvider); + + // AssertClientFields(clientProvider, expectedFields); + // } + + // // validates the fields are built correctly when a client has sub-clients + // [TestCaseSource(nameof(SubClientFieldsTestCases), Category = SubClientsCategory)] + // public void TestBuildFields_WithSubClients(InputClient client, List expectedFields) + // { + // var clientProvider = new ClientProvider(client); + + // Assert.IsNotNull(clientProvider); + + // AssertClientFields(clientProvider, expectedFields); + // } + + // [TestCaseSource(nameof(BuildConstructorsTestCases))] + // public void TestBuildConstructors_PrimaryConstructor(List inputParameters, int expectedCount) + // { + // var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); + // var clientProvider = new ClientProvider(client); + + // Assert.IsNotNull(clientProvider); + + // var constructors = clientProvider.Constructors; + // Assert.AreEqual(expectedCount, constructors.Count); + + // var primaryPublicConstructor = constructors.FirstOrDefault( + // c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); + // ValidatePrimaryConstructor(primaryPublicConstructor, inputParameters); + // } + + // [TestCaseSource(nameof(BuildConstructorsTestCases))] + // public void TestBuildConstructors_SecondaryConstructor(List inputParameters, int expectedCount) + // { + // var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); + // var clientProvider = new ClientProvider(client); + + // Assert.IsNotNull(clientProvider); + + // var constructors = clientProvider.Constructors; + + // Assert.AreEqual(expectedCount, constructors.Count); + // var primaryPublicConstructor = constructors.FirstOrDefault( + // c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); + + // Assert.IsNotNull(primaryPublicConstructor); + + // var secondaryPublicConstructor = constructors.FirstOrDefault( + // c => c.Signature?.Initializer != null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); + // ValidateSecondaryConstructor(primaryPublicConstructor, secondaryPublicConstructor, inputParameters); + // } + + // [Test] + // public void TestBuildConstructors_ForSubClient() + // { + // var clientProvider = new ClientProvider(_animalClient); + + // Assert.IsNotNull(clientProvider); + + // var constructors = clientProvider.Constructors; + + // Assert.AreEqual(2, constructors.Count); + // var internalConstructor = constructors.FirstOrDefault( + // c => c.Signature?.Modifiers == MethodSignatureModifiers.Internal); + // Assert.IsNotNull(internalConstructor); + // var ctorParams = internalConstructor?.Signature?.Parameters; + // Assert.AreEqual(2, ctorParams?.Count); // only 2 because there is no credential parameter + + // var mockingConstructor = constructors.FirstOrDefault( + // c => c.Signature?.Modifiers == MethodSignatureModifiers.Protected); + // Assert.IsNotNull(mockingConstructor); + // } + + // private static void ValidatePrimaryConstructor( + // ConstructorProvider? primaryPublicConstructor, + // List inputParameters) + // { + // Assert.IsNotNull(primaryPublicConstructor); + + // var primaryCtorParams = primaryPublicConstructor?.Signature?.Parameters; + + // Assert.AreEqual(2, primaryCtorParams?.Count); // only 2 because there is no credential parameter + + // // validate the order of the parameters (endpoint, credential, client options) + // var endpointParam = primaryCtorParams?[0]; + // Assert.AreEqual(KnownParameters.Endpoint.Name, endpointParam?.Name); + // Assert.AreEqual("options", primaryCtorParams?[1].Name); + + // if (endpointParam?.DefaultValue != null) + // { + // var inputEndpointParam = inputParameters.FirstOrDefault(p => p.IsEndpoint); + // var parsedValue = inputEndpointParam?.DefaultValue?.Value; + // Assert.AreEqual(Literal(parsedValue), endpointParam?.InitializationValue); + // } + + // // validate the body of the primary ctor + // var primaryCtorBody = primaryPublicConstructor?.BodyStatements; + // Assert.IsNotNull(primaryCtorBody); + // } + + // private void ValidateSecondaryConstructor( + // ConstructorProvider? primaryConstructor, + // ConstructorProvider? secondaryPublicConstructor, + // List inputParameters) + // { + // Assert.IsNotNull(secondaryPublicConstructor); + // var ctorParams = secondaryPublicConstructor?.Signature?.Parameters; + + // // secondary ctor should consist of all required parameters + auth parameter, but here we do not have auth, therefore they should be the same + // var requiredParams = inputParameters.Where(p => p.IsRequired).ToList(); + // Assert.AreEqual(requiredParams.Count, ctorParams?.Count); + // var endpointParam = ctorParams?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); + + // if (requiredParams.Count == 0) + // { + // // there should be no parameter if endpoint is optional and we do not have an auth + // Assert.AreEqual(0, ctorParams?.Count); + // } + // else + // { + // // otherwise, it should only consist of the endpoint parameter + // Assert.AreEqual(KnownParameters.Endpoint.Name, ctorParams?[0].Name); + // } + + // Assert.AreEqual(MethodBodyStatement.Empty, secondaryPublicConstructor?.BodyStatements); + + // // validate the initializer + // var initializer = secondaryPublicConstructor?.Signature?.Initializer; + // Assert.AreEqual(primaryConstructor?.Signature?.Parameters?.Count, initializer?.Arguments?.Count); + // } + + // [TestCaseSource(nameof(EndpointParamInitializationValueTestCases))] + // public void EndpointInitializationValue(InputParameter endpointParameter, ValueExpression? expectedValue) + // { + // var client = InputFactory.Client(TestClientName, parameters: [endpointParameter]); + // var clientProvider = new ClientProvider(client); + + // Assert.IsNotNull(clientProvider); + // // find the endpoint parameter from the primary constructor + // var primaryConstructor = clientProvider.Constructors.FirstOrDefault( + // c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); + // var endpoint = primaryConstructor?.Signature?.Parameters?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); + + // Assert.IsNotNull(endpoint); + // Assert.AreEqual(expectedValue?.GetType(), endpoint?.InitializationValue?.GetType()); + // if (expectedValue != null) + // { + // Assert.IsTrue(endpoint?.InitializationValue is NewInstanceExpression); + // } + // } + + // [TestCaseSource(nameof(SubClientFactoryMethodTestCases), Category = SubClientsCategory)] + // public void TestSubClientAccessorFactoryMethods(InputClient client, bool hasSubClients) + // { + // var clientProvider = new ClientProvider(client); + // Assert.IsNotNull(clientProvider); + + // var methods = clientProvider.Methods; + // List subClientAccessorFactoryMethods = []; + // foreach (var method in methods) + // { + // var methodSignature = method.Signature; + // if (methodSignature != null && + // methodSignature.Name.StartsWith("Get") && + // methodSignature.Modifiers.HasFlag(MethodSignatureModifiers.Public | MethodSignatureModifiers.Virtual)) + // { + // subClientAccessorFactoryMethods.Add(method); + // } + // } + + // if (hasSubClients) + // { + // Assert.AreEqual(1, subClientAccessorFactoryMethods.Count); + // var factoryMethod = subClientAccessorFactoryMethods[0]; + // Assert.AreEqual(0, factoryMethod.Signature?.Parameters.Count); + + // // method body should not be empty + // Assert.AreNotEqual(MethodBodyStatement.Empty, factoryMethod.BodyStatements); + // } + // else + // { + // Assert.AreEqual(0, subClientAccessorFactoryMethods.Count); + // } + // } + + // public static IEnumerable BuildFieldsTestCases + // { + // get + // { + // yield return new TestCaseData(new List + // { + // InputFactory.Parameter( + // "optionalParam", + // InputPrimitiveType.String, + // location: RequestLocation.None, + // kind: InputOperationParameterKind.Client), + // InputFactory.Parameter( + // KnownParameters.Endpoint.Name, + // InputPrimitiveType.String, + // location:RequestLocation.None, + // kind: InputOperationParameterKind.Client, + // isEndpoint: true) + // }, + // new List + // { + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), true), "_optionalParam") + // } + // ); + // yield return new TestCaseData(new List + // { + // // have to explicitly set isRequired because we now call CreateParameter in buildFields + // InputFactory.Parameter( + // "optionalNullableParam", + // InputPrimitiveType.String, + // location: RequestLocation.None, + // defaultValue: InputFactory.Constant.String("someValue"), + // kind: InputOperationParameterKind.Client, + // isRequired: false), + // InputFactory.Parameter( + // "requiredParam2", + // InputPrimitiveType.String, + // location: RequestLocation.None, + // defaultValue: InputFactory.Constant.String("someValue"), + // kind: InputOperationParameterKind.Client, + // isRequired: true), + // InputFactory.Parameter( + // "requiredParam3", + // InputPrimitiveType.Int64, + // location: RequestLocation.None, + // defaultValue: InputFactory.Constant.Int64(2), + // kind: InputOperationParameterKind.Client, + // isRequired: true), + // InputFactory.Parameter( + // KnownParameters.Endpoint.Name, + // InputPrimitiveType.String, + // location: RequestLocation.None, + // defaultValue: null, + // kind: InputOperationParameterKind.Client, + // isEndpoint: true) + // }, + // new List + // { + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), true), "_optionalNullableParam"), + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), false), "_requiredParam2"), + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(long), false), "_requiredParam3") + // }); + // } + // } + + // public static IEnumerable SubClientFieldsTestCases + // { + // get + // { + // yield return new TestCaseData(InputFactory.Client(TestClientName), new List + // { + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + // new(FieldModifiers.Private, new ExpectedCSharpType("Animal", "Sample", true), "_cachedAnimal"), + // }); + // yield return new TestCaseData(_animalClient, new List + // { + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + // new(FieldModifiers.Private, new ExpectedCSharpType("Dog", "Sample", true), "_cachedDog"), + // }); + // yield return new TestCaseData(_dogClient, new List + // { + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + // new(FieldModifiers.Private, new ExpectedCSharpType("Husky", "Sample", true), "_cachedHusky"), + // }); + // yield return new TestCaseData(_huskyClient, new List + // { + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + // }); + // } + // } + + // public static IEnumerable SubClientFactoryMethodTestCases + // { + // get + // { + // yield return new TestCaseData(InputFactory.Client(TestClientName), true); + // yield return new TestCaseData(_animalClient, true); + // yield return new TestCaseData(_dogClient, true); + // yield return new TestCaseData(_huskyClient, false); + // } + // } + + // public static IEnumerable BuildConstructorsTestCases + // { + // get + // { + // yield return new TestCaseData(new List + // { + // InputFactory.Parameter( + // "optionalParam", + // InputPrimitiveType.String, + // location: RequestLocation.None, + // kind: InputOperationParameterKind.Client), + // InputFactory.Parameter( + // KnownParameters.Endpoint.Name, + // InputPrimitiveType.String, + // location: RequestLocation.None, + // defaultValue: InputFactory.Constant.String("someValue"), + // kind: InputOperationParameterKind.Client, + // isEndpoint: true) + // }, 2); // in this case, the secondary ctor has the same ctor list as the protected ctor + // // scenario where endpoint is required + // yield return new TestCaseData(new List + // { + // InputFactory.Parameter( + // KnownParameters.Endpoint.Name, + // InputPrimitiveType.String, + // location: RequestLocation.None, + // kind: InputOperationParameterKind.Client, + // isRequired: true, + // isEndpoint: true), + // InputFactory.Parameter( + // "optionalParam", + // InputPrimitiveType.String, + // location: RequestLocation.None, + // kind: InputOperationParameterKind.Client) + // }, 3); + // } + // } + + // private static IEnumerable EndpointParamInitializationValueTestCases() + // { + // // string primitive type + // yield return new TestCaseData( + // InputFactory.Parameter( + // "param", + // InputPrimitiveType.String, + // location: RequestLocation.None, + // kind: InputOperationParameterKind.Client, + // isEndpoint: true, + // defaultValue: InputFactory.Constant.String("mockValue")), + // New.Instance(KnownParameters.Endpoint.Type, Literal("mockvalue"))); + // } + //} } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderOAuth2AuthTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderOAuth2AuthTests.cs index efbb7d254d..b389232ee9 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderOAuth2AuthTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderOAuth2AuthTests.cs @@ -20,440 +20,440 @@ namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders { - public class ClientProviderOAuth2AuthTests - { - private const string SubClientsCategory = "WithSubClients"; - private const string TestClientName = "TestClient"; - private static readonly InputClient _animalClient = new("animal", "AnimalClient description", [], [], TestClientName); - private static readonly InputClient _dogClient = new("dog", "DogClient description", [], [], _animalClient.Name); - private static readonly InputClient _huskyClient = new("husky", "HuskyClient description", [], [], _dogClient.Name); - - [SetUp] - public void SetUp() - { - var categories = TestContext.CurrentContext.Test?.Properties["Category"]; - bool containsSubClients = categories?.Contains(SubClientsCategory) ?? false; - - if (containsSubClients) - { - MockHelpers.LoadMockPlugin( - oauth2Auth: () => new InputOAuth2Auth(["mock"]), - clients: () => [_animalClient, _dogClient, _huskyClient], - clientPipelineApi: TestClientPipelineApi.Instance); - } - else - { - MockHelpers.LoadMockPlugin( - oauth2Auth: () => new InputOAuth2Auth(["mock"]), - clientPipelineApi: TestClientPipelineApi.Instance); - } - } - - [TestCaseSource(nameof(BuildFieldsTestCases))] - public void TestBuildFields(List inputParameters, List expectedFields) - { - var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - - AssertClientFields(clientProvider, expectedFields); - } - - // validates the fields are built correctly when a client has sub-clients - [TestCaseSource(nameof(SubClientFieldsTestCases), Category = SubClientsCategory)] - public void TestBuildFields_WithSubClients(InputClient client, List expectedFields) - { - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - - AssertClientFields(clientProvider, expectedFields); - } - - [TestCaseSource(nameof(BuildConstructorsTestCases))] - public void TestBuildConstructors_PrimaryConstructor(List inputParameters) - { - var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - - var constructors = clientProvider.Constructors; - Assert.AreEqual(3, constructors.Count); - - var primaryPublicConstructor = constructors.FirstOrDefault( - c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); - ValidatePrimaryConstructor(primaryPublicConstructor, inputParameters); - } - - [TestCaseSource(nameof(BuildConstructorsTestCases))] - public void TestBuildConstructors_SecondaryConstructor(List inputParameters) - { - var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - - var constructors = clientProvider.Constructors; - - Assert.AreEqual(3, constructors.Count); - var primaryPublicConstructor = constructors.FirstOrDefault( - c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); - - Assert.IsNotNull(primaryPublicConstructor); - - var secondaryPublicConstructor = constructors.FirstOrDefault( - c => c.Signature?.Initializer != null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); - ValidateSecondaryConstructor(primaryPublicConstructor, secondaryPublicConstructor, inputParameters); - } - - [Test] - public void TestBuildConstructors_ForSubClient() - { - var clientProvider = new ClientProvider(_animalClient); - - Assert.IsNotNull(clientProvider); - - var constructors = clientProvider.Constructors; - - Assert.AreEqual(2, constructors.Count); - var internalConstructor = constructors.FirstOrDefault( - c => c.Signature?.Modifiers == MethodSignatureModifiers.Internal); - Assert.IsNotNull(internalConstructor); - var ctorParams = internalConstructor?.Signature?.Parameters; - Assert.AreEqual(3, ctorParams?.Count); - - var mockingConstructor = constructors.FirstOrDefault( - c => c.Signature?.Modifiers == MethodSignatureModifiers.Protected); - Assert.IsNotNull(mockingConstructor); - } - - private static void ValidatePrimaryConstructor( - ConstructorProvider? primaryPublicConstructor, - List inputParameters) - { - Assert.IsNotNull(primaryPublicConstructor); - - var primaryCtorParams = primaryPublicConstructor?.Signature?.Parameters; - var expectedPrimaryCtorParamCount = 3; - - Assert.AreEqual(expectedPrimaryCtorParamCount, primaryCtorParams?.Count); - - // validate the order of the parameters (endpoint, credential, client options) - var endpointParam = primaryCtorParams?[0]; - Assert.AreEqual(KnownParameters.Endpoint.Name, endpointParam?.Name); - Assert.AreEqual("tokenCredential", primaryCtorParams?[1].Name); - Assert.AreEqual("options", primaryCtorParams?[2].Name); - - if (endpointParam?.DefaultValue != null) - { - var inputEndpointParam = inputParameters.FirstOrDefault(p => p.IsEndpoint); - var parsedValue = inputEndpointParam?.DefaultValue?.Value; - Assert.AreEqual(Literal(parsedValue), endpointParam?.InitializationValue); - } - - // validate the body of the primary ctor - var primaryCtorBody = primaryPublicConstructor?.BodyStatements; - Assert.IsNotNull(primaryCtorBody); - } - - private void ValidateSecondaryConstructor( - ConstructorProvider? primaryConstructor, - ConstructorProvider? secondaryPublicConstructor, - List inputParameters) - { - Assert.IsNotNull(secondaryPublicConstructor); - var ctorParams = secondaryPublicConstructor?.Signature?.Parameters; - - // secondary ctor should consist of all required parameters + auth parameter - var requiredParams = inputParameters.Where(p => p.IsRequired).ToList(); - Assert.AreEqual(requiredParams.Count + 1, ctorParams?.Count); - var endpointParam = ctorParams?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); - - if (requiredParams.Count == 0) - { - // auth should be the only parameter if endpoint is optional - Assert.AreEqual("tokenCredential", ctorParams?[0].Name); - } - else - { - // otherwise, it should only consist of the auth parameter - Assert.AreEqual(KnownParameters.Endpoint.Name, ctorParams?[0].Name); - Assert.AreEqual("tokenCredential", ctorParams?[1].Name); - } - - Assert.AreEqual(MethodBodyStatement.Empty, secondaryPublicConstructor?.BodyStatements); - - // validate the initializer - var initializer = secondaryPublicConstructor?.Signature?.Initializer; - Assert.AreEqual(primaryConstructor?.Signature?.Parameters?.Count, initializer?.Arguments?.Count); - } - - [TestCaseSource(nameof(EndpointParamInitializationValueTestCases))] - public void EndpointInitializationValue(InputParameter endpointParameter, ValueExpression? expectedValue) - { - var client = InputFactory.Client(TestClientName, parameters: [endpointParameter]); - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - // find the endpoint parameter from the primary constructor - var primaryConstructor = clientProvider.Constructors.FirstOrDefault( - c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); - var endpoint = primaryConstructor?.Signature?.Parameters?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); - - Assert.IsNotNull(endpoint); - Assert.AreEqual(expectedValue?.GetType(), endpoint?.InitializationValue?.GetType()); - if (expectedValue != null) - { - Assert.IsTrue(endpoint?.InitializationValue is NewInstanceExpression); - } - } - - [TestCaseSource(nameof(SubClientFactoryMethodTestCases), Category = SubClientsCategory)] - public void TestSubClientAccessorFactoryMethods(InputClient client, bool hasSubClients) - { - var clientProvider = new ClientProvider(client); - Assert.IsNotNull(clientProvider); - - var methods = clientProvider.Methods; - List subClientAccessorFactoryMethods = []; - foreach (var method in methods) - { - var methodSignature = method.Signature; - if (methodSignature != null && - methodSignature.Name.StartsWith("Get") && - methodSignature.Modifiers.HasFlag(MethodSignatureModifiers.Public | MethodSignatureModifiers.Virtual)) - { - subClientAccessorFactoryMethods.Add(method); - } - } - - if (hasSubClients) - { - Assert.AreEqual(1, subClientAccessorFactoryMethods.Count); - var factoryMethod = subClientAccessorFactoryMethods[0]; - Assert.AreEqual(0, factoryMethod.Signature?.Parameters.Count); - - // method body should not be empty - Assert.AreNotEqual(MethodBodyStatement.Empty, factoryMethod.BodyStatements); - } - else - { - Assert.AreEqual(0, subClientAccessorFactoryMethods.Count); - } - } - - public static IEnumerable BuildFieldsTestCases - { - get - { - yield return new TestCaseData(new List - { - InputFactory.Parameter( - "optionalParam", - InputPrimitiveType.String, - location: RequestLocation.None, - kind: InputOperationParameterKind.Client), - InputFactory.Parameter( - KnownParameters.Endpoint.Name, - InputPrimitiveType.String, - location:RequestLocation.None, - kind: InputOperationParameterKind.Client, - isEndpoint: true) - }, - new List - { - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), - new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), true), "_optionalParam") - } - ); - yield return new TestCaseData(new List - { - // have to explicitly set isRequired because we now call CreateParameter in buildFields - InputFactory.Parameter( - "optionalNullableParam", - InputPrimitiveType.String, - location: RequestLocation.None, - defaultValue: InputFactory.Constant.String("someValue"), - kind: InputOperationParameterKind.Client, - isRequired: false), - InputFactory.Parameter( - "requiredParam2", - InputPrimitiveType.String, - location: RequestLocation.None, - defaultValue: InputFactory.Constant.String("someValue"), - kind: InputOperationParameterKind.Client, - isRequired: true), - InputFactory.Parameter( - "requiredParam3", - InputPrimitiveType.Int64, - location: RequestLocation.None, - defaultValue: InputFactory.Constant.Int64(2), - kind: InputOperationParameterKind.Client, - isRequired: true), - InputFactory.Parameter( - KnownParameters.Endpoint.Name, - InputPrimitiveType.String, - location: RequestLocation.None, - defaultValue: null, - kind: InputOperationParameterKind.Client, - isEndpoint: true) - }, - new List - { - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), - new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), true), "_optionalNullableParam"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), false), "_requiredParam2"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(long), false), "_requiredParam3") - }); - } - } - - public static IEnumerable SubClientFieldsTestCases - { - get - { - yield return new TestCaseData(InputFactory.Client(TestClientName), new List - { - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), - new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), - new(FieldModifiers.Private, new ExpectedCSharpType("Animal", "Sample", true), "_cachedAnimal"), - }); - yield return new TestCaseData(_animalClient, new List - { - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), - new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), - new(FieldModifiers.Private, new ExpectedCSharpType("Dog", "Sample", true), "_cachedDog"), - }); - yield return new TestCaseData(_dogClient, new List - { - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), - new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), - new(FieldModifiers.Private, new ExpectedCSharpType("Husky", "Sample", true), "_cachedHusky"), - }); - yield return new TestCaseData(_huskyClient, new List - { - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), - new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential") - }); - } - } - - public static IEnumerable SubClientFactoryMethodTestCases - { - get - { - yield return new TestCaseData(InputFactory.Client(TestClientName), true); - yield return new TestCaseData(_animalClient, true); - yield return new TestCaseData(_dogClient, true); - yield return new TestCaseData(_huskyClient, false); - } - } - - public static IEnumerable BuildConstructorsTestCases - { - get - { - yield return new TestCaseData(new List - { - InputFactory.Parameter( - "optionalParam", - InputPrimitiveType.String, - location: RequestLocation.None, - kind: InputOperationParameterKind.Client), - InputFactory.Parameter( - KnownParameters.Endpoint.Name, - InputPrimitiveType.String, - location: RequestLocation.None, - defaultValue: InputFactory.Constant.String("someValue"), - kind: InputOperationParameterKind.Client, - isEndpoint: true) - }); - // scenario where endpoint is required - yield return new TestCaseData(new List - { - InputFactory.Parameter( - KnownParameters.Endpoint.Name, - InputPrimitiveType.String, - location: RequestLocation.None, - kind: InputOperationParameterKind.Client, - isRequired: true, - isEndpoint: true), - InputFactory.Parameter( - "optionalParam", - InputPrimitiveType.String, - location: RequestLocation.None, - kind: InputOperationParameterKind.Client) - }); - } - } - - private static IEnumerable EndpointParamInitializationValueTestCases() - { - // string primitive type - yield return new TestCaseData( - InputFactory.Parameter( - "param", - InputPrimitiveType.String, - location: RequestLocation.None, - kind: InputOperationParameterKind.Client, - isEndpoint: true, - defaultValue: InputFactory.Constant.String("mockValue")), - New.Instance(KnownParameters.Endpoint.Type, Literal("mockvalue"))); - } - - private record TestClientPipelineApi : ClientPipelineApi - { - private static ClientPipelineApi? _instance; - internal static ClientPipelineApi Instance => _instance ??= new TestClientPipelineApi(Empty); - - public TestClientPipelineApi(ValueExpression original) : base(typeof(string), original) - { - } - - public override CSharpType ClientPipelineType => typeof(string); - - public override CSharpType ClientPipelineOptionsType => typeof(string); - - public override CSharpType PipelinePolicyType => typeof(string); - - public override CSharpType? KeyCredentialType => null; - - public override CSharpType TokenCredentialType => typeof(TestTokenCredential); - - public override ValueExpression Create(ValueExpression options, ValueExpression perRetryPolicies) - => Original.Invoke("GetFakeCreate", [options, perRetryPolicies]); - - public override ValueExpression CreateMessage(HttpRequestOptionsApi requestOptions, ValueExpression responseClassifier) - => Original.Invoke("GetFakeCreateMessage", [requestOptions, responseClassifier]); - - public override ClientPipelineApi FromExpression(ValueExpression expression) - => new TestClientPipelineApi(expression); - - public override ValueExpression ConsumeKeyAuth(ValueExpression credential, ValueExpression headerName, ValueExpression? keyPrefix = null) - => throw new InvalidOperationException("ApiKey is not supported in this test"); - - public override ValueExpression ConsumeOAuth2Auth(ValueExpression credential, ValueExpression scopes) - => Original.Invoke("GetFakeTokenAuthorizationPolicy", [credential, scopes]); - - public override ClientPipelineApi ToExpression() => this; - - public override MethodBodyStatement[] ProcessMessage(HttpMessageApi message, HttpRequestOptionsApi options) - => [Original.Invoke("GetFakeProcessMessage", [message, options]).Terminate()]; - - public override MethodBodyStatement[] ProcessMessageAsync(HttpMessageApi message, HttpRequestOptionsApi options) - => [Original.Invoke("GetFakeProcessMessageAsync", [message, options]).Terminate()]; - } - - internal class TestTokenCredential { } - } + //public class ClientProviderOAuth2AuthTests + //{ + // private const string SubClientsCategory = "WithSubClients"; + // private const string TestClientName = "TestClient"; + // private static readonly InputClient _animalClient = new("animal", "AnimalClient description", [], [], TestClientName); + // private static readonly InputClient _dogClient = new("dog", "DogClient description", [], [], _animalClient.Name); + // private static readonly InputClient _huskyClient = new("husky", "HuskyClient description", [], [], _dogClient.Name); + + // [SetUp] + // public void SetUp() + // { + // var categories = TestContext.CurrentContext.Test?.Properties["Category"]; + // bool containsSubClients = categories?.Contains(SubClientsCategory) ?? false; + + // if (containsSubClients) + // { + // MockHelpers.LoadMockPlugin( + // oauth2Auth: () => new InputOAuth2Auth(["mock"]), + // clients: () => [_animalClient, _dogClient, _huskyClient], + // clientPipelineApi: TestClientPipelineApi.Instance); + // } + // else + // { + // MockHelpers.LoadMockPlugin( + // oauth2Auth: () => new InputOAuth2Auth(["mock"]), + // clientPipelineApi: TestClientPipelineApi.Instance); + // } + // } + + // [TestCaseSource(nameof(BuildFieldsTestCases))] + // public void TestBuildFields(List inputParameters, List expectedFields) + // { + // var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); + // var clientProvider = new ClientProvider(client); + + // Assert.IsNotNull(clientProvider); + + // AssertClientFields(clientProvider, expectedFields); + // } + + // // validates the fields are built correctly when a client has sub-clients + // [TestCaseSource(nameof(SubClientFieldsTestCases), Category = SubClientsCategory)] + // public void TestBuildFields_WithSubClients(InputClient client, List expectedFields) + // { + // var clientProvider = new ClientProvider(client); + + // Assert.IsNotNull(clientProvider); + + // AssertClientFields(clientProvider, expectedFields); + // } + + // [TestCaseSource(nameof(BuildConstructorsTestCases))] + // public void TestBuildConstructors_PrimaryConstructor(List inputParameters) + // { + // var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); + // var clientProvider = new ClientProvider(client); + + // Assert.IsNotNull(clientProvider); + + // var constructors = clientProvider.Constructors; + // Assert.AreEqual(3, constructors.Count); + + // var primaryPublicConstructor = constructors.FirstOrDefault( + // c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); + // ValidatePrimaryConstructor(primaryPublicConstructor, inputParameters); + // } + + // [TestCaseSource(nameof(BuildConstructorsTestCases))] + // public void TestBuildConstructors_SecondaryConstructor(List inputParameters) + // { + // var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); + // var clientProvider = new ClientProvider(client); + + // Assert.IsNotNull(clientProvider); + + // var constructors = clientProvider.Constructors; + + // Assert.AreEqual(3, constructors.Count); + // var primaryPublicConstructor = constructors.FirstOrDefault( + // c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); + + // Assert.IsNotNull(primaryPublicConstructor); + + // var secondaryPublicConstructor = constructors.FirstOrDefault( + // c => c.Signature?.Initializer != null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); + // ValidateSecondaryConstructor(primaryPublicConstructor, secondaryPublicConstructor, inputParameters); + // } + + // [Test] + // public void TestBuildConstructors_ForSubClient() + // { + // var clientProvider = new ClientProvider(_animalClient); + + // Assert.IsNotNull(clientProvider); + + // var constructors = clientProvider.Constructors; + + // Assert.AreEqual(2, constructors.Count); + // var internalConstructor = constructors.FirstOrDefault( + // c => c.Signature?.Modifiers == MethodSignatureModifiers.Internal); + // Assert.IsNotNull(internalConstructor); + // var ctorParams = internalConstructor?.Signature?.Parameters; + // Assert.AreEqual(3, ctorParams?.Count); + + // var mockingConstructor = constructors.FirstOrDefault( + // c => c.Signature?.Modifiers == MethodSignatureModifiers.Protected); + // Assert.IsNotNull(mockingConstructor); + // } + + // private static void ValidatePrimaryConstructor( + // ConstructorProvider? primaryPublicConstructor, + // List inputParameters) + // { + // Assert.IsNotNull(primaryPublicConstructor); + + // var primaryCtorParams = primaryPublicConstructor?.Signature?.Parameters; + // var expectedPrimaryCtorParamCount = 3; + + // Assert.AreEqual(expectedPrimaryCtorParamCount, primaryCtorParams?.Count); + + // // validate the order of the parameters (endpoint, credential, client options) + // var endpointParam = primaryCtorParams?[0]; + // Assert.AreEqual(KnownParameters.Endpoint.Name, endpointParam?.Name); + // Assert.AreEqual("tokenCredential", primaryCtorParams?[1].Name); + // Assert.AreEqual("options", primaryCtorParams?[2].Name); + + // if (endpointParam?.DefaultValue != null) + // { + // var inputEndpointParam = inputParameters.FirstOrDefault(p => p.IsEndpoint); + // var parsedValue = inputEndpointParam?.DefaultValue?.Value; + // Assert.AreEqual(Literal(parsedValue), endpointParam?.InitializationValue); + // } + + // // validate the body of the primary ctor + // var primaryCtorBody = primaryPublicConstructor?.BodyStatements; + // Assert.IsNotNull(primaryCtorBody); + // } + + // private void ValidateSecondaryConstructor( + // ConstructorProvider? primaryConstructor, + // ConstructorProvider? secondaryPublicConstructor, + // List inputParameters) + // { + // Assert.IsNotNull(secondaryPublicConstructor); + // var ctorParams = secondaryPublicConstructor?.Signature?.Parameters; + + // // secondary ctor should consist of all required parameters + auth parameter + // var requiredParams = inputParameters.Where(p => p.IsRequired).ToList(); + // Assert.AreEqual(requiredParams.Count + 1, ctorParams?.Count); + // var endpointParam = ctorParams?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); + + // if (requiredParams.Count == 0) + // { + // // auth should be the only parameter if endpoint is optional + // Assert.AreEqual("tokenCredential", ctorParams?[0].Name); + // } + // else + // { + // // otherwise, it should only consist of the auth parameter + // Assert.AreEqual(KnownParameters.Endpoint.Name, ctorParams?[0].Name); + // Assert.AreEqual("tokenCredential", ctorParams?[1].Name); + // } + + // Assert.AreEqual(MethodBodyStatement.Empty, secondaryPublicConstructor?.BodyStatements); + + // // validate the initializer + // var initializer = secondaryPublicConstructor?.Signature?.Initializer; + // Assert.AreEqual(primaryConstructor?.Signature?.Parameters?.Count, initializer?.Arguments?.Count); + // } + + // [TestCaseSource(nameof(EndpointParamInitializationValueTestCases))] + // public void EndpointInitializationValue(InputParameter endpointParameter, ValueExpression? expectedValue) + // { + // var client = InputFactory.Client(TestClientName, parameters: [endpointParameter]); + // var clientProvider = new ClientProvider(client); + + // Assert.IsNotNull(clientProvider); + // // find the endpoint parameter from the primary constructor + // var primaryConstructor = clientProvider.Constructors.FirstOrDefault( + // c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); + // var endpoint = primaryConstructor?.Signature?.Parameters?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); + + // Assert.IsNotNull(endpoint); + // Assert.AreEqual(expectedValue?.GetType(), endpoint?.InitializationValue?.GetType()); + // if (expectedValue != null) + // { + // Assert.IsTrue(endpoint?.InitializationValue is NewInstanceExpression); + // } + // } + + // [TestCaseSource(nameof(SubClientFactoryMethodTestCases), Category = SubClientsCategory)] + // public void TestSubClientAccessorFactoryMethods(InputClient client, bool hasSubClients) + // { + // var clientProvider = new ClientProvider(client); + // Assert.IsNotNull(clientProvider); + + // var methods = clientProvider.Methods; + // List subClientAccessorFactoryMethods = []; + // foreach (var method in methods) + // { + // var methodSignature = method.Signature; + // if (methodSignature != null && + // methodSignature.Name.StartsWith("Get") && + // methodSignature.Modifiers.HasFlag(MethodSignatureModifiers.Public | MethodSignatureModifiers.Virtual)) + // { + // subClientAccessorFactoryMethods.Add(method); + // } + // } + + // if (hasSubClients) + // { + // Assert.AreEqual(1, subClientAccessorFactoryMethods.Count); + // var factoryMethod = subClientAccessorFactoryMethods[0]; + // Assert.AreEqual(0, factoryMethod.Signature?.Parameters.Count); + + // // method body should not be empty + // Assert.AreNotEqual(MethodBodyStatement.Empty, factoryMethod.BodyStatements); + // } + // else + // { + // Assert.AreEqual(0, subClientAccessorFactoryMethods.Count); + // } + // } + + // public static IEnumerable BuildFieldsTestCases + // { + // get + // { + // yield return new TestCaseData(new List + // { + // InputFactory.Parameter( + // "optionalParam", + // InputPrimitiveType.String, + // location: RequestLocation.None, + // kind: InputOperationParameterKind.Client), + // InputFactory.Parameter( + // KnownParameters.Endpoint.Name, + // InputPrimitiveType.String, + // location:RequestLocation.None, + // kind: InputOperationParameterKind.Client, + // isEndpoint: true) + // }, + // new List + // { + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + // new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), true), "_optionalParam") + // } + // ); + // yield return new TestCaseData(new List + // { + // // have to explicitly set isRequired because we now call CreateParameter in buildFields + // InputFactory.Parameter( + // "optionalNullableParam", + // InputPrimitiveType.String, + // location: RequestLocation.None, + // defaultValue: InputFactory.Constant.String("someValue"), + // kind: InputOperationParameterKind.Client, + // isRequired: false), + // InputFactory.Parameter( + // "requiredParam2", + // InputPrimitiveType.String, + // location: RequestLocation.None, + // defaultValue: InputFactory.Constant.String("someValue"), + // kind: InputOperationParameterKind.Client, + // isRequired: true), + // InputFactory.Parameter( + // "requiredParam3", + // InputPrimitiveType.Int64, + // location: RequestLocation.None, + // defaultValue: InputFactory.Constant.Int64(2), + // kind: InputOperationParameterKind.Client, + // isRequired: true), + // InputFactory.Parameter( + // KnownParameters.Endpoint.Name, + // InputPrimitiveType.String, + // location: RequestLocation.None, + // defaultValue: null, + // kind: InputOperationParameterKind.Client, + // isEndpoint: true) + // }, + // new List + // { + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + // new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), true), "_optionalNullableParam"), + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), false), "_requiredParam2"), + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(long), false), "_requiredParam3") + // }); + // } + // } + + // public static IEnumerable SubClientFieldsTestCases + // { + // get + // { + // yield return new TestCaseData(InputFactory.Client(TestClientName), new List + // { + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + // new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), + // new(FieldModifiers.Private, new ExpectedCSharpType("Animal", "Sample", true), "_cachedAnimal"), + // }); + // yield return new TestCaseData(_animalClient, new List + // { + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + // new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), + // new(FieldModifiers.Private, new ExpectedCSharpType("Dog", "Sample", true), "_cachedDog"), + // }); + // yield return new TestCaseData(_dogClient, new List + // { + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + // new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), + // new(FieldModifiers.Private, new ExpectedCSharpType("Husky", "Sample", true), "_cachedHusky"), + // }); + // yield return new TestCaseData(_huskyClient, new List + // { + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), + // new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), + // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential") + // }); + // } + // } + + // public static IEnumerable SubClientFactoryMethodTestCases + // { + // get + // { + // yield return new TestCaseData(InputFactory.Client(TestClientName), true); + // yield return new TestCaseData(_animalClient, true); + // yield return new TestCaseData(_dogClient, true); + // yield return new TestCaseData(_huskyClient, false); + // } + // } + + // public static IEnumerable BuildConstructorsTestCases + // { + // get + // { + // yield return new TestCaseData(new List + // { + // InputFactory.Parameter( + // "optionalParam", + // InputPrimitiveType.String, + // location: RequestLocation.None, + // kind: InputOperationParameterKind.Client), + // InputFactory.Parameter( + // KnownParameters.Endpoint.Name, + // InputPrimitiveType.String, + // location: RequestLocation.None, + // defaultValue: InputFactory.Constant.String("someValue"), + // kind: InputOperationParameterKind.Client, + // isEndpoint: true) + // }); + // // scenario where endpoint is required + // yield return new TestCaseData(new List + // { + // InputFactory.Parameter( + // KnownParameters.Endpoint.Name, + // InputPrimitiveType.String, + // location: RequestLocation.None, + // kind: InputOperationParameterKind.Client, + // isRequired: true, + // isEndpoint: true), + // InputFactory.Parameter( + // "optionalParam", + // InputPrimitiveType.String, + // location: RequestLocation.None, + // kind: InputOperationParameterKind.Client) + // }); + // } + // } + + // private static IEnumerable EndpointParamInitializationValueTestCases() + // { + // // string primitive type + // yield return new TestCaseData( + // InputFactory.Parameter( + // "param", + // InputPrimitiveType.String, + // location: RequestLocation.None, + // kind: InputOperationParameterKind.Client, + // isEndpoint: true, + // defaultValue: InputFactory.Constant.String("mockValue")), + // New.Instance(KnownParameters.Endpoint.Type, Literal("mockvalue"))); + // } + + // private record TestClientPipelineApi : ClientPipelineApi + // { + // private static ClientPipelineApi? _instance; + // internal static ClientPipelineApi Instance => _instance ??= new TestClientPipelineApi(Empty); + + // public TestClientPipelineApi(ValueExpression original) : base(typeof(string), original) + // { + // } + + // public override CSharpType ClientPipelineType => typeof(string); + + // public override CSharpType ClientPipelineOptionsType => typeof(string); + + // public override CSharpType PipelinePolicyType => typeof(string); + + // public override CSharpType? KeyCredentialType => null; + + // public override CSharpType TokenCredentialType => typeof(TestTokenCredential); + + // public override ValueExpression Create(ValueExpression options, ValueExpression perRetryPolicies) + // => Original.Invoke("GetFakeCreate", [options, perRetryPolicies]); + + // public override ValueExpression CreateMessage(HttpRequestOptionsApi requestOptions, ValueExpression responseClassifier) + // => Original.Invoke("GetFakeCreateMessage", [requestOptions, responseClassifier]); + + // public override ClientPipelineApi FromExpression(ValueExpression expression) + // => new TestClientPipelineApi(expression); + + // public override ValueExpression ConsumeKeyAuth(ValueExpression credential, ValueExpression headerName, ValueExpression? keyPrefix = null) + // => throw new InvalidOperationException("ApiKey is not supported in this test"); + + // public override ValueExpression ConsumeOAuth2Auth(ValueExpression credential, ValueExpression scopes) + // => Original.Invoke("GetFakeTokenAuthorizationPolicy", [credential, scopes]); + + // public override ClientPipelineApi ToExpression() => this; + + // public override MethodBodyStatement[] ProcessMessage(HttpMessageApi message, HttpRequestOptionsApi options) + // => [Original.Invoke("GetFakeProcessMessage", [message, options]).Terminate()]; + + // public override MethodBodyStatement[] ProcessMessageAsync(HttpMessageApi message, HttpRequestOptionsApi options) + // => [Original.Invoke("GetFakeProcessMessageAsync", [message, options]).Terminate()]; + // } + + // internal class TestTokenCredential { } + //} } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs index 62f863574c..4f22943e05 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs @@ -33,6 +33,23 @@ public class ClientProviderTests InputFactory.Property("p1", InputPrimitiveType.String, isRequired: true), ]); + [SetUp] + public void SetUp() + { + var categories = TestContext.CurrentContext.Test?.Properties["Category"]; + bool containsSubClients = categories?.Contains(SubClientsCategory) ?? false; + if (containsSubClients) + { + MockHelpers.LoadMockPlugin( + apiKeyAuth: () => new InputApiKeyAuth("mock", null), + clients: () => [_animalClient, _dogClient, _huskyClient]); + } + else + { + MockHelpers.LoadMockPlugin(apiKeyAuth: () => new InputApiKeyAuth("mock", null)); + } + } + [Test] public void TestBuildProperties() { From 3f2275f064ab123aac87ac8b28120d5dc6d2e5ef Mon Sep 17 00:00:00 2001 From: Dapeng Zhang Date: Wed, 4 Dec 2024 15:46:32 +0800 Subject: [PATCH 10/22] remove two deprecated test case classes --- .../ClientProviderNoAuthTests.cs | 415 ---------------- .../ClientProviderOAuth2AuthTests.cs | 459 ------------------ 2 files changed, 874 deletions(-) delete mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderNoAuthTests.cs delete mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderOAuth2AuthTests.cs diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderNoAuthTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderNoAuthTests.cs deleted file mode 100644 index 6ec27a48bc..0000000000 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderNoAuthTests.cs +++ /dev/null @@ -1,415 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.ClientModel; -using System.ClientModel.Primitives; -using System.Collections.Generic; -using System.Linq; -using Microsoft.Generator.CSharp.ClientModel.Providers; -using Microsoft.Generator.CSharp.Expressions; -using Microsoft.Generator.CSharp.Input; -using Microsoft.Generator.CSharp.Primitives; -using Microsoft.Generator.CSharp.Providers; -using Microsoft.Generator.CSharp.Snippets; -using Microsoft.Generator.CSharp.Statements; -using Microsoft.Generator.CSharp.Tests.Common; -using NUnit.Framework; -using static Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders.ClientProviderTestsUtils; -using static Microsoft.Generator.CSharp.Snippets.Snippet; - -namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders -{ - //public class ClientProviderNoAuthTests - //{ - // private const string SubClientsCategory = "WithSubClients"; - // private const string TestClientName = "TestClient"; - // private static readonly InputClient _animalClient = new("animal", "AnimalClient description", [], [], TestClientName); - // private static readonly InputClient _dogClient = new("dog", "DogClient description", [], [], _animalClient.Name); - // private static readonly InputClient _huskyClient = new("husky", "HuskyClient description", [], [], _dogClient.Name); - - // [SetUp] - // public void SetUp() - // { - // var categories = TestContext.CurrentContext.Test?.Properties["Category"]; - // bool containsSubClients = categories?.Contains(SubClientsCategory) ?? false; - - // if (containsSubClients) - // { - // MockHelpers.LoadMockPlugin( - // clients: () => [_animalClient, _dogClient, _huskyClient]); - // } - // else - // { - // MockHelpers.LoadMockPlugin(); - // } - // } - - // [Test] - // public void TestBuildProperties() - // { - // var client = InputFactory.Client(TestClientName); - // var clientProvider = new ClientProvider(client); - - // Assert.IsNotNull(clientProvider); - - // // validate the properties - // var properties = clientProvider.Properties; - // Assert.IsTrue(properties.Count > 0); - // // there should be a pipeline property - // Assert.AreEqual(1, properties.Count); - - // var pipelineProperty = properties[0]; - // Assert.AreEqual(typeof(ClientPipeline), pipelineProperty.Type.FrameworkType); - // Assert.AreEqual("Pipeline", pipelineProperty.Name); - // Assert.AreEqual(MethodSignatureModifiers.Public, pipelineProperty.Modifiers); - // } - - // [TestCaseSource(nameof(BuildFieldsTestCases))] - // public void TestBuildFields(List inputParameters, List expectedFields) - // { - // var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); - // var clientProvider = new ClientProvider(client); - - // Assert.IsNotNull(clientProvider); - - // AssertClientFields(clientProvider, expectedFields); - // } - - // // validates the fields are built correctly when a client has sub-clients - // [TestCaseSource(nameof(SubClientFieldsTestCases), Category = SubClientsCategory)] - // public void TestBuildFields_WithSubClients(InputClient client, List expectedFields) - // { - // var clientProvider = new ClientProvider(client); - - // Assert.IsNotNull(clientProvider); - - // AssertClientFields(clientProvider, expectedFields); - // } - - // [TestCaseSource(nameof(BuildConstructorsTestCases))] - // public void TestBuildConstructors_PrimaryConstructor(List inputParameters, int expectedCount) - // { - // var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); - // var clientProvider = new ClientProvider(client); - - // Assert.IsNotNull(clientProvider); - - // var constructors = clientProvider.Constructors; - // Assert.AreEqual(expectedCount, constructors.Count); - - // var primaryPublicConstructor = constructors.FirstOrDefault( - // c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); - // ValidatePrimaryConstructor(primaryPublicConstructor, inputParameters); - // } - - // [TestCaseSource(nameof(BuildConstructorsTestCases))] - // public void TestBuildConstructors_SecondaryConstructor(List inputParameters, int expectedCount) - // { - // var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); - // var clientProvider = new ClientProvider(client); - - // Assert.IsNotNull(clientProvider); - - // var constructors = clientProvider.Constructors; - - // Assert.AreEqual(expectedCount, constructors.Count); - // var primaryPublicConstructor = constructors.FirstOrDefault( - // c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); - - // Assert.IsNotNull(primaryPublicConstructor); - - // var secondaryPublicConstructor = constructors.FirstOrDefault( - // c => c.Signature?.Initializer != null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); - // ValidateSecondaryConstructor(primaryPublicConstructor, secondaryPublicConstructor, inputParameters); - // } - - // [Test] - // public void TestBuildConstructors_ForSubClient() - // { - // var clientProvider = new ClientProvider(_animalClient); - - // Assert.IsNotNull(clientProvider); - - // var constructors = clientProvider.Constructors; - - // Assert.AreEqual(2, constructors.Count); - // var internalConstructor = constructors.FirstOrDefault( - // c => c.Signature?.Modifiers == MethodSignatureModifiers.Internal); - // Assert.IsNotNull(internalConstructor); - // var ctorParams = internalConstructor?.Signature?.Parameters; - // Assert.AreEqual(2, ctorParams?.Count); // only 2 because there is no credential parameter - - // var mockingConstructor = constructors.FirstOrDefault( - // c => c.Signature?.Modifiers == MethodSignatureModifiers.Protected); - // Assert.IsNotNull(mockingConstructor); - // } - - // private static void ValidatePrimaryConstructor( - // ConstructorProvider? primaryPublicConstructor, - // List inputParameters) - // { - // Assert.IsNotNull(primaryPublicConstructor); - - // var primaryCtorParams = primaryPublicConstructor?.Signature?.Parameters; - - // Assert.AreEqual(2, primaryCtorParams?.Count); // only 2 because there is no credential parameter - - // // validate the order of the parameters (endpoint, credential, client options) - // var endpointParam = primaryCtorParams?[0]; - // Assert.AreEqual(KnownParameters.Endpoint.Name, endpointParam?.Name); - // Assert.AreEqual("options", primaryCtorParams?[1].Name); - - // if (endpointParam?.DefaultValue != null) - // { - // var inputEndpointParam = inputParameters.FirstOrDefault(p => p.IsEndpoint); - // var parsedValue = inputEndpointParam?.DefaultValue?.Value; - // Assert.AreEqual(Literal(parsedValue), endpointParam?.InitializationValue); - // } - - // // validate the body of the primary ctor - // var primaryCtorBody = primaryPublicConstructor?.BodyStatements; - // Assert.IsNotNull(primaryCtorBody); - // } - - // private void ValidateSecondaryConstructor( - // ConstructorProvider? primaryConstructor, - // ConstructorProvider? secondaryPublicConstructor, - // List inputParameters) - // { - // Assert.IsNotNull(secondaryPublicConstructor); - // var ctorParams = secondaryPublicConstructor?.Signature?.Parameters; - - // // secondary ctor should consist of all required parameters + auth parameter, but here we do not have auth, therefore they should be the same - // var requiredParams = inputParameters.Where(p => p.IsRequired).ToList(); - // Assert.AreEqual(requiredParams.Count, ctorParams?.Count); - // var endpointParam = ctorParams?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); - - // if (requiredParams.Count == 0) - // { - // // there should be no parameter if endpoint is optional and we do not have an auth - // Assert.AreEqual(0, ctorParams?.Count); - // } - // else - // { - // // otherwise, it should only consist of the endpoint parameter - // Assert.AreEqual(KnownParameters.Endpoint.Name, ctorParams?[0].Name); - // } - - // Assert.AreEqual(MethodBodyStatement.Empty, secondaryPublicConstructor?.BodyStatements); - - // // validate the initializer - // var initializer = secondaryPublicConstructor?.Signature?.Initializer; - // Assert.AreEqual(primaryConstructor?.Signature?.Parameters?.Count, initializer?.Arguments?.Count); - // } - - // [TestCaseSource(nameof(EndpointParamInitializationValueTestCases))] - // public void EndpointInitializationValue(InputParameter endpointParameter, ValueExpression? expectedValue) - // { - // var client = InputFactory.Client(TestClientName, parameters: [endpointParameter]); - // var clientProvider = new ClientProvider(client); - - // Assert.IsNotNull(clientProvider); - // // find the endpoint parameter from the primary constructor - // var primaryConstructor = clientProvider.Constructors.FirstOrDefault( - // c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); - // var endpoint = primaryConstructor?.Signature?.Parameters?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); - - // Assert.IsNotNull(endpoint); - // Assert.AreEqual(expectedValue?.GetType(), endpoint?.InitializationValue?.GetType()); - // if (expectedValue != null) - // { - // Assert.IsTrue(endpoint?.InitializationValue is NewInstanceExpression); - // } - // } - - // [TestCaseSource(nameof(SubClientFactoryMethodTestCases), Category = SubClientsCategory)] - // public void TestSubClientAccessorFactoryMethods(InputClient client, bool hasSubClients) - // { - // var clientProvider = new ClientProvider(client); - // Assert.IsNotNull(clientProvider); - - // var methods = clientProvider.Methods; - // List subClientAccessorFactoryMethods = []; - // foreach (var method in methods) - // { - // var methodSignature = method.Signature; - // if (methodSignature != null && - // methodSignature.Name.StartsWith("Get") && - // methodSignature.Modifiers.HasFlag(MethodSignatureModifiers.Public | MethodSignatureModifiers.Virtual)) - // { - // subClientAccessorFactoryMethods.Add(method); - // } - // } - - // if (hasSubClients) - // { - // Assert.AreEqual(1, subClientAccessorFactoryMethods.Count); - // var factoryMethod = subClientAccessorFactoryMethods[0]; - // Assert.AreEqual(0, factoryMethod.Signature?.Parameters.Count); - - // // method body should not be empty - // Assert.AreNotEqual(MethodBodyStatement.Empty, factoryMethod.BodyStatements); - // } - // else - // { - // Assert.AreEqual(0, subClientAccessorFactoryMethods.Count); - // } - // } - - // public static IEnumerable BuildFieldsTestCases - // { - // get - // { - // yield return new TestCaseData(new List - // { - // InputFactory.Parameter( - // "optionalParam", - // InputPrimitiveType.String, - // location: RequestLocation.None, - // kind: InputOperationParameterKind.Client), - // InputFactory.Parameter( - // KnownParameters.Endpoint.Name, - // InputPrimitiveType.String, - // location:RequestLocation.None, - // kind: InputOperationParameterKind.Client, - // isEndpoint: true) - // }, - // new List - // { - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), true), "_optionalParam") - // } - // ); - // yield return new TestCaseData(new List - // { - // // have to explicitly set isRequired because we now call CreateParameter in buildFields - // InputFactory.Parameter( - // "optionalNullableParam", - // InputPrimitiveType.String, - // location: RequestLocation.None, - // defaultValue: InputFactory.Constant.String("someValue"), - // kind: InputOperationParameterKind.Client, - // isRequired: false), - // InputFactory.Parameter( - // "requiredParam2", - // InputPrimitiveType.String, - // location: RequestLocation.None, - // defaultValue: InputFactory.Constant.String("someValue"), - // kind: InputOperationParameterKind.Client, - // isRequired: true), - // InputFactory.Parameter( - // "requiredParam3", - // InputPrimitiveType.Int64, - // location: RequestLocation.None, - // defaultValue: InputFactory.Constant.Int64(2), - // kind: InputOperationParameterKind.Client, - // isRequired: true), - // InputFactory.Parameter( - // KnownParameters.Endpoint.Name, - // InputPrimitiveType.String, - // location: RequestLocation.None, - // defaultValue: null, - // kind: InputOperationParameterKind.Client, - // isEndpoint: true) - // }, - // new List - // { - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), true), "_optionalNullableParam"), - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), false), "_requiredParam2"), - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(long), false), "_requiredParam3") - // }); - // } - // } - - // public static IEnumerable SubClientFieldsTestCases - // { - // get - // { - // yield return new TestCaseData(InputFactory.Client(TestClientName), new List - // { - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), - // new(FieldModifiers.Private, new ExpectedCSharpType("Animal", "Sample", true), "_cachedAnimal"), - // }); - // yield return new TestCaseData(_animalClient, new List - // { - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), - // new(FieldModifiers.Private, new ExpectedCSharpType("Dog", "Sample", true), "_cachedDog"), - // }); - // yield return new TestCaseData(_dogClient, new List - // { - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), - // new(FieldModifiers.Private, new ExpectedCSharpType("Husky", "Sample", true), "_cachedHusky"), - // }); - // yield return new TestCaseData(_huskyClient, new List - // { - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), - // }); - // } - // } - - // public static IEnumerable SubClientFactoryMethodTestCases - // { - // get - // { - // yield return new TestCaseData(InputFactory.Client(TestClientName), true); - // yield return new TestCaseData(_animalClient, true); - // yield return new TestCaseData(_dogClient, true); - // yield return new TestCaseData(_huskyClient, false); - // } - // } - - // public static IEnumerable BuildConstructorsTestCases - // { - // get - // { - // yield return new TestCaseData(new List - // { - // InputFactory.Parameter( - // "optionalParam", - // InputPrimitiveType.String, - // location: RequestLocation.None, - // kind: InputOperationParameterKind.Client), - // InputFactory.Parameter( - // KnownParameters.Endpoint.Name, - // InputPrimitiveType.String, - // location: RequestLocation.None, - // defaultValue: InputFactory.Constant.String("someValue"), - // kind: InputOperationParameterKind.Client, - // isEndpoint: true) - // }, 2); // in this case, the secondary ctor has the same ctor list as the protected ctor - // // scenario where endpoint is required - // yield return new TestCaseData(new List - // { - // InputFactory.Parameter( - // KnownParameters.Endpoint.Name, - // InputPrimitiveType.String, - // location: RequestLocation.None, - // kind: InputOperationParameterKind.Client, - // isRequired: true, - // isEndpoint: true), - // InputFactory.Parameter( - // "optionalParam", - // InputPrimitiveType.String, - // location: RequestLocation.None, - // kind: InputOperationParameterKind.Client) - // }, 3); - // } - // } - - // private static IEnumerable EndpointParamInitializationValueTestCases() - // { - // // string primitive type - // yield return new TestCaseData( - // InputFactory.Parameter( - // "param", - // InputPrimitiveType.String, - // location: RequestLocation.None, - // kind: InputOperationParameterKind.Client, - // isEndpoint: true, - // defaultValue: InputFactory.Constant.String("mockValue")), - // New.Instance(KnownParameters.Endpoint.Type, Literal("mockvalue"))); - // } - //} -} diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderOAuth2AuthTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderOAuth2AuthTests.cs deleted file mode 100644 index b389232ee9..0000000000 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderOAuth2AuthTests.cs +++ /dev/null @@ -1,459 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.ClientModel; -using System.ClientModel.Primitives; -using System.Collections.Generic; -using System.Linq; -using Microsoft.Generator.CSharp.ClientModel.Providers; -using Microsoft.Generator.CSharp.Expressions; -using Microsoft.Generator.CSharp.Input; -using Microsoft.Generator.CSharp.Primitives; -using Microsoft.Generator.CSharp.Providers; -using Microsoft.Generator.CSharp.Snippets; -using Microsoft.Generator.CSharp.Statements; -using Microsoft.Generator.CSharp.Tests.Common; -using NUnit.Framework; -using static Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders.ClientProviderTestsUtils; -using static Microsoft.Generator.CSharp.Snippets.Snippet; - -namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders -{ - //public class ClientProviderOAuth2AuthTests - //{ - // private const string SubClientsCategory = "WithSubClients"; - // private const string TestClientName = "TestClient"; - // private static readonly InputClient _animalClient = new("animal", "AnimalClient description", [], [], TestClientName); - // private static readonly InputClient _dogClient = new("dog", "DogClient description", [], [], _animalClient.Name); - // private static readonly InputClient _huskyClient = new("husky", "HuskyClient description", [], [], _dogClient.Name); - - // [SetUp] - // public void SetUp() - // { - // var categories = TestContext.CurrentContext.Test?.Properties["Category"]; - // bool containsSubClients = categories?.Contains(SubClientsCategory) ?? false; - - // if (containsSubClients) - // { - // MockHelpers.LoadMockPlugin( - // oauth2Auth: () => new InputOAuth2Auth(["mock"]), - // clients: () => [_animalClient, _dogClient, _huskyClient], - // clientPipelineApi: TestClientPipelineApi.Instance); - // } - // else - // { - // MockHelpers.LoadMockPlugin( - // oauth2Auth: () => new InputOAuth2Auth(["mock"]), - // clientPipelineApi: TestClientPipelineApi.Instance); - // } - // } - - // [TestCaseSource(nameof(BuildFieldsTestCases))] - // public void TestBuildFields(List inputParameters, List expectedFields) - // { - // var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); - // var clientProvider = new ClientProvider(client); - - // Assert.IsNotNull(clientProvider); - - // AssertClientFields(clientProvider, expectedFields); - // } - - // // validates the fields are built correctly when a client has sub-clients - // [TestCaseSource(nameof(SubClientFieldsTestCases), Category = SubClientsCategory)] - // public void TestBuildFields_WithSubClients(InputClient client, List expectedFields) - // { - // var clientProvider = new ClientProvider(client); - - // Assert.IsNotNull(clientProvider); - - // AssertClientFields(clientProvider, expectedFields); - // } - - // [TestCaseSource(nameof(BuildConstructorsTestCases))] - // public void TestBuildConstructors_PrimaryConstructor(List inputParameters) - // { - // var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); - // var clientProvider = new ClientProvider(client); - - // Assert.IsNotNull(clientProvider); - - // var constructors = clientProvider.Constructors; - // Assert.AreEqual(3, constructors.Count); - - // var primaryPublicConstructor = constructors.FirstOrDefault( - // c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); - // ValidatePrimaryConstructor(primaryPublicConstructor, inputParameters); - // } - - // [TestCaseSource(nameof(BuildConstructorsTestCases))] - // public void TestBuildConstructors_SecondaryConstructor(List inputParameters) - // { - // var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); - // var clientProvider = new ClientProvider(client); - - // Assert.IsNotNull(clientProvider); - - // var constructors = clientProvider.Constructors; - - // Assert.AreEqual(3, constructors.Count); - // var primaryPublicConstructor = constructors.FirstOrDefault( - // c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); - - // Assert.IsNotNull(primaryPublicConstructor); - - // var secondaryPublicConstructor = constructors.FirstOrDefault( - // c => c.Signature?.Initializer != null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); - // ValidateSecondaryConstructor(primaryPublicConstructor, secondaryPublicConstructor, inputParameters); - // } - - // [Test] - // public void TestBuildConstructors_ForSubClient() - // { - // var clientProvider = new ClientProvider(_animalClient); - - // Assert.IsNotNull(clientProvider); - - // var constructors = clientProvider.Constructors; - - // Assert.AreEqual(2, constructors.Count); - // var internalConstructor = constructors.FirstOrDefault( - // c => c.Signature?.Modifiers == MethodSignatureModifiers.Internal); - // Assert.IsNotNull(internalConstructor); - // var ctorParams = internalConstructor?.Signature?.Parameters; - // Assert.AreEqual(3, ctorParams?.Count); - - // var mockingConstructor = constructors.FirstOrDefault( - // c => c.Signature?.Modifiers == MethodSignatureModifiers.Protected); - // Assert.IsNotNull(mockingConstructor); - // } - - // private static void ValidatePrimaryConstructor( - // ConstructorProvider? primaryPublicConstructor, - // List inputParameters) - // { - // Assert.IsNotNull(primaryPublicConstructor); - - // var primaryCtorParams = primaryPublicConstructor?.Signature?.Parameters; - // var expectedPrimaryCtorParamCount = 3; - - // Assert.AreEqual(expectedPrimaryCtorParamCount, primaryCtorParams?.Count); - - // // validate the order of the parameters (endpoint, credential, client options) - // var endpointParam = primaryCtorParams?[0]; - // Assert.AreEqual(KnownParameters.Endpoint.Name, endpointParam?.Name); - // Assert.AreEqual("tokenCredential", primaryCtorParams?[1].Name); - // Assert.AreEqual("options", primaryCtorParams?[2].Name); - - // if (endpointParam?.DefaultValue != null) - // { - // var inputEndpointParam = inputParameters.FirstOrDefault(p => p.IsEndpoint); - // var parsedValue = inputEndpointParam?.DefaultValue?.Value; - // Assert.AreEqual(Literal(parsedValue), endpointParam?.InitializationValue); - // } - - // // validate the body of the primary ctor - // var primaryCtorBody = primaryPublicConstructor?.BodyStatements; - // Assert.IsNotNull(primaryCtorBody); - // } - - // private void ValidateSecondaryConstructor( - // ConstructorProvider? primaryConstructor, - // ConstructorProvider? secondaryPublicConstructor, - // List inputParameters) - // { - // Assert.IsNotNull(secondaryPublicConstructor); - // var ctorParams = secondaryPublicConstructor?.Signature?.Parameters; - - // // secondary ctor should consist of all required parameters + auth parameter - // var requiredParams = inputParameters.Where(p => p.IsRequired).ToList(); - // Assert.AreEqual(requiredParams.Count + 1, ctorParams?.Count); - // var endpointParam = ctorParams?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); - - // if (requiredParams.Count == 0) - // { - // // auth should be the only parameter if endpoint is optional - // Assert.AreEqual("tokenCredential", ctorParams?[0].Name); - // } - // else - // { - // // otherwise, it should only consist of the auth parameter - // Assert.AreEqual(KnownParameters.Endpoint.Name, ctorParams?[0].Name); - // Assert.AreEqual("tokenCredential", ctorParams?[1].Name); - // } - - // Assert.AreEqual(MethodBodyStatement.Empty, secondaryPublicConstructor?.BodyStatements); - - // // validate the initializer - // var initializer = secondaryPublicConstructor?.Signature?.Initializer; - // Assert.AreEqual(primaryConstructor?.Signature?.Parameters?.Count, initializer?.Arguments?.Count); - // } - - // [TestCaseSource(nameof(EndpointParamInitializationValueTestCases))] - // public void EndpointInitializationValue(InputParameter endpointParameter, ValueExpression? expectedValue) - // { - // var client = InputFactory.Client(TestClientName, parameters: [endpointParameter]); - // var clientProvider = new ClientProvider(client); - - // Assert.IsNotNull(clientProvider); - // // find the endpoint parameter from the primary constructor - // var primaryConstructor = clientProvider.Constructors.FirstOrDefault( - // c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); - // var endpoint = primaryConstructor?.Signature?.Parameters?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); - - // Assert.IsNotNull(endpoint); - // Assert.AreEqual(expectedValue?.GetType(), endpoint?.InitializationValue?.GetType()); - // if (expectedValue != null) - // { - // Assert.IsTrue(endpoint?.InitializationValue is NewInstanceExpression); - // } - // } - - // [TestCaseSource(nameof(SubClientFactoryMethodTestCases), Category = SubClientsCategory)] - // public void TestSubClientAccessorFactoryMethods(InputClient client, bool hasSubClients) - // { - // var clientProvider = new ClientProvider(client); - // Assert.IsNotNull(clientProvider); - - // var methods = clientProvider.Methods; - // List subClientAccessorFactoryMethods = []; - // foreach (var method in methods) - // { - // var methodSignature = method.Signature; - // if (methodSignature != null && - // methodSignature.Name.StartsWith("Get") && - // methodSignature.Modifiers.HasFlag(MethodSignatureModifiers.Public | MethodSignatureModifiers.Virtual)) - // { - // subClientAccessorFactoryMethods.Add(method); - // } - // } - - // if (hasSubClients) - // { - // Assert.AreEqual(1, subClientAccessorFactoryMethods.Count); - // var factoryMethod = subClientAccessorFactoryMethods[0]; - // Assert.AreEqual(0, factoryMethod.Signature?.Parameters.Count); - - // // method body should not be empty - // Assert.AreNotEqual(MethodBodyStatement.Empty, factoryMethod.BodyStatements); - // } - // else - // { - // Assert.AreEqual(0, subClientAccessorFactoryMethods.Count); - // } - // } - - // public static IEnumerable BuildFieldsTestCases - // { - // get - // { - // yield return new TestCaseData(new List - // { - // InputFactory.Parameter( - // "optionalParam", - // InputPrimitiveType.String, - // location: RequestLocation.None, - // kind: InputOperationParameterKind.Client), - // InputFactory.Parameter( - // KnownParameters.Endpoint.Name, - // InputPrimitiveType.String, - // location:RequestLocation.None, - // kind: InputOperationParameterKind.Client, - // isEndpoint: true) - // }, - // new List - // { - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), - // new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), true), "_optionalParam") - // } - // ); - // yield return new TestCaseData(new List - // { - // // have to explicitly set isRequired because we now call CreateParameter in buildFields - // InputFactory.Parameter( - // "optionalNullableParam", - // InputPrimitiveType.String, - // location: RequestLocation.None, - // defaultValue: InputFactory.Constant.String("someValue"), - // kind: InputOperationParameterKind.Client, - // isRequired: false), - // InputFactory.Parameter( - // "requiredParam2", - // InputPrimitiveType.String, - // location: RequestLocation.None, - // defaultValue: InputFactory.Constant.String("someValue"), - // kind: InputOperationParameterKind.Client, - // isRequired: true), - // InputFactory.Parameter( - // "requiredParam3", - // InputPrimitiveType.Int64, - // location: RequestLocation.None, - // defaultValue: InputFactory.Constant.Int64(2), - // kind: InputOperationParameterKind.Client, - // isRequired: true), - // InputFactory.Parameter( - // KnownParameters.Endpoint.Name, - // InputPrimitiveType.String, - // location: RequestLocation.None, - // defaultValue: null, - // kind: InputOperationParameterKind.Client, - // isEndpoint: true) - // }, - // new List - // { - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), - // new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), true), "_optionalNullableParam"), - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(string), false), "_requiredParam2"), - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(long), false), "_requiredParam3") - // }); - // } - // } - - // public static IEnumerable SubClientFieldsTestCases - // { - // get - // { - // yield return new TestCaseData(InputFactory.Client(TestClientName), new List - // { - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), - // new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), - // new(FieldModifiers.Private, new ExpectedCSharpType("Animal", "Sample", true), "_cachedAnimal"), - // }); - // yield return new TestCaseData(_animalClient, new List - // { - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), - // new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), - // new(FieldModifiers.Private, new ExpectedCSharpType("Dog", "Sample", true), "_cachedDog"), - // }); - // yield return new TestCaseData(_dogClient, new List - // { - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), - // new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), - // new(FieldModifiers.Private, new ExpectedCSharpType("Husky", "Sample", true), "_cachedHusky"), - // }); - // yield return new TestCaseData(_huskyClient, new List - // { - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(Uri)), "_endpoint"), - // new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), - // new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential") - // }); - // } - // } - - // public static IEnumerable SubClientFactoryMethodTestCases - // { - // get - // { - // yield return new TestCaseData(InputFactory.Client(TestClientName), true); - // yield return new TestCaseData(_animalClient, true); - // yield return new TestCaseData(_dogClient, true); - // yield return new TestCaseData(_huskyClient, false); - // } - // } - - // public static IEnumerable BuildConstructorsTestCases - // { - // get - // { - // yield return new TestCaseData(new List - // { - // InputFactory.Parameter( - // "optionalParam", - // InputPrimitiveType.String, - // location: RequestLocation.None, - // kind: InputOperationParameterKind.Client), - // InputFactory.Parameter( - // KnownParameters.Endpoint.Name, - // InputPrimitiveType.String, - // location: RequestLocation.None, - // defaultValue: InputFactory.Constant.String("someValue"), - // kind: InputOperationParameterKind.Client, - // isEndpoint: true) - // }); - // // scenario where endpoint is required - // yield return new TestCaseData(new List - // { - // InputFactory.Parameter( - // KnownParameters.Endpoint.Name, - // InputPrimitiveType.String, - // location: RequestLocation.None, - // kind: InputOperationParameterKind.Client, - // isRequired: true, - // isEndpoint: true), - // InputFactory.Parameter( - // "optionalParam", - // InputPrimitiveType.String, - // location: RequestLocation.None, - // kind: InputOperationParameterKind.Client) - // }); - // } - // } - - // private static IEnumerable EndpointParamInitializationValueTestCases() - // { - // // string primitive type - // yield return new TestCaseData( - // InputFactory.Parameter( - // "param", - // InputPrimitiveType.String, - // location: RequestLocation.None, - // kind: InputOperationParameterKind.Client, - // isEndpoint: true, - // defaultValue: InputFactory.Constant.String("mockValue")), - // New.Instance(KnownParameters.Endpoint.Type, Literal("mockvalue"))); - // } - - // private record TestClientPipelineApi : ClientPipelineApi - // { - // private static ClientPipelineApi? _instance; - // internal static ClientPipelineApi Instance => _instance ??= new TestClientPipelineApi(Empty); - - // public TestClientPipelineApi(ValueExpression original) : base(typeof(string), original) - // { - // } - - // public override CSharpType ClientPipelineType => typeof(string); - - // public override CSharpType ClientPipelineOptionsType => typeof(string); - - // public override CSharpType PipelinePolicyType => typeof(string); - - // public override CSharpType? KeyCredentialType => null; - - // public override CSharpType TokenCredentialType => typeof(TestTokenCredential); - - // public override ValueExpression Create(ValueExpression options, ValueExpression perRetryPolicies) - // => Original.Invoke("GetFakeCreate", [options, perRetryPolicies]); - - // public override ValueExpression CreateMessage(HttpRequestOptionsApi requestOptions, ValueExpression responseClassifier) - // => Original.Invoke("GetFakeCreateMessage", [requestOptions, responseClassifier]); - - // public override ClientPipelineApi FromExpression(ValueExpression expression) - // => new TestClientPipelineApi(expression); - - // public override ValueExpression ConsumeKeyAuth(ValueExpression credential, ValueExpression headerName, ValueExpression? keyPrefix = null) - // => throw new InvalidOperationException("ApiKey is not supported in this test"); - - // public override ValueExpression ConsumeOAuth2Auth(ValueExpression credential, ValueExpression scopes) - // => Original.Invoke("GetFakeTokenAuthorizationPolicy", [credential, scopes]); - - // public override ClientPipelineApi ToExpression() => this; - - // public override MethodBodyStatement[] ProcessMessage(HttpMessageApi message, HttpRequestOptionsApi options) - // => [Original.Invoke("GetFakeProcessMessage", [message, options]).Terminate()]; - - // public override MethodBodyStatement[] ProcessMessageAsync(HttpMessageApi message, HttpRequestOptionsApi options) - // => [Original.Invoke("GetFakeProcessMessageAsync", [message, options]).Terminate()]; - // } - - // internal class TestTokenCredential { } - //} -} From 647fc579e7628eb099a025df73563776b11a0b75 Mon Sep 17 00:00:00 2001 From: Dapeng Zhang Date: Wed, 4 Dec 2024 16:04:44 +0800 Subject: [PATCH 11/22] recombine those two classes --- .../ClientProviderAuthTests.cs | 605 ------------------ .../ClientProviders/ClientProviderTests.cs | 574 ++++++++++++++++- 2 files changed, 568 insertions(+), 611 deletions(-) delete mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderAuthTests.cs diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderAuthTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderAuthTests.cs deleted file mode 100644 index 27ca430fe9..0000000000 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderAuthTests.cs +++ /dev/null @@ -1,605 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.ClientModel; -using System.Collections.Generic; -using System.Linq; -using Microsoft.Generator.CSharp.ClientModel.Providers; -using Microsoft.Generator.CSharp.Expressions; -using Microsoft.Generator.CSharp.Input; -using Microsoft.Generator.CSharp.Primitives; -using Microsoft.Generator.CSharp.Providers; -using Microsoft.Generator.CSharp.Snippets; -using Microsoft.Generator.CSharp.Statements; -using Microsoft.Generator.CSharp.Tests.Common; -using NUnit.Framework; -using static Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders.ClientProviderTestsUtils; -using static Microsoft.Generator.CSharp.Snippets.Snippet; - -namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders -{ - public class ClientProviderAuthTests - { - private const string SubClientsCategory = "WithSubClients"; - private const string KeyAuthCategory = "KeyAuth"; - private const string OAuth2Category = "OAuth2"; - private const string TestClientName = "TestClient"; - private static readonly InputClient _animalClient = new("animal", "AnimalClient description", [], [], TestClientName); - private static readonly InputClient _dogClient = new("dog", "DogClient description", [], [], _animalClient.Name); - private static readonly InputClient _huskyClient = new("husky", "HuskyClient description", [], [], _dogClient.Name); - - private bool _containsSubClients; - private bool _hasKeyAuth; - private bool _hasOAuth2; - private bool _hasAuth; - - [SetUp] - public void SetUp() - { - var categories = TestContext.CurrentContext.Test?.Properties["Category"]; - _containsSubClients = categories?.Contains(SubClientsCategory) ?? false; - _hasKeyAuth = categories?.Contains(KeyAuthCategory) ?? false; - _hasOAuth2 = categories?.Contains(OAuth2Category) ?? false; - _hasAuth = _hasKeyAuth || _hasOAuth2; - - Func>? clients = _containsSubClients ? - () => [_animalClient, _dogClient, _huskyClient] : - null; - Func? apiKeyAuth = _hasKeyAuth ? () => new InputApiKeyAuth("mock", null) : null; - Func? oauth2Auth = _hasOAuth2 ? () => new InputOAuth2Auth(["mock"]) : null; - MockHelpers.LoadMockPlugin( - apiKeyAuth: apiKeyAuth, - oauth2Auth: oauth2Auth, - clients: clients, - clientPipelineApi: TestClientPipelineApi.Instance); - } - - [TestCaseSource(nameof(BuildFieldsTestCases), Category = KeyAuthCategory)] - public void TestBuildFields_WithAuth(List inputParameters) - { - var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - - if (_hasKeyAuth) - { - // key auth should have the following fields: AuthorizationHeader, _keyCredential - AssertHasFields(clientProvider, new List - { - new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string)), "AuthorizationHeader"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(ApiKeyCredential)), "_keyCredential") - }); - } - if (_hasOAuth2) - { - // oauth2 auth should have the following fields: AuthorizationScopes, _tokenCredential - AssertHasFields(clientProvider, new List - { - new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), - }); - } - } - - [TestCaseSource(nameof(BuildFieldsTestCases))] - public void TestBuildFields_NoAuth(List inputParameters) - { - var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - - // fields here should not have anything related with auth - bool authFieldFound = false; - foreach (var field in clientProvider.Fields) - { - if (field.Name.EndsWith("Credential") || field.Name.Contains("Authorization")) - { - authFieldFound = true; - } - } - - Assert.IsFalse(authFieldFound); - } - - // validates the credential fields are built correctly when a client has sub-clients - [TestCaseSource(nameof(SubClientFieldsTestCases), Category = SubClientsCategory)] - public void TestBuildFields_WithSubClients_NoAuth(InputClient client) - { - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - - // fields here should not have anything related with auth - bool authFieldFound = false; - foreach (var field in clientProvider.Fields) - { - if (field.Name.EndsWith("Credential") || field.Name.Contains("Authorization")) - { - authFieldFound = true; - } - } - - Assert.IsFalse(authFieldFound); - } - - // validates the credential fields are built correctly when a client has sub-clients - [TestCaseSource(nameof(SubClientFieldsTestCases), Category = $"{SubClientsCategory},{KeyAuthCategory}")] - [TestCaseSource(nameof(SubClientFieldsTestCases), Category = $"{SubClientsCategory},{OAuth2Category}")] - [TestCaseSource(nameof(SubClientFieldsTestCases), Category = $"{SubClientsCategory},{KeyAuthCategory},{OAuth2Category}")] - public void TestBuildFields_WithSubClients_WithAuth(InputClient client) - { - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - - if (_hasKeyAuth) - { - // key auth should have the following fields: AuthorizationHeader, _keyCredential - AssertHasFields(clientProvider, new List - { - new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string)), "AuthorizationHeader"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(ApiKeyCredential)), "_keyCredential") - }); - } - if (_hasOAuth2) - { - // oauth2 auth should have the following fields: AuthorizationScopes, _tokenCredential - AssertHasFields(clientProvider, new List - { - new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), - }); - } - } - - [TestCaseSource(nameof(BuildConstructorsTestCases))] - [TestCaseSource(nameof(BuildConstructorsTestCases), Category = KeyAuthCategory)] - [TestCaseSource(nameof(BuildConstructorsTestCases), Category = OAuth2Category)] - [TestCaseSource(nameof(BuildConstructorsTestCases), Category = $"{KeyAuthCategory},{OAuth2Category}")] - public void TestBuildConstructors_PrimaryConstructor(List inputParameters) - { - var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - - var constructors = clientProvider.Constructors; - - var primaryPublicConstructors = constructors.Where( - c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public).ToArray(); - - // for no auth or one auth case, this should be 1 - // for both auth case, this should be 2 - var expectedPrimaryCtorCount = _hasKeyAuth && _hasOAuth2 ? 2 : 1; - Assert.AreEqual(expectedPrimaryCtorCount, primaryPublicConstructors.Length); - - foreach (var primaryCtor in primaryPublicConstructors) - { - ValidatePrimaryConstructor(primaryCtor, inputParameters); - } - } - - [TestCaseSource(nameof(BuildConstructorsTestCases))] - [TestCaseSource(nameof(BuildConstructorsTestCases), Category = KeyAuthCategory)] - [TestCaseSource(nameof(BuildConstructorsTestCases), Category = OAuth2Category)] - [TestCaseSource(nameof(BuildConstructorsTestCases), Category = $"{KeyAuthCategory},{OAuth2Category}")] - public void TestBuildConstructors_SecondaryConstructor(List inputParameters) - { - var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - - var constructors = clientProvider.Constructors; - - var primaryPublicConstructors = constructors.Where( - c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public).ToArray(); - var secondaryPublicConstructors = constructors.Where( - c => c.Signature?.Initializer != null && c.Signature?.Modifiers == MethodSignatureModifiers.Public).ToArray(); - - // for no auth or one auth case, this should be 1 - // for both auth case, this should be 2 - var expectedSecondaryCtorCount = _hasKeyAuth && _hasOAuth2 ? 2 : 1; - Assert.AreEqual(expectedSecondaryCtorCount, secondaryPublicConstructors.Length); - foreach (var secondaryPublicConstructor in secondaryPublicConstructors) - { - ValidateSecondaryConstructor(primaryPublicConstructors, secondaryPublicConstructor, inputParameters); - } - } - - [TestCase] - public void TestBuildConstructors_ForSubClient_NoAuth() - { - var clientProvider = new ClientProvider(_animalClient); - - Assert.IsNotNull(clientProvider); - - var constructors = clientProvider.Constructors; - - Assert.AreEqual(2, constructors.Count); - var internalConstructor = constructors.FirstOrDefault( - c => c.Signature?.Modifiers == MethodSignatureModifiers.Internal); - Assert.IsNotNull(internalConstructor); - // in the no auth case, the ctor no longer has the credentail parameter therefore here we expect 2 parameters. - var ctorParams = internalConstructor?.Signature?.Parameters; - Assert.AreEqual(2, ctorParams?.Count); - - var mockingConstructor = constructors.FirstOrDefault( - c => c.Signature?.Modifiers == MethodSignatureModifiers.Protected); - Assert.IsNotNull(mockingConstructor); - } - - [TestCase(Category = KeyAuthCategory)] - [TestCase(Category = OAuth2Category)] - public void TestBuildConstructors_ForSubClient_KeyAuthOrOAuth2Auth() - { - var clientProvider = new ClientProvider(_animalClient); - - Assert.IsNotNull(clientProvider); - - var constructors = clientProvider.Constructors; - - Assert.AreEqual(2, constructors.Count); - var internalConstructor = constructors.FirstOrDefault( - c => c.Signature?.Modifiers == MethodSignatureModifiers.Internal); - Assert.IsNotNull(internalConstructor); - // when there is only one approach of auth, we have 3 parameters in the ctor. - var ctorParams = internalConstructor?.Signature?.Parameters; - Assert.AreEqual(3, ctorParams?.Count); - - var mockingConstructor = constructors.FirstOrDefault( - c => c.Signature?.Modifiers == MethodSignatureModifiers.Protected); - Assert.IsNotNull(mockingConstructor); - } - - [TestCase(Category = $"{KeyAuthCategory},{OAuth2Category}")] - public void TestBuildConstructors_ForSubClient_BothAuth() - { - var clientProvider = new ClientProvider(_animalClient); - - Assert.IsNotNull(clientProvider); - - var constructors = clientProvider.Constructors; - - Assert.AreEqual(2, constructors.Count); - var internalConstructor = constructors.FirstOrDefault( - c => c.Signature?.Modifiers == MethodSignatureModifiers.Internal); - Assert.IsNotNull(internalConstructor); - // when we have both auths, we have 4 parameters in the ctor, because now we should have two credential parameters - var ctorParams = internalConstructor?.Signature?.Parameters; - Assert.AreEqual(4, ctorParams?.Count); - - var mockingConstructor = constructors.FirstOrDefault( - c => c.Signature?.Modifiers == MethodSignatureModifiers.Protected); - Assert.IsNotNull(mockingConstructor); - } - - private void ValidatePrimaryConstructor( - ConstructorProvider primaryPublicConstructor, - List inputParameters) - { - var primaryCtorParams = primaryPublicConstructor?.Signature?.Parameters; - // in no auth case, the ctor only have two parameters: endpoint and options - // in other cases, the ctor should have three parameters: endpoint, credential, options - // specifically, in both auth cases, we should have two ctors corresponding to each credential type as the second parameter - var expectedPrimaryCtorParamCount = !_hasKeyAuth && !_hasOAuth2 ? 2 : 3; - - Assert.AreEqual(expectedPrimaryCtorParamCount, primaryCtorParams?.Count); - - // the first should be endpoint - var endpointParam = primaryCtorParams?[0]; - Assert.AreEqual(KnownParameters.Endpoint.Name, endpointParam?.Name); - - if (endpointParam?.DefaultValue != null) - { - var inputEndpointParam = inputParameters.FirstOrDefault(p => p.IsEndpoint); - var parsedValue = inputEndpointParam?.DefaultValue?.Value; - Assert.AreEqual(Literal(parsedValue), endpointParam?.InitializationValue); - } - - // the last parameter should be the options - var optionsParam = primaryCtorParams?[^1]; - Assert.AreEqual("options", optionsParam?.Name); - - if (_hasAuth) - { - // when there is any auth, the second should be auth parameter - var authParam = primaryCtorParams?[1]; - Assert.IsNotNull(authParam); - if (authParam?.Name == "keyCredential") - { - Assert.AreEqual(new CSharpType(typeof(ApiKeyCredential)), authParam?.Type); - } - else if (authParam?.Name == "tokenCredential") - { - Assert.AreEqual(new CSharpType(typeof(TestTokenCredential)), authParam?.Type); - } - else - { - Assert.Fail("Unexpected auth parameter"); - } - } - - // validate the body of the primary ctor - var primaryCtorBody = primaryPublicConstructor?.BodyStatements; - Assert.IsNotNull(primaryCtorBody); - } - - private void ValidateSecondaryConstructor( - IReadOnlyList primaryConstructors, - ConstructorProvider secondaryPublicConstructor, - List inputParameters) - { - var ctorParams = secondaryPublicConstructor.Signature?.Parameters; - - // secondary ctor should consist of all required parameters + auth parameter (when present) - var requiredParams = inputParameters.Where(p => p.IsRequired).ToList(); - var authParameterCount = _hasAuth ? 1 : 0; - Assert.AreEqual(requiredParams.Count + authParameterCount, ctorParams?.Count); - var endpointParam = ctorParams?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); - - if (requiredParams.Count == 0) - { - // auth should be the only parameter if endpoint is optional when there is auth - if (_hasAuth) - { - Assert.IsTrue(ctorParams?[0].Name.EndsWith("Credential")); - } - else - { - // when there is no auth, the ctor should not have parameters - Assert.AreEqual(0, ctorParams?.Count); - } - } - else - { - // otherwise, it should only consist of the auth parameter - Assert.AreEqual(KnownParameters.Endpoint.Name, ctorParams?[0].Name); - if (_hasAuth) - { - Assert.IsTrue(ctorParams?[1].Name.EndsWith("Credential")); - } - } - - Assert.AreEqual(MethodBodyStatement.Empty, secondaryPublicConstructor?.BodyStatements); - - // validate the initializer - var initializer = secondaryPublicConstructor?.Signature?.Initializer; - Assert.NotNull(initializer); - Assert.IsTrue(primaryConstructors.Any(pc => pc.Signature.Parameters.Count == initializer?.Arguments.Count)); - } - - [TestCaseSource(nameof(EndpointParamInitializationValueTestCases))] - public void EndpointInitializationValue(InputParameter endpointParameter, ValueExpression? expectedValue) - { - var client = InputFactory.Client(TestClientName, parameters: [endpointParameter]); - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - // find the endpoint parameter from the primary constructor - var primaryConstructor = clientProvider.Constructors.FirstOrDefault( - c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); - var endpoint = primaryConstructor?.Signature?.Parameters?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); - - Assert.IsNotNull(endpoint); - Assert.AreEqual(expectedValue?.GetType(), endpoint?.InitializationValue?.GetType()); - if (expectedValue != null) - { - Assert.IsTrue(endpoint?.InitializationValue is NewInstanceExpression); - } - } - - [TestCaseSource(nameof(SubClientFactoryMethodTestCases), Category = SubClientsCategory)] - public void TestSubClientAccessorFactoryMethods(InputClient client, bool hasSubClients) - { - var clientProvider = new ClientProvider(client); - Assert.IsNotNull(clientProvider); - - var methods = clientProvider.Methods; - List subClientAccessorFactoryMethods = []; - foreach (var method in methods) - { - var methodSignature = method.Signature; - if (methodSignature != null && - methodSignature.Name.StartsWith("Get") && - methodSignature.Modifiers.HasFlag(MethodSignatureModifiers.Public | MethodSignatureModifiers.Virtual)) - { - subClientAccessorFactoryMethods.Add(method); - } - } - - if (hasSubClients) - { - Assert.AreEqual(1, subClientAccessorFactoryMethods.Count); - var factoryMethod = subClientAccessorFactoryMethods[0]; - Assert.AreEqual(0, factoryMethod.Signature?.Parameters.Count); - - // method body should not be empty - Assert.AreNotEqual(MethodBodyStatement.Empty, factoryMethod.BodyStatements); - } - else - { - Assert.AreEqual(0, subClientAccessorFactoryMethods.Count); - } - } - - public static IEnumerable BuildFieldsTestCases - { - get - { - yield return new TestCaseData(new List - { - InputFactory.Parameter( - "optionalParam", - InputPrimitiveType.String, - location: RequestLocation.None, - kind: InputOperationParameterKind.Client), - InputFactory.Parameter( - KnownParameters.Endpoint.Name, - InputPrimitiveType.String, - location:RequestLocation.None, - kind: InputOperationParameterKind.Client, - isEndpoint: true) - }); - yield return new TestCaseData(new List - { - // have to explicitly set isRequired because we now call CreateParameter in buildFields - InputFactory.Parameter( - "optionalNullableParam", - InputPrimitiveType.String, - location: RequestLocation.None, - defaultValue: InputFactory.Constant.String("someValue"), - kind: InputOperationParameterKind.Client, - isRequired: false), - InputFactory.Parameter( - "requiredParam2", - InputPrimitiveType.String, - location: RequestLocation.None, - defaultValue: InputFactory.Constant.String("someValue"), - kind: InputOperationParameterKind.Client, - isRequired: true), - InputFactory.Parameter( - "requiredParam3", - InputPrimitiveType.Int64, - location: RequestLocation.None, - defaultValue: InputFactory.Constant.Int64(2), - kind: InputOperationParameterKind.Client, - isRequired: true), - InputFactory.Parameter( - KnownParameters.Endpoint.Name, - InputPrimitiveType.String, - location: RequestLocation.None, - defaultValue: null, - kind: InputOperationParameterKind.Client, - isEndpoint: true) - }); - } - } - - public static IEnumerable SubClientFieldsTestCases - { - get - { - yield return new TestCaseData(InputFactory.Client(TestClientName)); - yield return new TestCaseData(_animalClient); - yield return new TestCaseData(_dogClient); - yield return new TestCaseData(_huskyClient); - } - } - - public static IEnumerable SubClientFactoryMethodTestCases - { - get - { - yield return new TestCaseData(InputFactory.Client(TestClientName), true); - yield return new TestCaseData(_animalClient, true); - yield return new TestCaseData(_dogClient, true); - yield return new TestCaseData(_huskyClient, false); - } - } - - public static IEnumerable BuildConstructorsTestCases - { - get - { - yield return new TestCaseData(new List - { - InputFactory.Parameter( - "optionalParam", - InputPrimitiveType.String, - location: RequestLocation.None, - kind: InputOperationParameterKind.Client), - InputFactory.Parameter( - KnownParameters.Endpoint.Name, - InputPrimitiveType.String, - location: RequestLocation.None, - defaultValue: InputFactory.Constant.String("someValue"), - kind: InputOperationParameterKind.Client, - isEndpoint: true) - }); - // scenario where endpoint is required - yield return new TestCaseData(new List - { - InputFactory.Parameter( - KnownParameters.Endpoint.Name, - InputPrimitiveType.String, - location: RequestLocation.None, - kind: InputOperationParameterKind.Client, - isRequired: true, - isEndpoint: true), - InputFactory.Parameter( - "optionalParam", - InputPrimitiveType.String, - location: RequestLocation.None, - kind: InputOperationParameterKind.Client) - }); - } - } - - private static IEnumerable EndpointParamInitializationValueTestCases - { - get - { - // string primitive type - yield return new TestCaseData( - InputFactory.Parameter( - "param", - InputPrimitiveType.String, - location: RequestLocation.None, - kind: InputOperationParameterKind.Client, - isEndpoint: true, - defaultValue: InputFactory.Constant.String("mockValue")), - New.Instance(KnownParameters.Endpoint.Type, Literal("mockvalue"))); - } - } - - // TODO -- this is temporary here before System.ClientModel officially supports OAuth2 auth - private record TestClientPipelineApi : ClientPipelineApi - { - private static ClientPipelineApi? _instance; - internal static ClientPipelineApi Instance => _instance ??= new TestClientPipelineApi(Empty); - - public TestClientPipelineApi(ValueExpression original) : base(typeof(string), original) - { - } - - public override CSharpType ClientPipelineType => typeof(string); - - public override CSharpType ClientPipelineOptionsType => typeof(string); - - public override CSharpType PipelinePolicyType => typeof(string); - - public override CSharpType KeyCredentialType => typeof(ApiKeyCredential); - - public override CSharpType TokenCredentialType => typeof(TestTokenCredential); - - public override ValueExpression Create(ValueExpression options, ValueExpression perRetryPolicies) - => Original.Invoke("GetFakeCreate", [options, perRetryPolicies]); - - public override ValueExpression CreateMessage(HttpRequestOptionsApi requestOptions, ValueExpression responseClassifier) - => Original.Invoke("GetFakeCreateMessage", [requestOptions, responseClassifier]); - - public override ClientPipelineApi FromExpression(ValueExpression expression) - => new TestClientPipelineApi(expression); - - public override ValueExpression ConsumeKeyAuth(ValueExpression credential, ValueExpression headerName, ValueExpression? keyPrefix = null) - => Original.Invoke("GetFakeApiKeyAuthorizationPolicy", keyPrefix != null ? [credential, headerName, keyPrefix] : [credential, headerName]); - - public override ValueExpression ConsumeOAuth2Auth(ValueExpression credential, ValueExpression scopes) - => Original.Invoke("GetFakeTokenAuthorizationPolicy", [credential, scopes]); - - public override ClientPipelineApi ToExpression() => this; - - public override MethodBodyStatement[] ProcessMessage(HttpMessageApi message, HttpRequestOptionsApi options) - => [Original.Invoke("GetFakeProcessMessage", [message, options]).Terminate()]; - - public override MethodBodyStatement[] ProcessMessageAsync(HttpMessageApi message, HttpRequestOptionsApi options) - => [Original.Invoke("GetFakeProcessMessageAsync", [message, options]).Terminate()]; - } - - internal class TestTokenCredential { } - } -} diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs index 4f22943e05..e7194bf359 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Generator.CSharp.ClientModel.Providers; +using Microsoft.Generator.CSharp.Expressions; using Microsoft.Generator.CSharp.Input; using Microsoft.Generator.CSharp.Primitives; using Microsoft.Generator.CSharp.Providers; @@ -15,12 +16,15 @@ using Microsoft.Generator.CSharp.Tests.Common; using NUnit.Framework; using static Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders.ClientProviderTestsUtils; +using static Microsoft.Generator.CSharp.Snippets.Snippet; namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders { public class ClientProviderTests { private const string SubClientsCategory = "WithSubClients"; + private const string KeyAuthCategory = "WithKeyAuth"; + private const string OAuth2Category = "WithOAuth2"; private const string TestClientName = "TestClient"; private static readonly InputClient _animalClient = new("animal", "AnimalClient description", [], [], TestClientName); private static readonly InputClient _dogClient = new("dog", "DogClient description", [], [], _animalClient.Name); @@ -33,20 +37,402 @@ public class ClientProviderTests InputFactory.Property("p1", InputPrimitiveType.String, isRequired: true), ]); + private bool _containsSubClients; + private bool _hasKeyAuth; + private bool _hasOAuth2; + private bool _hasAuth; + [SetUp] public void SetUp() { var categories = TestContext.CurrentContext.Test?.Properties["Category"]; - bool containsSubClients = categories?.Contains(SubClientsCategory) ?? false; - if (containsSubClients) + _containsSubClients = categories?.Contains(SubClientsCategory) ?? false; + _hasKeyAuth = categories?.Contains(KeyAuthCategory) ?? false; + _hasOAuth2 = categories?.Contains(OAuth2Category) ?? false; + _hasAuth = _hasKeyAuth || _hasOAuth2; + + Func>? clients = _containsSubClients ? + () => [_animalClient, _dogClient, _huskyClient] : + null; + Func? apiKeyAuth = _hasKeyAuth ? () => new InputApiKeyAuth("mock", null) : null; + Func? oauth2Auth = _hasOAuth2 ? () => new InputOAuth2Auth(["mock"]) : null; + MockHelpers.LoadMockPlugin( + apiKeyAuth: apiKeyAuth, + oauth2Auth: oauth2Auth, + clients: clients, + clientPipelineApi: _hasAuth ? TestClientPipelineApi.Instance : null); + } + + [TestCaseSource(nameof(BuildAuthFieldsTestCases), Category = KeyAuthCategory)] + [TestCaseSource(nameof(BuildAuthFieldsTestCases), Category = OAuth2Category)] + [TestCaseSource(nameof(BuildAuthFieldsTestCases), Category = $"{KeyAuthCategory},{OAuth2Category}")] + public void TestBuildAuthFields_WithAuth(List inputParameters) + { + var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + if (_hasKeyAuth) + { + // key auth should have the following fields: AuthorizationHeader, _keyCredential + AssertHasFields(clientProvider, new List + { + new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string)), "AuthorizationHeader"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(ApiKeyCredential)), "_keyCredential") + }); + } + if (_hasOAuth2) + { + // oauth2 auth should have the following fields: AuthorizationScopes, _tokenCredential + AssertHasFields(clientProvider, new List + { + new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), + }); + } + } + + [TestCaseSource(nameof(BuildAuthFieldsTestCases))] + public void TestBuildAuthFields_NoAuth(List inputParameters) + { + var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + // fields here should not have anything related with auth + bool authFieldFound = false; + foreach (var field in clientProvider.Fields) + { + if (field.Name.EndsWith("Credential") || field.Name.Contains("Authorization")) + { + authFieldFound = true; + } + } + + Assert.IsFalse(authFieldFound); + } + + // validates the credential fields are built correctly when a client has sub-clients + [TestCaseSource(nameof(SubClientAuthFieldsTestCases), Category = SubClientsCategory)] + public void TestBuildFields_WithSubClients_NoAuth(InputClient client) + { + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + // fields here should not have anything related with auth + bool authFieldFound = false; + foreach (var field in clientProvider.Fields) + { + if (field.Name.EndsWith("Credential") || field.Name.Contains("Authorization")) + { + authFieldFound = true; + } + } + + Assert.IsFalse(authFieldFound); + } + + // validates the credential fields are built correctly when a client has sub-clients + [TestCaseSource(nameof(SubClientAuthFieldsTestCases), Category = $"{SubClientsCategory},{KeyAuthCategory}")] + [TestCaseSource(nameof(SubClientAuthFieldsTestCases), Category = $"{SubClientsCategory},{OAuth2Category}")] + [TestCaseSource(nameof(SubClientAuthFieldsTestCases), Category = $"{SubClientsCategory},{KeyAuthCategory},{OAuth2Category}")] + public void TestBuildFields_WithSubClients_WithAuth(InputClient client) + { + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + if (_hasKeyAuth) + { + // key auth should have the following fields: AuthorizationHeader, _keyCredential + AssertHasFields(clientProvider, new List + { + new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string)), "AuthorizationHeader"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(ApiKeyCredential)), "_keyCredential") + }); + } + if (_hasOAuth2) + { + // oauth2 auth should have the following fields: AuthorizationScopes, _tokenCredential + AssertHasFields(clientProvider, new List + { + new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), + }); + } + } + + [TestCaseSource(nameof(BuildConstructorsTestCases))] + [TestCaseSource(nameof(BuildConstructorsTestCases), Category = KeyAuthCategory)] + [TestCaseSource(nameof(BuildConstructorsTestCases), Category = OAuth2Category)] + [TestCaseSource(nameof(BuildConstructorsTestCases), Category = $"{KeyAuthCategory},{OAuth2Category}")] + public void TestBuildConstructors_PrimaryConstructor(List inputParameters) + { + var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + var constructors = clientProvider.Constructors; + + var primaryPublicConstructors = constructors.Where( + c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public).ToArray(); + + // for no auth or one auth case, this should be 1 + // for both auth case, this should be 2 + var expectedPrimaryCtorCount = _hasKeyAuth && _hasOAuth2 ? 2 : 1; + Assert.AreEqual(expectedPrimaryCtorCount, primaryPublicConstructors.Length); + + foreach (var primaryCtor in primaryPublicConstructors) + { + ValidatePrimaryConstructor(primaryCtor, inputParameters); + } + } + + [TestCaseSource(nameof(BuildConstructorsTestCases))] + [TestCaseSource(nameof(BuildConstructorsTestCases), Category = KeyAuthCategory)] + [TestCaseSource(nameof(BuildConstructorsTestCases), Category = OAuth2Category)] + [TestCaseSource(nameof(BuildConstructorsTestCases), Category = $"{KeyAuthCategory},{OAuth2Category}")] + public void TestBuildConstructors_SecondaryConstructor(List inputParameters) + { + var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + var constructors = clientProvider.Constructors; + + var primaryPublicConstructors = constructors.Where( + c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public).ToArray(); + var secondaryPublicConstructors = constructors.Where( + c => c.Signature?.Initializer != null && c.Signature?.Modifiers == MethodSignatureModifiers.Public).ToArray(); + + // for no auth or one auth case, this should be 1 + // for both auth case, this should be 2 + var expectedSecondaryCtorCount = _hasKeyAuth && _hasOAuth2 ? 2 : 1; + Assert.AreEqual(expectedSecondaryCtorCount, secondaryPublicConstructors.Length); + foreach (var secondaryPublicConstructor in secondaryPublicConstructors) + { + ValidateSecondaryConstructor(primaryPublicConstructors, secondaryPublicConstructor, inputParameters); + } + } + + [TestCase] + public void TestBuildConstructors_ForSubClient_NoAuth() + { + var clientProvider = new ClientProvider(_animalClient); + + Assert.IsNotNull(clientProvider); + + var constructors = clientProvider.Constructors; + + Assert.AreEqual(2, constructors.Count); + var internalConstructor = constructors.FirstOrDefault( + c => c.Signature?.Modifiers == MethodSignatureModifiers.Internal); + Assert.IsNotNull(internalConstructor); + // in the no auth case, the ctor no longer has the credentail parameter therefore here we expect 2 parameters. + var ctorParams = internalConstructor?.Signature?.Parameters; + Assert.AreEqual(2, ctorParams?.Count); + + var mockingConstructor = constructors.FirstOrDefault( + c => c.Signature?.Modifiers == MethodSignatureModifiers.Protected); + Assert.IsNotNull(mockingConstructor); + } + + [TestCase(Category = KeyAuthCategory)] + [TestCase(Category = OAuth2Category)] + public void TestBuildConstructors_ForSubClient_KeyAuthOrOAuth2Auth() + { + var clientProvider = new ClientProvider(_animalClient); + + Assert.IsNotNull(clientProvider); + + var constructors = clientProvider.Constructors; + + Assert.AreEqual(2, constructors.Count); + var internalConstructor = constructors.FirstOrDefault( + c => c.Signature?.Modifiers == MethodSignatureModifiers.Internal); + Assert.IsNotNull(internalConstructor); + // when there is only one approach of auth, we have 3 parameters in the ctor. + var ctorParams = internalConstructor?.Signature?.Parameters; + Assert.AreEqual(3, ctorParams?.Count); + + var mockingConstructor = constructors.FirstOrDefault( + c => c.Signature?.Modifiers == MethodSignatureModifiers.Protected); + Assert.IsNotNull(mockingConstructor); + } + + [TestCase(Category = $"{KeyAuthCategory},{OAuth2Category}")] + public void TestBuildConstructors_ForSubClient_BothAuth() + { + var clientProvider = new ClientProvider(_animalClient); + + Assert.IsNotNull(clientProvider); + + var constructors = clientProvider.Constructors; + + Assert.AreEqual(2, constructors.Count); + var internalConstructor = constructors.FirstOrDefault( + c => c.Signature?.Modifiers == MethodSignatureModifiers.Internal); + Assert.IsNotNull(internalConstructor); + // when we have both auths, we have 4 parameters in the ctor, because now we should have two credential parameters + var ctorParams = internalConstructor?.Signature?.Parameters; + Assert.AreEqual(4, ctorParams?.Count); + + var mockingConstructor = constructors.FirstOrDefault( + c => c.Signature?.Modifiers == MethodSignatureModifiers.Protected); + Assert.IsNotNull(mockingConstructor); + } + + private void ValidatePrimaryConstructor( + ConstructorProvider primaryPublicConstructor, + List inputParameters) + { + var primaryCtorParams = primaryPublicConstructor?.Signature?.Parameters; + // in no auth case, the ctor only have two parameters: endpoint and options + // in other cases, the ctor should have three parameters: endpoint, credential, options + // specifically, in both auth cases, we should have two ctors corresponding to each credential type as the second parameter + var expectedPrimaryCtorParamCount = !_hasKeyAuth && !_hasOAuth2 ? 2 : 3; + + Assert.AreEqual(expectedPrimaryCtorParamCount, primaryCtorParams?.Count); + + // the first should be endpoint + var endpointParam = primaryCtorParams?[0]; + Assert.AreEqual(KnownParameters.Endpoint.Name, endpointParam?.Name); + + if (endpointParam?.DefaultValue != null) + { + var inputEndpointParam = inputParameters.FirstOrDefault(p => p.IsEndpoint); + var parsedValue = inputEndpointParam?.DefaultValue?.Value; + Assert.AreEqual(Literal(parsedValue), endpointParam?.InitializationValue); + } + + // the last parameter should be the options + var optionsParam = primaryCtorParams?[^1]; + Assert.AreEqual("options", optionsParam?.Name); + + if (_hasAuth) + { + // when there is any auth, the second should be auth parameter + var authParam = primaryCtorParams?[1]; + Assert.IsNotNull(authParam); + if (authParam?.Name == "keyCredential") + { + Assert.AreEqual(new CSharpType(typeof(ApiKeyCredential)), authParam?.Type); + } + else if (authParam?.Name == "tokenCredential") + { + Assert.AreEqual(new CSharpType(typeof(TestTokenCredential)), authParam?.Type); + } + else + { + Assert.Fail("Unexpected auth parameter"); + } + } + + // validate the body of the primary ctor + var primaryCtorBody = primaryPublicConstructor?.BodyStatements; + Assert.IsNotNull(primaryCtorBody); + } + + private void ValidateSecondaryConstructor( + IReadOnlyList primaryConstructors, + ConstructorProvider secondaryPublicConstructor, + List inputParameters) + { + var ctorParams = secondaryPublicConstructor.Signature?.Parameters; + + // secondary ctor should consist of all required parameters + auth parameter (when present) + var requiredParams = inputParameters.Where(p => p.IsRequired).ToList(); + var authParameterCount = _hasAuth ? 1 : 0; + Assert.AreEqual(requiredParams.Count + authParameterCount, ctorParams?.Count); + var endpointParam = ctorParams?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); + + if (requiredParams.Count == 0) + { + // auth should be the only parameter if endpoint is optional when there is auth + if (_hasAuth) + { + Assert.IsTrue(ctorParams?[0].Name.EndsWith("Credential")); + } + else + { + // when there is no auth, the ctor should not have parameters + Assert.AreEqual(0, ctorParams?.Count); + } + } + else + { + // otherwise, it should only consist of the auth parameter + Assert.AreEqual(KnownParameters.Endpoint.Name, ctorParams?[0].Name); + if (_hasAuth) + { + Assert.IsTrue(ctorParams?[1].Name.EndsWith("Credential")); + } + } + + Assert.AreEqual(MethodBodyStatement.Empty, secondaryPublicConstructor?.BodyStatements); + + // validate the initializer + var initializer = secondaryPublicConstructor?.Signature?.Initializer; + Assert.NotNull(initializer); + Assert.IsTrue(primaryConstructors.Any(pc => pc.Signature.Parameters.Count == initializer?.Arguments.Count)); + } + + [TestCaseSource(nameof(EndpointParamInitializationValueTestCases))] + public void EndpointInitializationValue(InputParameter endpointParameter, ValueExpression? expectedValue) + { + var client = InputFactory.Client(TestClientName, parameters: [endpointParameter]); + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + // find the endpoint parameter from the primary constructor + var primaryConstructor = clientProvider.Constructors.FirstOrDefault( + c => c.Signature?.Initializer == null && c.Signature?.Modifiers == MethodSignatureModifiers.Public); + var endpoint = primaryConstructor?.Signature?.Parameters?.FirstOrDefault(p => p.Name == KnownParameters.Endpoint.Name); + + Assert.IsNotNull(endpoint); + Assert.AreEqual(expectedValue?.GetType(), endpoint?.InitializationValue?.GetType()); + if (expectedValue != null) { - MockHelpers.LoadMockPlugin( - apiKeyAuth: () => new InputApiKeyAuth("mock", null), - clients: () => [_animalClient, _dogClient, _huskyClient]); + Assert.IsTrue(endpoint?.InitializationValue is NewInstanceExpression); + } + } + + [TestCaseSource(nameof(SubClientFactoryMethodTestCases), Category = SubClientsCategory)] + public void TestSubClientAccessorFactoryMethods(InputClient client, bool hasSubClients) + { + var clientProvider = new ClientProvider(client); + Assert.IsNotNull(clientProvider); + + var methods = clientProvider.Methods; + List subClientAccessorFactoryMethods = []; + foreach (var method in methods) + { + var methodSignature = method.Signature; + if (methodSignature != null && + methodSignature.Name.StartsWith("Get") && + methodSignature.Modifiers.HasFlag(MethodSignatureModifiers.Public | MethodSignatureModifiers.Virtual)) + { + subClientAccessorFactoryMethods.Add(method); + } + } + + if (hasSubClients) + { + Assert.AreEqual(1, subClientAccessorFactoryMethods.Count); + var factoryMethod = subClientAccessorFactoryMethods[0]; + Assert.AreEqual(0, factoryMethod.Signature?.Parameters.Count); + + // method body should not be empty + Assert.AreNotEqual(MethodBodyStatement.Empty, factoryMethod.BodyStatements); } else { - MockHelpers.LoadMockPlugin(apiKeyAuth: () => new InputApiKeyAuth("mock", null)); + Assert.AreEqual(0, subClientAccessorFactoryMethods.Count); } } @@ -367,6 +753,171 @@ protected override MethodProvider[] BuildMethods() protected override PropertyProvider[] BuildProperties() => []; } + public static IEnumerable SubClientFactoryMethodTestCases + { + get + { + yield return new TestCaseData(InputFactory.Client(TestClientName), true); + yield return new TestCaseData(_animalClient, true); + yield return new TestCaseData(_dogClient, true); + yield return new TestCaseData(_huskyClient, false); + } + } + + public static IEnumerable BuildConstructorsTestCases + { + get + { + yield return new TestCaseData(new List + { + InputFactory.Parameter( + "optionalParam", + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client), + InputFactory.Parameter( + KnownParameters.Endpoint.Name, + InputPrimitiveType.String, + location: RequestLocation.None, + defaultValue: InputFactory.Constant.String("someValue"), + kind: InputOperationParameterKind.Client, + isEndpoint: true) + }); + // scenario where endpoint is required + yield return new TestCaseData(new List + { + InputFactory.Parameter( + KnownParameters.Endpoint.Name, + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client, + isRequired: true, + isEndpoint: true), + InputFactory.Parameter( + "optionalParam", + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client) + }); + } + } + + private static IEnumerable EndpointParamInitializationValueTestCases + { + get + { + // string primitive type + yield return new TestCaseData( + InputFactory.Parameter( + "param", + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client, + isEndpoint: true, + defaultValue: InputFactory.Constant.String("mockValue")), + New.Instance(KnownParameters.Endpoint.Type, Literal("mockvalue"))); + } + } + + // TODO -- this is temporary here before System.ClientModel officially supports OAuth2 auth + private record TestClientPipelineApi : ClientPipelineApi + { + private static ClientPipelineApi? _instance; + internal static ClientPipelineApi Instance => _instance ??= new TestClientPipelineApi(Empty); + + public TestClientPipelineApi(ValueExpression original) : base(typeof(string), original) + { + } + + public override CSharpType ClientPipelineType => typeof(string); + + public override CSharpType ClientPipelineOptionsType => typeof(string); + + public override CSharpType PipelinePolicyType => typeof(string); + + public override CSharpType KeyCredentialType => typeof(ApiKeyCredential); + + public override CSharpType TokenCredentialType => typeof(TestTokenCredential); + + public override ValueExpression Create(ValueExpression options, ValueExpression perRetryPolicies) + => Original.Invoke("GetFakeCreate", [options, perRetryPolicies]); + + public override ValueExpression CreateMessage(HttpRequestOptionsApi requestOptions, ValueExpression responseClassifier) + => Original.Invoke("GetFakeCreateMessage", [requestOptions, responseClassifier]); + + public override ClientPipelineApi FromExpression(ValueExpression expression) + => new TestClientPipelineApi(expression); + + public override ValueExpression ConsumeKeyAuth(ValueExpression credential, ValueExpression headerName, ValueExpression? keyPrefix = null) + => Original.Invoke("GetFakeApiKeyAuthorizationPolicy", keyPrefix != null ? [credential, headerName, keyPrefix] : [credential, headerName]); + + public override ValueExpression ConsumeOAuth2Auth(ValueExpression credential, ValueExpression scopes) + => Original.Invoke("GetFakeTokenAuthorizationPolicy", [credential, scopes]); + + public override ClientPipelineApi ToExpression() => this; + + public override MethodBodyStatement[] ProcessMessage(HttpMessageApi message, HttpRequestOptionsApi options) + => [Original.Invoke("GetFakeProcessMessage", [message, options]).Terminate()]; + + public override MethodBodyStatement[] ProcessMessageAsync(HttpMessageApi message, HttpRequestOptionsApi options) + => [Original.Invoke("GetFakeProcessMessageAsync", [message, options]).Terminate()]; + } + + internal class TestTokenCredential { } + + public static IEnumerable BuildAuthFieldsTestCases + { + get + { + yield return new TestCaseData(new List + { + InputFactory.Parameter( + "optionalParam", + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client), + InputFactory.Parameter( + KnownParameters.Endpoint.Name, + InputPrimitiveType.String, + location:RequestLocation.None, + kind: InputOperationParameterKind.Client, + isEndpoint: true) + }); + yield return new TestCaseData(new List + { + // have to explicitly set isRequired because we now call CreateParameter in buildFields + InputFactory.Parameter( + "optionalNullableParam", + InputPrimitiveType.String, + location: RequestLocation.None, + defaultValue: InputFactory.Constant.String("someValue"), + kind: InputOperationParameterKind.Client, + isRequired: false), + InputFactory.Parameter( + "requiredParam2", + InputPrimitiveType.String, + location: RequestLocation.None, + defaultValue: InputFactory.Constant.String("someValue"), + kind: InputOperationParameterKind.Client, + isRequired: true), + InputFactory.Parameter( + "requiredParam3", + InputPrimitiveType.Int64, + location: RequestLocation.None, + defaultValue: InputFactory.Constant.Int64(2), + kind: InputOperationParameterKind.Client, + isRequired: true), + InputFactory.Parameter( + KnownParameters.Endpoint.Name, + InputPrimitiveType.String, + location: RequestLocation.None, + defaultValue: null, + kind: InputOperationParameterKind.Client, + isEndpoint: true) + }); + } + } + public static IEnumerable BuildFieldsTestCases { get @@ -433,6 +984,17 @@ public static IEnumerable BuildFieldsTestCases } } + public static IEnumerable SubClientAuthFieldsTestCases + { + get + { + yield return new TestCaseData(InputFactory.Client(TestClientName)); + yield return new TestCaseData(_animalClient); + yield return new TestCaseData(_dogClient); + yield return new TestCaseData(_huskyClient); + } + } + public static IEnumerable SubClientFieldsTestCases { get From e873771b1cfc265ad5c8ea61d225e6120cf41fba Mon Sep 17 00:00:00 2001 From: Dapeng Zhang Date: Wed, 4 Dec 2024 16:06:43 +0800 Subject: [PATCH 12/22] rearrange the test methods --- .../ClientProviders/ClientProviderTests.cs | 88 +++++++++---------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs index e7194bf359..0b69c18ba4 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs @@ -63,6 +63,37 @@ public void SetUp() clientPipelineApi: _hasAuth ? TestClientPipelineApi.Instance : null); } + [Test] + public void TestBuildProperties() + { + var client = InputFactory.Client(TestClientName); + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + // validate the properties + var properties = clientProvider.Properties; + Assert.IsTrue(properties.Count > 0); + // there should be a pipeline property + Assert.AreEqual(1, properties.Count); + + var pipelineProperty = properties.First(); + Assert.AreEqual(typeof(ClientPipeline), pipelineProperty.Type.FrameworkType); + Assert.AreEqual("Pipeline", pipelineProperty.Name); + Assert.AreEqual(MethodSignatureModifiers.Public, pipelineProperty.Modifiers); + } + + [TestCaseSource(nameof(BuildFieldsTestCases))] + public void TestBuildFields(List inputParameters, List expectedFields) + { + var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + AssertHasFields(clientProvider, expectedFields); + } + [TestCaseSource(nameof(BuildAuthFieldsTestCases), Category = KeyAuthCategory)] [TestCaseSource(nameof(BuildAuthFieldsTestCases), Category = OAuth2Category)] [TestCaseSource(nameof(BuildAuthFieldsTestCases), Category = $"{KeyAuthCategory},{OAuth2Category}")] @@ -114,9 +145,20 @@ public void TestBuildAuthFields_NoAuth(List inputParameters) Assert.IsFalse(authFieldFound); } + // validates the fields are built correctly when a client has sub-clients + [TestCaseSource(nameof(SubClientFieldsTestCases), Category = SubClientsCategory)] + public void TestBuildFields_WithSubClients(InputClient client, List expectedFields) + { + var clientProvider = new ClientProvider(client); + + Assert.IsNotNull(clientProvider); + + AssertHasFields(clientProvider, expectedFields); + } + // validates the credential fields are built correctly when a client has sub-clients [TestCaseSource(nameof(SubClientAuthFieldsTestCases), Category = SubClientsCategory)] - public void TestBuildFields_WithSubClients_NoAuth(InputClient client) + public void TestBuildAuthFields_WithSubClients_NoAuth(InputClient client) { var clientProvider = new ClientProvider(client); @@ -139,7 +181,7 @@ public void TestBuildFields_WithSubClients_NoAuth(InputClient client) [TestCaseSource(nameof(SubClientAuthFieldsTestCases), Category = $"{SubClientsCategory},{KeyAuthCategory}")] [TestCaseSource(nameof(SubClientAuthFieldsTestCases), Category = $"{SubClientsCategory},{OAuth2Category}")] [TestCaseSource(nameof(SubClientAuthFieldsTestCases), Category = $"{SubClientsCategory},{KeyAuthCategory},{OAuth2Category}")] - public void TestBuildFields_WithSubClients_WithAuth(InputClient client) + public void TestBuildAuthFields_WithSubClients_WithAuth(InputClient client) { var clientProvider = new ClientProvider(client); @@ -436,48 +478,6 @@ public void TestSubClientAccessorFactoryMethods(InputClient client, bool hasSubC } } - [Test] - public void TestBuildProperties() - { - var client = InputFactory.Client(TestClientName); - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - - // validate the properties - var properties = clientProvider.Properties; - Assert.IsTrue(properties.Count > 0); - // there should be a pipeline property - Assert.AreEqual(1, properties.Count); - - var pipelineProperty = properties.First(); - Assert.AreEqual(typeof(ClientPipeline), pipelineProperty.Type.FrameworkType); - Assert.AreEqual("Pipeline", pipelineProperty.Name); - Assert.AreEqual(MethodSignatureModifiers.Public, pipelineProperty.Modifiers); - } - - [TestCaseSource(nameof(BuildFieldsTestCases))] - public void TestBuildFields(List inputParameters, List expectedFields) - { - var client = InputFactory.Client(TestClientName, parameters: [.. inputParameters]); - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - - AssertHasFields(clientProvider, expectedFields); - } - - // validates the fields are built correctly when a client has sub-clients - [TestCaseSource(nameof(SubClientFieldsTestCases), Category = SubClientsCategory)] - public void TestBuildFields_WithSubClients(InputClient client, List expectedFields) - { - var clientProvider = new ClientProvider(client); - - Assert.IsNotNull(clientProvider); - - AssertHasFields(clientProvider, expectedFields); - } - [TestCase(true)] [TestCase(false)] public void TestGetClientOptions(bool isSubClient) From 2b0c9ca081b3ddd98e094bbf6e0cfcc73d600423 Mon Sep 17 00:00:00 2001 From: Dapeng Zhang Date: Wed, 4 Dec 2024 16:10:08 +0800 Subject: [PATCH 13/22] more rearrangement --- .../ClientProviders/ClientProviderTests.cs | 270 +++++++++--------- 1 file changed, 135 insertions(+), 135 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs index 0b69c18ba4..5b6a129d33 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs @@ -444,6 +444,29 @@ public void EndpointInitializationValue(InputParameter endpointParameter, ValueE } } + [TestCase(true)] + [TestCase(false)] + public void TestGetClientOptions(bool isSubClient) + { + string? parentClientName = null; + if (isSubClient) + { + parentClientName = "parent"; + } + + var client = InputFactory.Client(TestClientName, parent: parentClientName); + var clientProvider = new ClientProvider(client); + + if (isSubClient) + { + Assert.IsNull(clientProvider?.ClientOptions); + } + else + { + Assert.IsNotNull(clientProvider?.ClientOptions); + } + } + [TestCaseSource(nameof(SubClientFactoryMethodTestCases), Category = SubClientsCategory)] public void TestSubClientAccessorFactoryMethods(InputClient client, bool hasSubClients) { @@ -478,29 +501,6 @@ public void TestSubClientAccessorFactoryMethods(InputClient client, bool hasSubC } } - [TestCase(true)] - [TestCase(false)] - public void TestGetClientOptions(bool isSubClient) - { - string? parentClientName = null; - if (isSubClient) - { - parentClientName = "parent"; - } - - var client = InputFactory.Client(TestClientName, parent: parentClientName); - var clientProvider = new ClientProvider(client); - - if (isSubClient) - { - Assert.IsNull(clientProvider?.ClientOptions); - } - else - { - Assert.IsNotNull(clientProvider?.ClientOptions); - } - } - [Test] public void ValidateQueryParamDiff() { @@ -753,118 +753,6 @@ protected override MethodProvider[] BuildMethods() protected override PropertyProvider[] BuildProperties() => []; } - public static IEnumerable SubClientFactoryMethodTestCases - { - get - { - yield return new TestCaseData(InputFactory.Client(TestClientName), true); - yield return new TestCaseData(_animalClient, true); - yield return new TestCaseData(_dogClient, true); - yield return new TestCaseData(_huskyClient, false); - } - } - - public static IEnumerable BuildConstructorsTestCases - { - get - { - yield return new TestCaseData(new List - { - InputFactory.Parameter( - "optionalParam", - InputPrimitiveType.String, - location: RequestLocation.None, - kind: InputOperationParameterKind.Client), - InputFactory.Parameter( - KnownParameters.Endpoint.Name, - InputPrimitiveType.String, - location: RequestLocation.None, - defaultValue: InputFactory.Constant.String("someValue"), - kind: InputOperationParameterKind.Client, - isEndpoint: true) - }); - // scenario where endpoint is required - yield return new TestCaseData(new List - { - InputFactory.Parameter( - KnownParameters.Endpoint.Name, - InputPrimitiveType.String, - location: RequestLocation.None, - kind: InputOperationParameterKind.Client, - isRequired: true, - isEndpoint: true), - InputFactory.Parameter( - "optionalParam", - InputPrimitiveType.String, - location: RequestLocation.None, - kind: InputOperationParameterKind.Client) - }); - } - } - - private static IEnumerable EndpointParamInitializationValueTestCases - { - get - { - // string primitive type - yield return new TestCaseData( - InputFactory.Parameter( - "param", - InputPrimitiveType.String, - location: RequestLocation.None, - kind: InputOperationParameterKind.Client, - isEndpoint: true, - defaultValue: InputFactory.Constant.String("mockValue")), - New.Instance(KnownParameters.Endpoint.Type, Literal("mockvalue"))); - } - } - - // TODO -- this is temporary here before System.ClientModel officially supports OAuth2 auth - private record TestClientPipelineApi : ClientPipelineApi - { - private static ClientPipelineApi? _instance; - internal static ClientPipelineApi Instance => _instance ??= new TestClientPipelineApi(Empty); - - public TestClientPipelineApi(ValueExpression original) : base(typeof(string), original) - { - } - - public override CSharpType ClientPipelineType => typeof(string); - - public override CSharpType ClientPipelineOptionsType => typeof(string); - - public override CSharpType PipelinePolicyType => typeof(string); - - public override CSharpType KeyCredentialType => typeof(ApiKeyCredential); - - public override CSharpType TokenCredentialType => typeof(TestTokenCredential); - - public override ValueExpression Create(ValueExpression options, ValueExpression perRetryPolicies) - => Original.Invoke("GetFakeCreate", [options, perRetryPolicies]); - - public override ValueExpression CreateMessage(HttpRequestOptionsApi requestOptions, ValueExpression responseClassifier) - => Original.Invoke("GetFakeCreateMessage", [requestOptions, responseClassifier]); - - public override ClientPipelineApi FromExpression(ValueExpression expression) - => new TestClientPipelineApi(expression); - - public override ValueExpression ConsumeKeyAuth(ValueExpression credential, ValueExpression headerName, ValueExpression? keyPrefix = null) - => Original.Invoke("GetFakeApiKeyAuthorizationPolicy", keyPrefix != null ? [credential, headerName, keyPrefix] : [credential, headerName]); - - public override ValueExpression ConsumeOAuth2Auth(ValueExpression credential, ValueExpression scopes) - => Original.Invoke("GetFakeTokenAuthorizationPolicy", [credential, scopes]); - - public override ClientPipelineApi ToExpression() => this; - - public override MethodBodyStatement[] ProcessMessage(HttpMessageApi message, HttpRequestOptionsApi options) - => [Original.Invoke("GetFakeProcessMessage", [message, options]).Terminate()]; - - public override MethodBodyStatement[] ProcessMessageAsync(HttpMessageApi message, HttpRequestOptionsApi options) - => [Original.Invoke("GetFakeProcessMessageAsync", [message, options]).Terminate()]; - } - - internal class TestTokenCredential { } - public static IEnumerable BuildAuthFieldsTestCases { get @@ -1044,6 +932,72 @@ public static IEnumerable ValidateClientWithSpreadTestCases } } + public static IEnumerable SubClientFactoryMethodTestCases + { + get + { + yield return new TestCaseData(InputFactory.Client(TestClientName), true); + yield return new TestCaseData(_animalClient, true); + yield return new TestCaseData(_dogClient, true); + yield return new TestCaseData(_huskyClient, false); + } + } + + public static IEnumerable BuildConstructorsTestCases + { + get + { + yield return new TestCaseData(new List + { + InputFactory.Parameter( + "optionalParam", + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client), + InputFactory.Parameter( + KnownParameters.Endpoint.Name, + InputPrimitiveType.String, + location: RequestLocation.None, + defaultValue: InputFactory.Constant.String("someValue"), + kind: InputOperationParameterKind.Client, + isEndpoint: true) + }); + // scenario where endpoint is required + yield return new TestCaseData(new List + { + InputFactory.Parameter( + KnownParameters.Endpoint.Name, + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client, + isRequired: true, + isEndpoint: true), + InputFactory.Parameter( + "optionalParam", + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client) + }); + } + } + + private static IEnumerable EndpointParamInitializationValueTestCases + { + get + { + // string primitive type + yield return new TestCaseData( + InputFactory.Parameter( + "param", + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client, + isEndpoint: true, + defaultValue: InputFactory.Constant.String("mockValue")), + New.Instance(KnownParameters.Endpoint.Type, Literal("mockvalue"))); + } + } + public static IEnumerable RequestOptionsParameterInSignatureTestCases { get @@ -1230,5 +1184,51 @@ private static IEnumerable ValidateApiVersionPathParameterTestCase ])); } } + + // TODO -- this is temporary here before System.ClientModel officially supports OAuth2 auth + private record TestClientPipelineApi : ClientPipelineApi + { + private static ClientPipelineApi? _instance; + internal static ClientPipelineApi Instance => _instance ??= new TestClientPipelineApi(Empty); + + public TestClientPipelineApi(ValueExpression original) : base(typeof(string), original) + { + } + + public override CSharpType ClientPipelineType => typeof(string); + + public override CSharpType ClientPipelineOptionsType => typeof(string); + + public override CSharpType PipelinePolicyType => typeof(string); + + public override CSharpType KeyCredentialType => typeof(ApiKeyCredential); + + public override CSharpType TokenCredentialType => typeof(TestTokenCredential); + + public override ValueExpression Create(ValueExpression options, ValueExpression perRetryPolicies) + => Original.Invoke("GetFakeCreate", [options, perRetryPolicies]); + + public override ValueExpression CreateMessage(HttpRequestOptionsApi requestOptions, ValueExpression responseClassifier) + => Original.Invoke("GetFakeCreateMessage", [requestOptions, responseClassifier]); + + public override ClientPipelineApi FromExpression(ValueExpression expression) + => new TestClientPipelineApi(expression); + + public override ValueExpression ConsumeKeyAuth(ValueExpression credential, ValueExpression headerName, ValueExpression? keyPrefix = null) + => Original.Invoke("GetFakeApiKeyAuthorizationPolicy", keyPrefix != null ? [credential, headerName, keyPrefix] : [credential, headerName]); + + public override ValueExpression ConsumeOAuth2Auth(ValueExpression credential, ValueExpression scopes) + => Original.Invoke("GetFakeTokenAuthorizationPolicy", [credential, scopes]); + + public override ClientPipelineApi ToExpression() => this; + + public override MethodBodyStatement[] ProcessMessage(HttpMessageApi message, HttpRequestOptionsApi options) + => [Original.Invoke("GetFakeProcessMessage", [message, options]).Terminate()]; + + public override MethodBodyStatement[] ProcessMessageAsync(HttpMessageApi message, HttpRequestOptionsApi options) + => [Original.Invoke("GetFakeProcessMessageAsync", [message, options]).Terminate()]; + } + + internal class TestTokenCredential { } } } From 19dad66e0e560362478fc480f2cf7258b6163b36 Mon Sep 17 00:00:00 2001 From: Dapeng Zhang Date: Wed, 4 Dec 2024 16:12:13 +0800 Subject: [PATCH 14/22] more rearrangement --- .../ClientProviders/ClientProviderTests.cs | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs index 5b6a129d33..fc89dc62b0 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs @@ -981,23 +981,6 @@ public static IEnumerable BuildConstructorsTestCases } } - private static IEnumerable EndpointParamInitializationValueTestCases - { - get - { - // string primitive type - yield return new TestCaseData( - InputFactory.Parameter( - "param", - InputPrimitiveType.String, - location: RequestLocation.None, - kind: InputOperationParameterKind.Client, - isEndpoint: true, - defaultValue: InputFactory.Constant.String("mockValue")), - New.Instance(KnownParameters.Endpoint.Type, Literal("mockvalue"))); - } - } - public static IEnumerable RequestOptionsParameterInSignatureTestCases { get @@ -1117,6 +1100,23 @@ public static IEnumerable RequestOptionsParameterInSignatureTestCa } } + private static IEnumerable EndpointParamInitializationValueTestCases + { + get + { + // string primitive type + yield return new TestCaseData( + InputFactory.Parameter( + "param", + InputPrimitiveType.String, + location: RequestLocation.None, + kind: InputOperationParameterKind.Client, + isEndpoint: true, + defaultValue: InputFactory.Constant.String("mockValue")), + New.Instance(KnownParameters.Endpoint.Type, Literal("mockvalue"))); + } + } + private static IEnumerable ValidateApiVersionPathParameterTestCases { get From 3cde6e8db19605b757dda0d6159c22e0592fae96 Mon Sep 17 00:00:00 2001 From: Dapeng Zhang Date: Wed, 4 Dec 2024 16:13:25 +0800 Subject: [PATCH 15/22] rename a class --- .../Providers/ClientProviders/ClientProviderTests.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs index fc89dc62b0..d8633a689a 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs @@ -119,7 +119,7 @@ public void TestBuildAuthFields_WithAuth(List inputParameters) AssertHasFields(clientProvider, new List { new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(FakeTokenCredential)), "_tokenCredential"), }); } } @@ -202,7 +202,7 @@ public void TestBuildAuthFields_WithSubClients_WithAuth(InputClient client) AssertHasFields(clientProvider, new List { new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), - new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(TestTokenCredential)), "_tokenCredential"), + new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(FakeTokenCredential)), "_tokenCredential"), }); } } @@ -367,7 +367,7 @@ private void ValidatePrimaryConstructor( } else if (authParam?.Name == "tokenCredential") { - Assert.AreEqual(new CSharpType(typeof(TestTokenCredential)), authParam?.Type); + Assert.AreEqual(new CSharpType(typeof(FakeTokenCredential)), authParam?.Type); } else { @@ -1203,7 +1203,7 @@ public TestClientPipelineApi(ValueExpression original) : base(typeof(string), or public override CSharpType KeyCredentialType => typeof(ApiKeyCredential); - public override CSharpType TokenCredentialType => typeof(TestTokenCredential); + public override CSharpType TokenCredentialType => typeof(FakeTokenCredential); public override ValueExpression Create(ValueExpression options, ValueExpression perRetryPolicies) => Original.Invoke("GetFakeCreate", [options, perRetryPolicies]); @@ -1229,6 +1229,6 @@ public override MethodBodyStatement[] ProcessMessageAsync(HttpMessageApi message => [Original.Invoke("GetFakeProcessMessageAsync", [message, options]).Terminate()]; } - internal class TestTokenCredential { } + internal class FakeTokenCredential { } } } From 84cc3601d3e44de14773f5ee4e8cac960d0a25b3 Mon Sep 17 00:00:00 2001 From: Dapeng Zhang Date: Mon, 9 Dec 2024 10:29:31 +0800 Subject: [PATCH 16/22] resolve comments --- .../Abstractions/ClientPipelineApi.cs | 4 +-- .../src/Providers/ClientPipelineProvider.cs | 4 +-- .../src/Providers/ClientProvider.cs | 27 +++++++++---------- .../Abstractions/ClientPipelineApiTests.cs | 4 +-- .../ClientProviders/ClientProviderTests.cs | 4 +-- 5 files changed, 21 insertions(+), 22 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/Abstractions/ClientPipelineApi.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/Abstractions/ClientPipelineApi.cs index 9806d92915..a9928848d3 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/Abstractions/ClientPipelineApi.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/Abstractions/ClientPipelineApi.cs @@ -28,8 +28,8 @@ protected ClientPipelineApi(Type type, ValueExpression original) : base(type, or public abstract ValueExpression Create(ValueExpression options, ValueExpression perRetryPolicies); - public abstract ValueExpression ConsumeKeyAuth(ValueExpression credential, ValueExpression headerName, ValueExpression? keyPrefix = null); - public abstract ValueExpression ConsumeOAuth2Auth(ValueExpression credential, ValueExpression scopes); + public abstract ValueExpression KeyAuthorizationPolicy(ValueExpression credential, ValueExpression headerName, ValueExpression? keyPrefix = null); + public abstract ValueExpression TokenAuthorizationPolicy(ValueExpression credential, ValueExpression scopes); public abstract ClientPipelineApi FromExpression(ValueExpression expression); public abstract ClientPipelineApi ToExpression(); } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientPipelineProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientPipelineProvider.cs index 39b9f6e82d..ef6297ceb9 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientPipelineProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientPipelineProvider.cs @@ -39,13 +39,13 @@ public override ValueExpression CreateMessage(HttpRequestOptionsApi requestOptio public override ClientPipelineApi FromExpression(ValueExpression expression) => new ClientPipelineProvider(expression); - public override ValueExpression ConsumeKeyAuth(ValueExpression credential, ValueExpression headerName, ValueExpression? keyPrefix = null) + public override ValueExpression KeyAuthorizationPolicy(ValueExpression credential, ValueExpression headerName, ValueExpression? keyPrefix = null) { ValueExpression[] arguments = keyPrefix == null ? [credential, headerName] : [credential, headerName, keyPrefix]; return Static().Invoke(nameof(ApiKeyAuthenticationPolicy.CreateHeaderApiKeyPolicy), arguments).As(); } - public override ValueExpression ConsumeOAuth2Auth(ValueExpression credential, ValueExpression scopes) + public override ValueExpression TokenAuthorizationPolicy(ValueExpression credential, ValueExpression scopes) { // Scm library does not support token credentials yet. The throw here is intentional. // For a plugin that supports token credentials, they could override this implementation as well as the above TokenCredentialType property. diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientProvider.cs index b90ac04099..ada1b78037 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientProvider.cs @@ -32,13 +32,12 @@ public class ClientProvider : TypeProvider private readonly ParameterProvider _endpointParameter; private readonly FieldProvider? _clientCachingField; - #region credential fields private readonly FieldProvider? _apiKeyAuthField; private readonly FieldProvider? _authorizationHeaderConstant; private readonly FieldProvider? _authorizationApiKeyPrefixConstant; private readonly FieldProvider? _tokenCredentialField; private readonly FieldProvider? _tokenCredentialScopesField; - #endregion + private FieldProvider? _apiVersionField; private readonly Lazy> _subClientInternalConstructorParams; private IReadOnlyList>? _subClients; @@ -288,19 +287,19 @@ protected override ConstructorProvider[] BuildConstructors() // handle sub-client constructors if (ClientOptionsParameter is null) { - List body = new(3) { EndpointField.Assign(_endpointParameter).Terminate() }; - foreach (var p in _subClientInternalConstructorParams.Value) + List body = new(3) { EndpointField.Assign(_endpointParameter).Terminate() }; + foreach (var p in _subClientInternalConstructorParams.Value) + { + var assignment = p.Field?.Assign(p).Terminate() ?? p.Property?.Assign(p).Terminate(); + if (assignment != null) { - var assignment = p.Field?.Assign(p).Terminate() ?? p.Property?.Assign(p).Terminate(); - if (assignment != null) - { - body.Add(assignment); - } + body.Add(assignment); } - var subClientConstructor = new ConstructorProvider( - new ConstructorSignature(Type, _publicCtorDescription, MethodSignatureModifiers.Internal, _subClientInternalConstructorParams.Value), - body, - this); + } + var subClientConstructor = new ConstructorProvider( + new ConstructorSignature(Type, _publicCtorDescription, MethodSignatureModifiers.Internal, _subClientInternalConstructorParams.Value), + body, + this); return [mockingConstructor, subClientConstructor]; } @@ -406,7 +405,7 @@ private MethodBodyStatement[] BuildPrimaryConstructorBody(IReadOnlyList().ConsumeKeyAuth(_apiKeyAuthField, _authorizationHeaderConstant, keyPrefix)); + perRetryPolicies = New.Array(ClientModelPlugin.Instance.TypeFactory.ClientPipelineApi.PipelinePolicyType, isInline: true, This.ToApi().KeyAuthorizationPolicy(_apiKeyAuthField, _authorizationHeaderConstant, keyPrefix)); } body.Add(PipelineProperty.Assign(This.ToApi().Create(ClientOptionsParameter, perRetryPolicies)).Terminate()); diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/Abstractions/ClientPipelineApiTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/Abstractions/ClientPipelineApiTests.cs index 80b68173bb..5e968b87b0 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/Abstractions/ClientPipelineApiTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/Abstractions/ClientPipelineApiTests.cs @@ -68,10 +68,10 @@ public override ValueExpression CreateMessage(HttpRequestOptionsApi requestOptio public override ClientPipelineApi FromExpression(ValueExpression expression) => new TestClientPipelineApi(expression); - public override ValueExpression ConsumeKeyAuth(ValueExpression credential, ValueExpression headerName, ValueExpression? keyPrefix = null) + public override ValueExpression KeyAuthorizationPolicy(ValueExpression credential, ValueExpression headerName, ValueExpression? keyPrefix = null) => Original.Invoke("GetFakeAuthorizationPolicy", keyPrefix == null ? [credential, headerName] : [credential, headerName, keyPrefix]); - public override ValueExpression ConsumeOAuth2Auth(ValueExpression credential, ValueExpression scopes) + public override ValueExpression TokenAuthorizationPolicy(ValueExpression credential, ValueExpression scopes) => Original.Invoke("GetFakeTokenAuthorizationPolicy", [credential, scopes]); public override ClientPipelineApi ToExpression() => this; diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs index d8633a689a..b9a85869fb 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs @@ -1214,10 +1214,10 @@ public override ValueExpression CreateMessage(HttpRequestOptionsApi requestOptio public override ClientPipelineApi FromExpression(ValueExpression expression) => new TestClientPipelineApi(expression); - public override ValueExpression ConsumeKeyAuth(ValueExpression credential, ValueExpression headerName, ValueExpression? keyPrefix = null) + public override ValueExpression KeyAuthorizationPolicy(ValueExpression credential, ValueExpression headerName, ValueExpression? keyPrefix = null) => Original.Invoke("GetFakeApiKeyAuthorizationPolicy", keyPrefix != null ? [credential, headerName, keyPrefix] : [credential, headerName]); - public override ValueExpression ConsumeOAuth2Auth(ValueExpression credential, ValueExpression scopes) + public override ValueExpression TokenAuthorizationPolicy(ValueExpression credential, ValueExpression scopes) => Original.Invoke("GetFakeTokenAuthorizationPolicy", [credential, scopes]); public override ClientPipelineApi ToExpression() => this; From 7b83443dc4272afd164ef2fb7f28bf0e111615f4 Mon Sep 17 00:00:00 2001 From: Dapeng Zhang Date: Mon, 9 Dec 2024 10:41:59 +0800 Subject: [PATCH 17/22] resolve more comments --- .../src/Providers/ClientPipelineProvider.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientPipelineProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientPipelineProvider.cs index ef6297ceb9..5cf9279ea5 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientPipelineProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientPipelineProvider.cs @@ -1,13 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System; +using System.ClientModel; using System.ClientModel.Primitives; using Microsoft.Generator.CSharp.Expressions; using Microsoft.Generator.CSharp.Primitives; -using Microsoft.Generator.CSharp.Statements; using Microsoft.Generator.CSharp.Snippets; +using Microsoft.Generator.CSharp.Statements; using static Microsoft.Generator.CSharp.Snippets.Snippet; -using System.ClientModel; namespace Microsoft.Generator.CSharp.ClientModel.Providers { @@ -49,7 +50,7 @@ public override ValueExpression TokenAuthorizationPolicy(ValueExpression credent { // Scm library does not support token credentials yet. The throw here is intentional. // For a plugin that supports token credentials, they could override this implementation as well as the above TokenCredentialType property. - throw new System.NotImplementedException(); + throw new NotImplementedException(); } public override ClientPipelineApi ToExpression() => this; From 5fed9555bde304358af9e9e6701cb5542d5c2966 Mon Sep 17 00:00:00 2001 From: Dapeng Zhang Date: Mon, 9 Dec 2024 10:58:57 +0800 Subject: [PATCH 18/22] move those utils back to clientprovidertests --- .../ClientProviders/ClientProviderTests.cs | 88 ++++++++++++++- .../ClientProviderTestsUtils.cs | 102 ------------------ 2 files changed, 87 insertions(+), 103 deletions(-) delete mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTestsUtils.cs diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs index b9a85869fb..30ea8cf2c6 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs @@ -15,7 +15,6 @@ using Microsoft.Generator.CSharp.Statements; using Microsoft.Generator.CSharp.Tests.Common; using NUnit.Framework; -using static Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders.ClientProviderTestsUtils; using static Microsoft.Generator.CSharp.Snippets.Snippet; namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders @@ -1230,5 +1229,92 @@ public override MethodBodyStatement[] ProcessMessageAsync(HttpMessageApi message } internal class FakeTokenCredential { } + + public record ExpectedCSharpType + { + public string Name { get; } + + public string Namespace { get; } + + public bool IsFrameworkType { get; } + + public Type FrameworkType => _frameworkType ?? throw new InvalidOperationException(); + + public bool IsNullable { get; } + + private readonly Type? _frameworkType; + + public ExpectedCSharpType(Type frameworkType, bool isNullable) + { + _frameworkType = frameworkType; + IsFrameworkType = true; + IsNullable = isNullable; + Name = frameworkType.Name; + Namespace = frameworkType.Namespace!; + } + + public ExpectedCSharpType(string name, string ns, bool isNullable) + { + IsFrameworkType = false; + IsNullable = isNullable; + Name = name; + Namespace = ns; + } + + public static implicit operator ExpectedCSharpType(CSharpType type) + { + if (type.IsFrameworkType) + { + return new(type.FrameworkType, type.IsNullable); + } + else + { + return new(type.Name, type.Namespace, type.IsNullable); + } + } + } + + public record ExpectedFieldProvider(FieldModifiers Modifiers, ExpectedCSharpType Type, string Name); + + private static void AssertCSharpTypeAreEqual(ExpectedCSharpType expected, CSharpType type) + { + if (expected.IsFrameworkType) + { + Assert.IsTrue(type.IsFrameworkType); + Assert.AreEqual(expected.FrameworkType, type.FrameworkType); + } + else + { + Assert.IsFalse(type.IsFrameworkType); + Assert.AreEqual(expected.Name, type.Name); + Assert.AreEqual(expected.Namespace, type.Namespace); + } + Assert.AreEqual(expected.IsNullable, type.IsNullable); + } + + private static void AssertFieldAreEqual(ExpectedFieldProvider expected, FieldProvider field) + { + Assert.AreEqual(expected.Name, field.Name); + AssertCSharpTypeAreEqual(expected.Type, field.Type); + Assert.AreEqual(expected.Modifiers, field.Modifiers); + } + + private static void AssertHasFields(TypeProvider provider, IReadOnlyList expectedFields) + { + var fields = provider.Fields; + + // validate the length of the result + Assert.GreaterOrEqual(fields.Count, expectedFields.Count); + + // validate each of them + var fieldDict = fields.ToDictionary(f => f.Name); + for (int i = 0; i < expectedFields.Count; i++) + { + var expected = expectedFields[i]; + + Assert.IsTrue(fieldDict.TryGetValue(expected.Name, out var actual), $"Field {expected.Name} not present"); + AssertFieldAreEqual(expected, actual!); + } + } } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTestsUtils.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTestsUtils.cs deleted file mode 100644 index 09c0e61b7e..0000000000 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTestsUtils.cs +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.Generator.CSharp.Primitives; -using Microsoft.Generator.CSharp.Providers; -using NUnit.Framework; - -namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.ClientProviders -{ - public static class ClientProviderTestsUtils - { - public record ExpectedCSharpType - { - public string Name { get; } - - public string Namespace { get; } - - public bool IsFrameworkType { get; } - - public Type FrameworkType => _frameworkType ?? throw new InvalidOperationException(); - - public bool IsNullable { get; } - - private readonly Type? _frameworkType; - - public ExpectedCSharpType(Type frameworkType, bool isNullable) - { - _frameworkType = frameworkType; - IsFrameworkType = true; - IsNullable = isNullable; - Name = frameworkType.Name; - Namespace = frameworkType.Namespace!; - } - - public ExpectedCSharpType(string name, string ns, bool isNullable) - { - IsFrameworkType = false; - IsNullable = isNullable; - Name = name; - Namespace = ns; - } - - public static implicit operator ExpectedCSharpType(CSharpType type) - { - if (type.IsFrameworkType) - { - return new(type.FrameworkType, type.IsNullable); - } - else - { - return new(type.Name, type.Namespace, type.IsNullable); - } - } - } - - public record ExpectedFieldProvider(FieldModifiers Modifiers, ExpectedCSharpType Type, string Name); - - internal static void AssertCSharpTypeAreEqual(ExpectedCSharpType expected, CSharpType type) - { - if (expected.IsFrameworkType) - { - Assert.IsTrue(type.IsFrameworkType); - Assert.AreEqual(expected.FrameworkType, type.FrameworkType); - } - else - { - Assert.IsFalse(type.IsFrameworkType); - Assert.AreEqual(expected.Name, type.Name); - Assert.AreEqual(expected.Namespace, type.Namespace); - } - Assert.AreEqual(expected.IsNullable, type.IsNullable); - } - - internal static void AssertFieldAreEqual(ExpectedFieldProvider expected, FieldProvider field) - { - Assert.AreEqual(expected.Name, field.Name); - AssertCSharpTypeAreEqual(expected.Type, field.Type); - Assert.AreEqual(expected.Modifiers, field.Modifiers); - } - - internal static void AssertHasFields(TypeProvider provider, IReadOnlyList expectedFields) - { - var fields = provider.Fields; - - // validate the length of the result - Assert.GreaterOrEqual(fields.Count, expectedFields.Count); - - // validate each of them - var fieldDict = fields.ToDictionary(f => f.Name); - for (int i = 0; i < expectedFields.Count; i++) - { - var expected = expectedFields[i]; - - Assert.IsTrue(fieldDict.TryGetValue(expected.Name, out var actual), $"Field {expected.Name} not present"); - AssertFieldAreEqual(expected, actual!); - } - } - } -} From ed8838d9ad079febda192082c02541d51899e243 Mon Sep 17 00:00:00 2001 From: Dapeng Zhang Date: Thu, 12 Dec 2024 15:02:35 +0800 Subject: [PATCH 19/22] fix problematic modifiers on fields --- .../src/Providers/ClientProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientProvider.cs index ada1b78037..ed0fb5ccf0 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientProvider.cs @@ -109,7 +109,7 @@ public ClientProvider(InputClient inputClient) if (tokenAuth.Scopes != null) { _tokenCredentialScopesField = new FieldProvider( - FieldModifiers.Private | FieldModifiers.Const, + FieldModifiers.Private | FieldModifiers.Static | FieldModifiers.ReadOnly, typeof(string[]), TokenCredentialScopesFieldName, this, From 5184c60f6477fb8273f3f0dfedfa618f36689fc9 Mon Sep 17 00:00:00 2001 From: Dapeng Zhang Date: Thu, 12 Dec 2024 15:24:54 +0800 Subject: [PATCH 20/22] fix test cases --- .../test/Providers/ClientProviders/ClientProviderTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs index 43e5d0c635..76de2a5cf4 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs @@ -117,7 +117,7 @@ public void TestBuildAuthFields_WithAuth(List inputParameters) // oauth2 auth should have the following fields: AuthorizationScopes, _tokenCredential AssertHasFields(clientProvider, new List { - new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), + new(FieldModifiers.Private | FieldModifiers.Static | FieldModifiers.ReadOnly, new CSharpType(typeof(string[])), "AuthorizationScopes"), new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(FakeTokenCredential)), "_tokenCredential"), }); } @@ -200,7 +200,7 @@ public void TestBuildAuthFields_WithSubClients_WithAuth(InputClient client) // oauth2 auth should have the following fields: AuthorizationScopes, _tokenCredential AssertHasFields(clientProvider, new List { - new(FieldModifiers.Private | FieldModifiers.Const, new CSharpType(typeof(string[])), "AuthorizationScopes"), + new(FieldModifiers.Private | FieldModifiers.Static | FieldModifiers.ReadOnly, new CSharpType(typeof(string[])), "AuthorizationScopes"), new(FieldModifiers.Private | FieldModifiers.ReadOnly, new CSharpType(typeof(FakeTokenCredential)), "_tokenCredential"), }); } From 8e025ce515c85119f627fdb5f2986b95ad26f18e Mon Sep 17 00:00:00 2001 From: Dapeng Zhang Date: Fri, 13 Dec 2024 11:26:08 +0800 Subject: [PATCH 21/22] fix issues in ctor body --- .../src/Providers/ClientProvider.cs | 136 +++++++++--------- 1 file changed, 65 insertions(+), 71 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientProvider.cs index ed0fb5ccf0..c050d10981 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ClientProvider.cs @@ -19,6 +19,10 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers { public class ClientProvider : TypeProvider { + private record AuthFields(FieldProvider AuthField); + private record ApiKeyFields(FieldProvider AuthField, FieldProvider AuthorizationHeaderField, FieldProvider? AuthorizationApiKeyPrefixField) : AuthFields(AuthField); + private record OAuth2Fields(FieldProvider AuthField, FieldProvider AuthorizationScopesField) : AuthFields(AuthField); + private const string AuthorizationHeaderConstName = "AuthorizationHeader"; private const string AuthorizationApiKeyPrefixConstName = "AuthorizationApiKeyPrefix"; private const string ApiKeyCredentialFieldName = "_keyCredential"; @@ -32,11 +36,8 @@ public class ClientProvider : TypeProvider private readonly ParameterProvider _endpointParameter; private readonly FieldProvider? _clientCachingField; - private readonly FieldProvider? _apiKeyAuthField; - private readonly FieldProvider? _authorizationHeaderConstant; - private readonly FieldProvider? _authorizationApiKeyPrefixConstant; - private readonly FieldProvider? _tokenCredentialField; - private readonly FieldProvider? _tokenCredentialScopesField; + private readonly ApiKeyFields? _apiKeyAuthFields; + private readonly OAuth2Fields? _oauth2Fields; private FieldProvider? _apiVersionField; private readonly Lazy> _subClientInternalConstructorParams; @@ -70,51 +71,46 @@ public ClientProvider(InputClient inputClient) var keyCredentialType = ClientModelPlugin.Instance.TypeFactory.ClientPipelineApi.KeyCredentialType; if (apiKey != null && keyCredentialType != null) { - _apiKeyAuthField = new FieldProvider( + var apiKeyAuthField = new FieldProvider( FieldModifiers.Private | FieldModifiers.ReadOnly, keyCredentialType, ApiKeyCredentialFieldName, this, description: $"A credential used to authenticate to the service."); - if (apiKey.Name != null) - { - _authorizationHeaderConstant = new FieldProvider( - FieldModifiers.Private | FieldModifiers.Const, - typeof(string), - AuthorizationHeaderConstName, - this, - initializationValue: Literal(apiKey.Name)); - } - if (apiKey.Prefix != null) - { - _authorizationApiKeyPrefixConstant = new FieldProvider( + var authorizationHeaderField = new FieldProvider( + FieldModifiers.Private | FieldModifiers.Const, + typeof(string), + AuthorizationHeaderConstName, + this, + initializationValue: Literal(apiKey.Name)); + var authorizationApiKeyPrefixField = apiKey.Prefix != null ? + new FieldProvider( FieldModifiers.Private | FieldModifiers.Const, typeof(string), AuthorizationApiKeyPrefixConstName, this, - initializationValue: Literal(apiKey.Prefix)); - } + initializationValue: Literal(apiKey.Prefix)) : + null; + _apiKeyAuthFields = new(apiKeyAuthField, authorizationHeaderField, authorizationApiKeyPrefixField); } // in this plugin, the type of TokenCredential is null therefore these code will never be executed, but it should be invoked in other plugins that could support it. var tokenAuth = _inputAuth?.OAuth2; var tokenCredentialType = ClientModelPlugin.Instance.TypeFactory.ClientPipelineApi.TokenCredentialType; if (tokenAuth != null && tokenCredentialType != null) { - _tokenCredentialField = new FieldProvider( + var tokenCredentialField = new FieldProvider( FieldModifiers.Private | FieldModifiers.ReadOnly, tokenCredentialType, TokenCredentialFieldName, this, description: $"A credential used to authenticate to the service."); - if (tokenAuth.Scopes != null) - { - _tokenCredentialScopesField = new FieldProvider( - FieldModifiers.Private | FieldModifiers.Static | FieldModifiers.ReadOnly, - typeof(string[]), - TokenCredentialScopesFieldName, - this, - initializationValue: New.Array(typeof(string), tokenAuth.Scopes.Select(s => Literal(s)).ToArray())); - } + var tokenCredentialScopesField = new FieldProvider( + FieldModifiers.Private | FieldModifiers.Static | FieldModifiers.ReadOnly, + typeof(string[]), + TokenCredentialScopesFieldName, + this, + initializationValue: New.Array(typeof(string), tokenAuth.Scopes.Select(Literal).ToArray())); + _oauth2Fields = new(tokenCredentialField, tokenCredentialScopesField); } EndpointField = new( FieldModifiers.Private | FieldModifiers.ReadOnly, @@ -154,13 +150,13 @@ private IReadOnlyList GetSubClientInternalConstructorParamete PipelineProperty.AsParameter }; - if (_apiKeyAuthField != null) + if (_apiKeyAuthFields != null) { - subClientParameters.Add(_apiKeyAuthField.AsParameter); + subClientParameters.Add(_apiKeyAuthFields.AuthField.AsParameter); } - if (_tokenCredentialField != null) + if (_oauth2Fields != null) { - subClientParameters.Add(_tokenCredentialField.AsParameter); + subClientParameters.Add(_oauth2Fields.AuthField.AsParameter); } subClientParameters.Add(_endpointParameter); subClientParameters.AddRange(ClientParameters); @@ -212,24 +208,20 @@ protected override FieldProvider[] BuildFields() { List fields = [EndpointField]; - if (_apiKeyAuthField != null && _authorizationHeaderConstant != null) + if (_apiKeyAuthFields != null) { - fields.Add(_authorizationHeaderConstant); - fields.Add(_apiKeyAuthField); - - if (_authorizationApiKeyPrefixConstant != null) + fields.Add(_apiKeyAuthFields.AuthField); + fields.Add(_apiKeyAuthFields.AuthorizationHeaderField); + if (_apiKeyAuthFields.AuthorizationApiKeyPrefixField != null) { - fields.Add(_authorizationApiKeyPrefixConstant); + fields.Add(_apiKeyAuthFields.AuthorizationApiKeyPrefixField); } } - if (_tokenCredentialField != null) + if (_oauth2Fields != null) { - fields.Add(_tokenCredentialField); - } - if (_tokenCredentialScopesField != null) - { - fields.Add(_tokenCredentialScopesField); + fields.Add(_oauth2Fields.AuthField); + fields.Add(_oauth2Fields.AuthorizationScopesField); } fields.AddRange(_additionalClientFields.Value); @@ -309,17 +301,17 @@ protected override ConstructorProvider[] BuildConstructors() var secondaryConstructors = new List(); // if there is key auth - if (_apiKeyAuthField != null) + if (_apiKeyAuthFields != null) { - AppendConstructors(_apiKeyAuthField, primaryConstructors, secondaryConstructors); + AppendConstructors(_apiKeyAuthFields, primaryConstructors, secondaryConstructors); } // if there is oauth2 auth - if (_tokenCredentialField != null) + if (_oauth2Fields!= null) { - AppendConstructors(_tokenCredentialField, primaryConstructors, secondaryConstructors); + AppendConstructors(_oauth2Fields, primaryConstructors, secondaryConstructors); } // if there is no auth - if (_apiKeyAuthField == null && _tokenCredentialField == null) + if (_apiKeyAuthFields == null && _oauth2Fields == null) { AppendConstructors(null, primaryConstructors, secondaryConstructors); } @@ -328,13 +320,13 @@ protected override ConstructorProvider[] BuildConstructors() ? [ConstructorProviderHelper.BuildMockingConstructor(this), .. secondaryConstructors, .. primaryConstructors] : [.. secondaryConstructors, .. primaryConstructors]; - void AppendConstructors(FieldProvider? authField, List primaryConstructors, List secondaryConstructors) + void AppendConstructors(AuthFields? authFields, List primaryConstructors, List secondaryConstructors) { - var requiredParameters = GetRequiredParameters(authField); + var requiredParameters = GetRequiredParameters(authFields?.AuthField); ParameterProvider[] primaryConstructorParameters = [_endpointParameter, .. requiredParameters, ClientOptionsParameter]; var primaryConstructor = new ConstructorProvider( new ConstructorSignature(Type, _publicCtorDescription, MethodSignatureModifiers.Public, primaryConstructorParameters), - BuildPrimaryConstructorBody(primaryConstructorParameters), + BuildPrimaryConstructorBody(primaryConstructorParameters, authFields), this); primaryConstructors.Add(primaryConstructor); @@ -377,7 +369,7 @@ private ParameterProvider CreateParameter(InputParameter parameter) return param; } - private MethodBodyStatement[] BuildPrimaryConstructorBody(IReadOnlyList primaryConstructorParameters) + private MethodBodyStatement[] BuildPrimaryConstructorBody(IReadOnlyList primaryConstructorParameters, AuthFields? authFields) { if (ClientOptions is null || ClientOptionsParameter is null) { @@ -400,12 +392,19 @@ private MethodBodyStatement[] BuildPrimaryConstructorBody(IReadOnlyList().KeyAuthorizationPolicy(_apiKeyAuthField, _authorizationHeaderConstant, keyPrefix)); + case ApiKeyFields keyAuthFields: + ValueExpression? keyPrefixExpression = keyAuthFields.AuthorizationApiKeyPrefixField != null ? (ValueExpression)keyAuthFields.AuthorizationApiKeyPrefixField : null; + perRetryPolicies = New.Array(ClientModelPlugin.Instance.TypeFactory.ClientPipelineApi.PipelinePolicyType, isInline: true, This.ToApi().KeyAuthorizationPolicy(keyAuthFields.AuthField, keyAuthFields.AuthorizationHeaderField, keyPrefixExpression)); + break; + case OAuth2Fields oauth2AuthFields: + perRetryPolicies = New.Array(ClientModelPlugin.Instance.TypeFactory.ClientPipelineApi.PipelinePolicyType, isInline: true, This.ToApi().TokenAuthorizationPolicy(oauth2AuthFields.AuthField, oauth2AuthFields.AuthorizationScopesField)); + break; + default: + perRetryPolicies = New.Array(ClientModelPlugin.Instance.TypeFactory.ClientPipelineApi.PipelinePolicyType); + break; } body.Add(PipelineProperty.Assign(This.ToApi().Create(ClientOptionsParameter, perRetryPolicies)).Terminate()); @@ -413,18 +412,13 @@ private MethodBodyStatement[] BuildPrimaryConstructorBody(IReadOnlyList p.Name.ToCleanName()); foreach (var f in Fields) { - if (f != _apiKeyAuthField - && f != EndpointField - && !f.Modifiers.HasFlag(FieldModifiers.Const)) + if (f == _apiVersionField && ClientOptions.VersionProperty != null) { - if (f == _apiVersionField && ClientOptions.VersionProperty != null) - { - body.Add(f.Assign(ClientOptionsParameter.Property(ClientOptions.VersionProperty.Name)).Terminate()); - } - else if (clientOptionsPropertyDict.TryGetValue(f.Name.ToCleanName(), out var optionsProperty)) - { - clientOptionsPropertyDict.TryGetValue(f.Name.ToCleanName(), out optionsProperty); - } + body.Add(f.Assign(ClientOptionsParameter.Property(ClientOptions.VersionProperty.Name)).Terminate()); + } + else if (clientOptionsPropertyDict.TryGetValue(f.Name.ToCleanName(), out var optionsProperty)) + { + clientOptionsPropertyDict.TryGetValue(f.Name.ToCleanName(), out optionsProperty); } } From 631b9aaf9101c1c571aa37d3c3012bcbc812dd8d Mon Sep 17 00:00:00 2001 From: Dapeng Zhang Date: Fri, 13 Dec 2024 14:43:25 +0800 Subject: [PATCH 22/22] add test cases to validate the body of ctors --- .../ClientProviders/ClientProviderTests.cs | 50 +++++++------------ ...yConstructor(WithDefault,False,False,0).cs | 6 +++ ...ryConstructor(WithDefault,False,True,0).cs | 8 +++ ...ryConstructor(WithDefault,True,False,0).cs | 8 +++ ...aryConstructor(WithDefault,True,True,0).cs | 8 +++ ...aryConstructor(WithDefault,True,True,1).cs | 8 +++ ...Constructor(WithRequired,False,False,0).cs | 6 +++ ...yConstructor(WithRequired,False,True,0).cs | 8 +++ ...yConstructor(WithRequired,True,False,0).cs | 8 +++ ...ryConstructor(WithRequired,True,True,0).cs | 8 +++ ...ryConstructor(WithRequired,True,True,1).cs | 8 +++ .../src/Generated/UnbrandedTypeSpecClient.cs | 2 +- 12 files changed, 94 insertions(+), 34 deletions(-) create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithDefault,False,False,0).cs create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithDefault,False,True,0).cs create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithDefault,True,False,0).cs create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithDefault,True,True,0).cs create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithDefault,True,True,1).cs create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithRequired,False,False,0).cs create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithRequired,False,True,0).cs create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithRequired,True,False,0).cs create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithRequired,True,True,0).cs create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithRequired,True,True,1).cs diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs index 76de2a5cf4..b221fcd4ec 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs @@ -6,6 +6,7 @@ using System.ClientModel.Primitives; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; using Microsoft.Generator.CSharp.ClientModel.Providers; using Microsoft.Generator.CSharp.Expressions; using Microsoft.Generator.CSharp.Input; @@ -59,7 +60,7 @@ public void SetUp() apiKeyAuth: apiKeyAuth, oauth2Auth: oauth2Auth, clients: clients, - clientPipelineApi: _hasAuth ? TestClientPipelineApi.Instance : null); + clientPipelineApi: TestClientPipelineApi.Instance); } [Test] @@ -227,9 +228,9 @@ public void TestBuildConstructors_PrimaryConstructor(List inputP var expectedPrimaryCtorCount = _hasKeyAuth && _hasOAuth2 ? 2 : 1; Assert.AreEqual(expectedPrimaryCtorCount, primaryPublicConstructors.Length); - foreach (var primaryCtor in primaryPublicConstructors) + for (int i = 0; i < primaryPublicConstructors.Length; i++) { - ValidatePrimaryConstructor(primaryCtor, inputParameters); + ValidatePrimaryConstructor(primaryPublicConstructors[i], inputParameters, i); } } @@ -330,7 +331,10 @@ public void TestBuildConstructors_ForSubClient_BothAuth() private void ValidatePrimaryConstructor( ConstructorProvider primaryPublicConstructor, - List inputParameters) + List inputParameters, + int ctorIndex, + [CallerMemberName] string method = "", + [CallerFilePath] string filePath = "") { var primaryCtorParams = primaryPublicConstructor?.Signature?.Parameters; // in no auth case, the ctor only have two parameters: endpoint and options @@ -375,8 +379,11 @@ private void ValidatePrimaryConstructor( } // validate the body of the primary ctor + var caseName = TestContext.CurrentContext.Test.Properties.Get("caseName"); + var expected = Helpers.GetExpectedFromFile($"{caseName},{_hasKeyAuth},{_hasOAuth2},{ctorIndex}", method, filePath); var primaryCtorBody = primaryPublicConstructor?.BodyStatements; Assert.IsNotNull(primaryCtorBody); + Assert.AreEqual(expected, primaryCtorBody?.ToDisplayString()); } private void ValidateSecondaryConstructor( @@ -960,7 +967,7 @@ public static IEnumerable BuildConstructorsTestCases defaultValue: InputFactory.Constant.String("someValue"), kind: InputOperationParameterKind.Client, isEndpoint: true) - }); + }).SetProperty("caseName", "WithDefault"); // scenario where endpoint is required yield return new TestCaseData(new List { @@ -976,7 +983,7 @@ public static IEnumerable BuildConstructorsTestCases InputPrimitiveType.String, location: RequestLocation.None, kind: InputOperationParameterKind.Client) - }); + }).SetProperty("caseName", "WithRequired"); } } @@ -1185,47 +1192,24 @@ private static IEnumerable ValidateApiVersionPathParameterTestCase } // TODO -- this is temporary here before System.ClientModel officially supports OAuth2 auth - private record TestClientPipelineApi : ClientPipelineApi + private record TestClientPipelineApi : ClientPipelineProvider { private static ClientPipelineApi? _instance; - internal static ClientPipelineApi Instance => _instance ??= new TestClientPipelineApi(Empty); + internal new static ClientPipelineApi Instance => _instance ??= new TestClientPipelineApi(Empty); - public TestClientPipelineApi(ValueExpression original) : base(typeof(string), original) + public TestClientPipelineApi(ValueExpression original) : base(original) { } - public override CSharpType ClientPipelineType => typeof(string); - - public override CSharpType ClientPipelineOptionsType => typeof(string); - - public override CSharpType PipelinePolicyType => typeof(string); - - public override CSharpType KeyCredentialType => typeof(ApiKeyCredential); - public override CSharpType TokenCredentialType => typeof(FakeTokenCredential); - public override ValueExpression Create(ValueExpression options, ValueExpression perRetryPolicies) - => Original.Invoke("GetFakeCreate", [options, perRetryPolicies]); - - public override ValueExpression CreateMessage(HttpRequestOptionsApi requestOptions, ValueExpression responseClassifier) - => Original.Invoke("GetFakeCreateMessage", [requestOptions, responseClassifier]); - public override ClientPipelineApi FromExpression(ValueExpression expression) => new TestClientPipelineApi(expression); - - public override ValueExpression KeyAuthorizationPolicy(ValueExpression credential, ValueExpression headerName, ValueExpression? keyPrefix = null) - => Original.Invoke("GetFakeApiKeyAuthorizationPolicy", keyPrefix != null ? [credential, headerName, keyPrefix] : [credential, headerName]); - + public override ValueExpression TokenAuthorizationPolicy(ValueExpression credential, ValueExpression scopes) => Original.Invoke("GetFakeTokenAuthorizationPolicy", [credential, scopes]); public override ClientPipelineApi ToExpression() => this; - - public override MethodBodyStatement[] ProcessMessage(HttpMessageApi message, HttpRequestOptionsApi options) - => [Original.Invoke("GetFakeProcessMessage", [message, options]).Terminate()]; - - public override MethodBodyStatement[] ProcessMessageAsync(HttpMessageApi message, HttpRequestOptionsApi options) - => [Original.Invoke("GetFakeProcessMessageAsync", [message, options]).Terminate()]; } internal class FakeTokenCredential { } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithDefault,False,False,0).cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithDefault,False,False,0).cs new file mode 100644 index 0000000000..3fcf6856cf --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithDefault,False,False,0).cs @@ -0,0 +1,6 @@ +global::Sample.Argument.AssertNotNull(endpoint, nameof(endpoint)); + +options ??= new global::Sample.TestClientOptions(); + +_endpoint = endpoint; +Pipeline = global::System.ClientModel.Primitives.ClientPipeline.Create(options, Array.Empty(), Array.Empty(), Array.Empty()); diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithDefault,False,True,0).cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithDefault,False,True,0).cs new file mode 100644 index 0000000000..71d1e06f4d --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithDefault,False,True,0).cs @@ -0,0 +1,8 @@ +global::Sample.Argument.AssertNotNull(endpoint, nameof(endpoint)); +global::Sample.Argument.AssertNotNull(tokenCredential, nameof(tokenCredential)); + +options ??= new global::Sample.TestClientOptions(); + +_endpoint = endpoint; +_tokenCredential = tokenCredential; +Pipeline = global::System.ClientModel.Primitives.ClientPipeline.Create(options, Array.Empty(), new global::System.ClientModel.Primitives.PipelinePolicy[] { this.GetFakeTokenAuthorizationPolicy(_tokenCredential, AuthorizationScopes) }, Array.Empty()); diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithDefault,True,False,0).cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithDefault,True,False,0).cs new file mode 100644 index 0000000000..227fc6726b --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithDefault,True,False,0).cs @@ -0,0 +1,8 @@ +global::Sample.Argument.AssertNotNull(endpoint, nameof(endpoint)); +global::Sample.Argument.AssertNotNull(keyCredential, nameof(keyCredential)); + +options ??= new global::Sample.TestClientOptions(); + +_endpoint = endpoint; +_keyCredential = keyCredential; +Pipeline = global::System.ClientModel.Primitives.ClientPipeline.Create(options, Array.Empty(), new global::System.ClientModel.Primitives.PipelinePolicy[] { global::System.ClientModel.Primitives.ApiKeyAuthenticationPolicy.CreateHeaderApiKeyPolicy(_keyCredential, AuthorizationHeader) }, Array.Empty()); diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithDefault,True,True,0).cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithDefault,True,True,0).cs new file mode 100644 index 0000000000..227fc6726b --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithDefault,True,True,0).cs @@ -0,0 +1,8 @@ +global::Sample.Argument.AssertNotNull(endpoint, nameof(endpoint)); +global::Sample.Argument.AssertNotNull(keyCredential, nameof(keyCredential)); + +options ??= new global::Sample.TestClientOptions(); + +_endpoint = endpoint; +_keyCredential = keyCredential; +Pipeline = global::System.ClientModel.Primitives.ClientPipeline.Create(options, Array.Empty(), new global::System.ClientModel.Primitives.PipelinePolicy[] { global::System.ClientModel.Primitives.ApiKeyAuthenticationPolicy.CreateHeaderApiKeyPolicy(_keyCredential, AuthorizationHeader) }, Array.Empty()); diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithDefault,True,True,1).cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithDefault,True,True,1).cs new file mode 100644 index 0000000000..71d1e06f4d --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithDefault,True,True,1).cs @@ -0,0 +1,8 @@ +global::Sample.Argument.AssertNotNull(endpoint, nameof(endpoint)); +global::Sample.Argument.AssertNotNull(tokenCredential, nameof(tokenCredential)); + +options ??= new global::Sample.TestClientOptions(); + +_endpoint = endpoint; +_tokenCredential = tokenCredential; +Pipeline = global::System.ClientModel.Primitives.ClientPipeline.Create(options, Array.Empty(), new global::System.ClientModel.Primitives.PipelinePolicy[] { this.GetFakeTokenAuthorizationPolicy(_tokenCredential, AuthorizationScopes) }, Array.Empty()); diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithRequired,False,False,0).cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithRequired,False,False,0).cs new file mode 100644 index 0000000000..3fcf6856cf --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithRequired,False,False,0).cs @@ -0,0 +1,6 @@ +global::Sample.Argument.AssertNotNull(endpoint, nameof(endpoint)); + +options ??= new global::Sample.TestClientOptions(); + +_endpoint = endpoint; +Pipeline = global::System.ClientModel.Primitives.ClientPipeline.Create(options, Array.Empty(), Array.Empty(), Array.Empty()); diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithRequired,False,True,0).cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithRequired,False,True,0).cs new file mode 100644 index 0000000000..71d1e06f4d --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithRequired,False,True,0).cs @@ -0,0 +1,8 @@ +global::Sample.Argument.AssertNotNull(endpoint, nameof(endpoint)); +global::Sample.Argument.AssertNotNull(tokenCredential, nameof(tokenCredential)); + +options ??= new global::Sample.TestClientOptions(); + +_endpoint = endpoint; +_tokenCredential = tokenCredential; +Pipeline = global::System.ClientModel.Primitives.ClientPipeline.Create(options, Array.Empty(), new global::System.ClientModel.Primitives.PipelinePolicy[] { this.GetFakeTokenAuthorizationPolicy(_tokenCredential, AuthorizationScopes) }, Array.Empty()); diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithRequired,True,False,0).cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithRequired,True,False,0).cs new file mode 100644 index 0000000000..227fc6726b --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithRequired,True,False,0).cs @@ -0,0 +1,8 @@ +global::Sample.Argument.AssertNotNull(endpoint, nameof(endpoint)); +global::Sample.Argument.AssertNotNull(keyCredential, nameof(keyCredential)); + +options ??= new global::Sample.TestClientOptions(); + +_endpoint = endpoint; +_keyCredential = keyCredential; +Pipeline = global::System.ClientModel.Primitives.ClientPipeline.Create(options, Array.Empty(), new global::System.ClientModel.Primitives.PipelinePolicy[] { global::System.ClientModel.Primitives.ApiKeyAuthenticationPolicy.CreateHeaderApiKeyPolicy(_keyCredential, AuthorizationHeader) }, Array.Empty()); diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithRequired,True,True,0).cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithRequired,True,True,0).cs new file mode 100644 index 0000000000..227fc6726b --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithRequired,True,True,0).cs @@ -0,0 +1,8 @@ +global::Sample.Argument.AssertNotNull(endpoint, nameof(endpoint)); +global::Sample.Argument.AssertNotNull(keyCredential, nameof(keyCredential)); + +options ??= new global::Sample.TestClientOptions(); + +_endpoint = endpoint; +_keyCredential = keyCredential; +Pipeline = global::System.ClientModel.Primitives.ClientPipeline.Create(options, Array.Empty(), new global::System.ClientModel.Primitives.PipelinePolicy[] { global::System.ClientModel.Primitives.ApiKeyAuthenticationPolicy.CreateHeaderApiKeyPolicy(_keyCredential, AuthorizationHeader) }, Array.Empty()); diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithRequired,True,True,1).cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithRequired,True,True,1).cs new file mode 100644 index 0000000000..71d1e06f4d --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestBuildConstructors_PrimaryConstructor(WithRequired,True,True,1).cs @@ -0,0 +1,8 @@ +global::Sample.Argument.AssertNotNull(endpoint, nameof(endpoint)); +global::Sample.Argument.AssertNotNull(tokenCredential, nameof(tokenCredential)); + +options ??= new global::Sample.TestClientOptions(); + +_endpoint = endpoint; +_tokenCredential = tokenCredential; +Pipeline = global::System.ClientModel.Primitives.ClientPipeline.Create(options, Array.Empty(), new global::System.ClientModel.Primitives.PipelinePolicy[] { this.GetFakeTokenAuthorizationPolicy(_tokenCredential, AuthorizationScopes) }, Array.Empty()); diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/UnbrandedTypeSpecClient.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/UnbrandedTypeSpecClient.cs index 278862d6b0..0173263461 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/UnbrandedTypeSpecClient.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/UnbrandedTypeSpecClient.cs @@ -17,9 +17,9 @@ namespace UnbrandedTypeSpec public partial class UnbrandedTypeSpecClient { private readonly Uri _endpoint; - private const string AuthorizationHeader = "my-api-key"; /// A credential used to authenticate to the service. private readonly ApiKeyCredential _keyCredential; + private const string AuthorizationHeader = "my-api-key"; private readonly string _apiVersion; /// Initializes a new instance of UnbrandedTypeSpecClient for mocking.