diff --git a/AutoRest/Generators/AzureResourceSchema/AzureResourceSchema.Tests/ResourceSchemaParserTests.cs b/AutoRest/Generators/AzureResourceSchema/AzureResourceSchema.Tests/ResourceSchemaParserTests.cs index 4c90684e6a852..cb5c18ebb77de 100644 --- a/AutoRest/Generators/AzureResourceSchema/AzureResourceSchema.Tests/ResourceSchemaParserTests.cs +++ b/AutoRest/Generators/AzureResourceSchema/AzureResourceSchema.Tests/ResourceSchemaParserTests.cs @@ -171,15 +171,121 @@ public void IsCreateResourceMethodWhenUrlDoesntEndWithResourceNamePlaceholder() } [Fact] - public void GetResourceTypeWithOneLevelOfResources() + public void GetResourceTypesWithOneLevelOfResources() { - Assert.Equal("Microsoft.Cdn/profiles", ResourceSchemaParser.GetResourceType("Microsoft.Cdn", "profiles/{profileName}")); + Assert.Equal(new string[] { "Microsoft.Cdn/profiles" }, ResourceSchemaParser.GetResourceTypes("Microsoft.Cdn", "profiles/{profileName}", new List())); } [Fact] - public void GetResourceTypeWithMultipleLevelsOfResources() + public void GetResourceTypesWithMultipleLevelsOfResources() { - Assert.Equal("Microsoft.Cdn/profiles/endpoints/customDomains", ResourceSchemaParser.GetResourceType("Microsoft.Cdn", "profiles/{profileName}/endpoints/{endpointName}/customDomains/{customDomainName}")); + Assert.Equal(new string[] { "Microsoft.Cdn/profiles/endpoints/customDomains" }, ResourceSchemaParser.GetResourceTypes("Microsoft.Cdn", "profiles/{profileName}/endpoints/{endpointName}/customDomains/{customDomainName}", new List())); + } + + [Fact] + public void GetResourceTypesParameterReferenceWithNoMatchingParameterDefinition() + { + const string provider = "Microsoft.Network"; + const string pathAfterProvider = "dnszones/{zoneName}/{recordType}/{relativeRecordSetName}"; + List methodParameters = new List(); + Assert.Throws(() => { ResourceSchemaParser.GetResourceTypes(provider, pathAfterProvider, methodParameters); }); + } + + [Fact] + public void GetResourceTypesWithParameterReferenceWithParameterDefinitionWithNoType() + { + const string provider = "Microsoft.Network"; + const string pathAfterProvider = "dnszones/{zoneName}/{recordType}/{relativeRecordSetName}"; + List methodParameters = new List() + { + new Parameter() + { + Name = "recordType" + } + }; + Assert.Throws(() => { ResourceSchemaParser.GetResourceTypes(provider, pathAfterProvider, methodParameters); }); + } + + [Fact] + public void GetResourceTypesWithParameterReferenceWithParameterDefinitionWithPrimaryType() + { + const string provider = "Microsoft.Network"; + const string pathAfterProvider = "dnszones/{zoneName}/{recordType}/{relativeRecordSetName}"; + List methodParameters = new List() + { + new Parameter() + { + Name = "recordType", + Type = new PrimaryType(KnownPrimaryType.String) + } + }; + Assert.Throws(() => { ResourceSchemaParser.GetResourceTypes(provider, pathAfterProvider, methodParameters); }); + } + + [Fact] + public void GetResourceTypesWithParameterReferenceWithParameterDefinitionWithEnumTypeWithNoValues() + { + const string provider = "Microsoft.Network"; + const string pathAfterProvider = "dnszones/{zoneName}/{recordType}/{relativeRecordSetName}"; + List methodParameters = new List() + { + new Parameter() + { + Name = "recordType", + Type = new EnumType() + } + }; + Assert.Throws(() => { ResourceSchemaParser.GetResourceTypes(provider, pathAfterProvider, methodParameters); }); + } + + [Fact] + public void GetResourceTypesWithParameterReferenceWithParameterDefinitionWithEnumTypeWithOneValue() + { + const string provider = "Microsoft.Network"; + const string pathAfterProvider = "dnszones/{zoneName}/{recordType}/{relativeRecordSetName}"; + EnumType enumType = new EnumType(); + enumType.Values.Add(new EnumValue() + { + Name = "A" + }); + List methodParameters = new List() + { + new Parameter() + { + Name = "recordType", + Type = enumType + } + }; + Assert.Equal(new string[] { "Microsoft.Network/dnszones/A" }, ResourceSchemaParser.GetResourceTypes(provider, pathAfterProvider, methodParameters)); + } + + [Fact] + public void GetResourceTypesWithParameterReferenceWithParameterDefinitionWithEnumTypeWithMultipleValues() + { + const string provider = "Microsoft.Network"; + const string pathAfterProvider = "dnszones/{zoneName}/{recordType}/{relativeRecordSetName}"; + EnumType enumType = new EnumType(); + enumType.Values.Add(new EnumValue() { Name = "A" }); + enumType.Values.Add(new EnumValue() { Name = "AAAA" }); + enumType.Values.Add(new EnumValue() { Name = "CNAME" }); + enumType.Values.Add(new EnumValue() { Name = "MX" }); + List methodParameters = new List() + { + new Parameter() + { + Name = "recordType", + Type = enumType + } + }; + Assert.Equal( + new string[] + { + "Microsoft.Network/dnszones/A", + "Microsoft.Network/dnszones/AAAA", + "Microsoft.Network/dnszones/CNAME", + "Microsoft.Network/dnszones/MX" + }, + ResourceSchemaParser.GetResourceTypes(provider, pathAfterProvider, methodParameters)); } private static Method CreateMethod(HttpMethod httpMethod = HttpMethod.Put, Parameter body = null, IType responseBody = null, string url = null) diff --git a/AutoRest/Generators/AzureResourceSchema/AzureResourceSchema/ResourceSchemaParser.cs b/AutoRest/Generators/AzureResourceSchema/AzureResourceSchema/ResourceSchemaParser.cs index 1e98e8f9507b2..8e0ee9a13461f 100644 --- a/AutoRest/Generators/AzureResourceSchema/AzureResourceSchema/ResourceSchemaParser.cs +++ b/AutoRest/Generators/AzureResourceSchema/AzureResourceSchema/ResourceSchemaParser.cs @@ -74,7 +74,7 @@ public static IDictionary Parse(ServiceClient serviceClie } string methodUrlPathAfterProvider = afterPrefix.Substring(forwardSlashIndexAfterProvider + 1); - string resourceType = GetResourceType(resourceProvider, methodUrlPathAfterProvider); + string resourceType = GetResourceTypes(resourceProvider, methodUrlPathAfterProvider, createResourceMethod.Parameters)[0]; resourceDefinition.AddProperty("type", new JsonSchema() { @@ -397,8 +397,9 @@ public static bool IsCreateResourceMethod(Method method) /// /// /// + /// /// - public static string GetResourceType(string resourceProvider, string methodPathAfterProvider) + public static string[] GetResourceTypes(string resourceProvider, string methodPathAfterProvider, List createResourceMethodParameters) { if (string.IsNullOrWhiteSpace(resourceProvider)) { @@ -409,16 +410,63 @@ public static string GetResourceType(string resourceProvider, string methodPathA throw new ArgumentException("methodPathAfterProvider cannot be null or whitespace", "methodPathAfterProvider"); } - List resourceTypeParts = new List(); - resourceTypeParts.Add(resourceProvider); + List resourceTypes = new List(); + resourceTypes.Add(resourceProvider); string[] pathSegments = methodPathAfterProvider.Split(new char[] { '/' }); for (int i = 0; i < pathSegments.Length; i += 2) { - resourceTypeParts.Add(pathSegments[i]); + string pathSegment = pathSegments[i]; + if (pathSegment.StartsWith("{") && pathSegment.EndsWith("}")) + { + string parameterName = pathSegment.Substring(1, pathSegment.Length - 2); + Parameter parameter = createResourceMethodParameters.FirstOrDefault(methodParameter => methodParameter.Name == parameterName); + if (parameter == null) + { + string errorMessage = string.Format("Found undefined parameter reference {0} in create resource method \"{1}/{2}/{3}\".", pathSegment, resourceMethodPrefix, resourceProvider, methodPathAfterProvider); + throw new ArgumentException(errorMessage, "createResourceMethodParameters"); + } + + if (parameter.Type == null) + { + string errorMessage = string.Format("Parameter reference {0} has no defined type.", pathSegment); + throw new ArgumentException(errorMessage, "createResourceMethodParameters"); + } + + EnumType parameterType = parameter.Type as EnumType; + if (parameterType == null) + { + string errorMessage = string.Format("Parameter reference {0} is defined as a type other than an EnumType: {1}", pathSegment, parameter.Type.GetType().Name); + throw new ArgumentException(errorMessage, "createResourceMethodParameters"); + } + + if (parameterType.Values == null || parameterType.Values.Count == 0) + { + string errorMessage = string.Format("Parameter reference {0} is defined as an EnumType, but it doesn't have any specified values.", pathSegment); + throw new ArgumentException(errorMessage, "createResourceMethodParameters"); + } + + List newResourceTypes = new List(); + foreach (string resourceType in resourceTypes) + { + foreach (EnumValue parameterValue in parameterType.Values) + { + newResourceTypes.Add(string.Join("/", resourceType, parameterValue.Name)); + } + } + + resourceTypes = newResourceTypes; + } + else + { + for (int j = 0; j < resourceTypes.Count; ++j) + { + resourceTypes[j] = string.Join("/", resourceTypes[j], pathSegment); + } + } } - return string.Join("/", resourceTypeParts); + return resourceTypes.ToArray(); } } }