From 9a943497940d8ed4a8f13deca57ea4e40f8a4877 Mon Sep 17 00:00:00 2001 From: Luc Genetier Date: Sun, 21 Jan 2024 17:01:21 +0100 Subject: [PATCH 1/5] Add ValidationRuleSet.Remove --- .../Rules/OpenApiComponentsRules.cs | 2 +- .../Validations/Rules/OpenApiContactRules.cs | 2 +- .../Validations/Rules/OpenApiDocumentRules.cs | 2 +- .../Rules/OpenApiExtensionRules.cs | 2 +- .../Rules/OpenApiExternalDocsRules.cs | 2 +- .../Validations/Rules/OpenApiHeaderRules.cs | 2 +- .../Validations/Rules/OpenApiInfoRules.cs | 2 +- .../Validations/Rules/OpenApiLicenseRules.cs | 2 +- .../Rules/OpenApiMediaTypeRules.cs | 2 +- .../Rules/OpenApiOAuthFlowRules.cs | 2 +- .../Rules/OpenApiParameterRules.cs | 8 +++---- .../Validations/Rules/OpenApiPathsRules.cs | 4 ++-- .../Validations/Rules/OpenApiResponseRules.cs | 2 +- .../Rules/OpenApiResponsesRules.cs | 6 ++--- .../Validations/Rules/OpenApiSchemaRules.cs | 4 ++-- .../Validations/Rules/OpenApiServerRules.cs | 2 +- .../Validations/Rules/OpenApiTagRules.cs | 2 +- .../Validations/ValidationRule.cs | 24 +++++++++++++++++-- .../Validations/ValidationRuleSet.cs | 22 +++++++++++++++++ .../PublicApi/PublicApi.approved.txt | 4 ++++ .../Services/OpenApiValidatorTests.cs | 12 +++++++++- .../OpenApiReferenceValidationTests.cs | 2 +- 22 files changed, 84 insertions(+), 28 deletions(-) diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiComponentsRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiComponentsRules.cs index f2f3a649c..93eba5c71 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiComponentsRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiComponentsRules.cs @@ -24,7 +24,7 @@ public static class OpenApiComponentsRules /// that MUST use keys that match the regular expression: ^[a-zA-Z0-9\.\-_]+$. /// public static ValidationRule KeyMustBeRegularExpression => - new( + new(nameof(KeyMustBeRegularExpression), (context, components) => { ValidateKeys(context, components.Schemas?.Keys, "schemas"); diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiContactRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiContactRules.cs index cfa8d9927..e31dc1e07 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiContactRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiContactRules.cs @@ -17,7 +17,7 @@ public static class OpenApiContactRules /// Email field MUST be email address. /// public static ValidationRule EmailMustBeEmailFormat => - new( + new(nameof(EmailMustBeEmailFormat), (context, item) => { context.Enter("email"); diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiDocumentRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiDocumentRules.cs index be0dc1538..f38e2530f 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiDocumentRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiDocumentRules.cs @@ -17,7 +17,7 @@ public static class OpenApiDocumentRules /// The Info field is required. /// public static ValidationRule OpenApiDocumentFieldIsMissing => - new( + new(nameof(OpenApiDocumentFieldIsMissing), (context, item) => { // info diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiExtensionRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiExtensionRules.cs index 5d124e8de..890be82d7 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiExtensionRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiExtensionRules.cs @@ -17,7 +17,7 @@ public static class OpenApiExtensibleRules /// Extension name MUST start with "x-". /// public static ValidationRule ExtensionNameMustStartWithXDash => - new( + new(nameof(ExtensionNameMustStartWithXDash), (context, item) => { context.Enter("extensions"); diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiExternalDocsRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiExternalDocsRules.cs index ff4fde4a2..1754dbee2 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiExternalDocsRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiExternalDocsRules.cs @@ -17,7 +17,7 @@ public static class OpenApiExternalDocsRules /// Validate the field is required. /// public static ValidationRule UrlIsRequired => - new( + new(nameof(UrlIsRequired), (context, item) => { // url diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiHeaderRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiHeaderRules.cs index c446a7b56..194e426cc 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiHeaderRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiHeaderRules.cs @@ -16,7 +16,7 @@ public static class OpenApiHeaderRules /// Validate the data matches with the given data type. /// public static ValidationRule HeaderMismatchedDataType => - new( + new(nameof(HeaderMismatchedDataType), (context, header) => { // example diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiInfoRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiInfoRules.cs index 88b534c02..337bf8687 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiInfoRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiInfoRules.cs @@ -17,7 +17,7 @@ public static class OpenApiInfoRules /// Validate the field is required. /// public static ValidationRule InfoRequiredFields => - new( + new(nameof(InfoRequiredFields), (context, item) => { // title diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiLicenseRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiLicenseRules.cs index edbf19bf5..08f67d209 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiLicenseRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiLicenseRules.cs @@ -17,7 +17,7 @@ public static class OpenApiLicenseRules /// REQUIRED. /// public static ValidationRule LicenseRequiredFields => - new( + new(nameof(LicenseRequiredFields), (context, license) => { context.Enter("name"); diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiMediaTypeRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiMediaTypeRules.cs index 6f7b65a6c..7ac09cbbf 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiMediaTypeRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiMediaTypeRules.cs @@ -24,7 +24,7 @@ public static class OpenApiMediaTypeRules /// Validate the data matches with the given data type. /// public static ValidationRule MediaTypeMismatchedDataType => - new( + new(nameof(MediaTypeMismatchedDataType), (context, mediaType) => { // example diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiOAuthFlowRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiOAuthFlowRules.cs index de31d933d..c6db49d7c 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiOAuthFlowRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiOAuthFlowRules.cs @@ -17,7 +17,7 @@ public static class OpenApiOAuthFlowRules /// Validate the field is required. /// public static ValidationRule OAuthFlowRequiredFields => - new( + new(nameof(OAuthFlowRequiredFields), (context, flow) => { // authorizationUrl diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs index 5c19ce1d9..a1a228134 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs @@ -17,7 +17,7 @@ public static class OpenApiParameterRules /// Validate the field is required. /// public static ValidationRule ParameterRequiredFields => - new( + new(nameof(ParameterRequiredFields), (context, item) => { // name @@ -43,7 +43,7 @@ public static class OpenApiParameterRules /// Validate the "required" field is true when "in" is path. /// public static ValidationRule RequiredMustBeTrueWhenInIsPath => - new( + new(nameof(RequiredMustBeTrueWhenInIsPath), (context, item) => { // required @@ -62,7 +62,7 @@ public static class OpenApiParameterRules /// Validate the data matches with the given data type. /// public static ValidationRule ParameterMismatchedDataType => - new( + new(nameof(ParameterMismatchedDataType), (context, parameter) => { // example @@ -100,7 +100,7 @@ public static class OpenApiParameterRules /// Validate that a path parameter should always appear in the path /// public static ValidationRule PathParameterShouldBeInThePath => - new( + new(nameof(PathParameterShouldBeInThePath), (context, parameter) => { if (parameter.In == ParameterLocation.Path && diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiPathsRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiPathsRules.cs index d248edb3c..9c23f7220 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiPathsRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiPathsRules.cs @@ -18,7 +18,7 @@ public static class OpenApiPathsRules /// A relative path to an individual endpoint. The field name MUST begin with a slash. /// public static ValidationRule PathNameMustBeginWithSlash => - new( + new(nameof(PathNameMustBeginWithSlash), (context, item) => { foreach (var pathName in item.Keys) @@ -39,7 +39,7 @@ public static class OpenApiPathsRules /// A relative path to an individual endpoint. The field name MUST begin with a slash. /// public static ValidationRule PathMustBeUnique => - new ValidationRule( + new ValidationRule(nameof(PathMustBeUnique), (context, item) => { var hashSet = new HashSet(); diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiResponseRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiResponseRules.cs index 0f725c90e..f30b49ea0 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiResponseRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiResponseRules.cs @@ -17,7 +17,7 @@ public static class OpenApiResponseRules /// Validate the field is required. /// public static ValidationRule ResponseRequiredFields => - new( + new(nameof(ResponseRequiredFields), (context, response) => { // description diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiResponsesRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiResponsesRules.cs index 1afe9a388..a2b91dc31 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiResponsesRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiResponsesRules.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System.Linq; @@ -17,7 +17,7 @@ public static class OpenApiResponsesRules /// An OpenAPI operation must contain at least one response /// public static ValidationRule ResponsesMustContainAtLeastOneResponse => - new( + new(nameof(ResponsesMustContainAtLeastOneResponse), (context, responses) => { if (!responses.Keys.Any()) @@ -31,7 +31,7 @@ public static class OpenApiResponsesRules /// The response key must either be "default" or an HTTP status code (1xx, 2xx, 3xx, 4xx, 5xx). /// public static ValidationRule ResponsesMustBeIdentifiedByDefaultOrStatusCode => - new( + new(nameof(ResponsesMustBeIdentifiedByDefaultOrStatusCode), (context, responses) => { foreach (var key in responses.Keys) diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs index a936766c8..411f26fd0 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs @@ -17,7 +17,7 @@ public static class OpenApiSchemaRules /// Validate the data matches with the given data type. /// public static ValidationRule SchemaMismatchedDataType => - new( + new(nameof(SchemaMismatchedDataType), (context, schema) => { // default @@ -60,7 +60,7 @@ public static class OpenApiSchemaRules /// Validates Schema Discriminator /// public static ValidationRule ValidateSchemaDiscriminator => - new( + new(nameof(ValidateSchemaDiscriminator), (context, schema) => { // discriminator diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiServerRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiServerRules.cs index 292fd1fd0..dd11a661d 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiServerRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiServerRules.cs @@ -17,7 +17,7 @@ public static class OpenApiServerRules /// Validate the field is required. /// public static ValidationRule ServerRequiredFields => - new( + new(nameof(ServerRequiredFields), (context, server) => { context.Enter("url"); diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiTagRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiTagRules.cs index f28732e1e..cc006f971 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiTagRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiTagRules.cs @@ -17,7 +17,7 @@ public static class OpenApiTagRules /// Validate the field is required. /// public static ValidationRule TagRequiredFields => - new( + new(nameof(TagRequiredFields), (context, tag) => { context.Enter("name"); diff --git a/src/Microsoft.OpenApi/Validations/ValidationRule.cs b/src/Microsoft.OpenApi/Validations/ValidationRule.cs index 48907635d..9f5c78105 100644 --- a/src/Microsoft.OpenApi/Validations/ValidationRule.cs +++ b/src/Microsoft.OpenApi/Validations/ValidationRule.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. using System; -using System.Globalization; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Properties; @@ -18,6 +17,11 @@ public abstract class ValidationRule /// internal abstract Type ElementType { get; } + /// + /// Validation rule Name. + /// + public abstract string Name { get; } + /// /// Validate the object. /// @@ -36,13 +40,29 @@ public class ValidationRule : ValidationRule where T : IOpenApiElement /// /// Initializes a new instance of the class. - /// + /// /// Action to perform the validation. public ValidationRule(Action validate) + : this (null, validate) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Validation rule name. + /// Action to perform the validation. + public ValidationRule(string name, Action validate) { _validate = Utils.CheckArgumentNull(validate); + Name = name ?? "UnnamedRule"; } + /// + /// Validation Rule Name. + /// + public override string Name { get; } + internal override Type ElementType { get { return typeof(T); } diff --git a/src/Microsoft.OpenApi/Validations/ValidationRuleSet.cs b/src/Microsoft.OpenApi/Validations/ValidationRuleSet.cs index a5c6fee83..4f578b0fb 100644 --- a/src/Microsoft.OpenApi/Validations/ValidationRuleSet.cs +++ b/src/Microsoft.OpenApi/Validations/ValidationRuleSet.cs @@ -134,6 +134,28 @@ public void Add(ValidationRule rule) item.Add(rule); } + /// + /// Remove a rule by name. + /// + /// Name of the rule. + public void Remove(string ruleName) + { + foreach (KeyValuePair> rule in _rules) + { + var validationRule = rule.Value.FirstOrDefault(vr => vr.Name.Equals(ruleName, StringComparison.Ordinal)); + if (validationRule != null) + { + rule.Value.Remove(validationRule); + } + } + + var r = _rules.FirstOrDefault(kvp => !kvp.Value.Any()); + if (r.Key != null) + { + _rules.Remove(r.Key); + } + } + /// /// Get the enumerator. /// diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index a5309e46d..79425084f 100755 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -1348,6 +1348,7 @@ namespace Microsoft.OpenApi.Validations public abstract class ValidationRule { protected ValidationRule() { } + public abstract string Name { get; } } public sealed class ValidationRuleSet : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable { @@ -1358,6 +1359,7 @@ namespace Microsoft.OpenApi.Validations public void Add(Microsoft.OpenApi.Validations.ValidationRule rule) { } public System.Collections.Generic.IList FindRules(System.Type type) { } public System.Collections.Generic.IEnumerator GetEnumerator() { } + public void Remove(string ruleName) { } public static Microsoft.OpenApi.Validations.ValidationRuleSet GetDefaultRuleSet() { } public static Microsoft.OpenApi.Validations.ValidationRuleSet GetEmptyRuleSet() { } } @@ -1365,6 +1367,8 @@ namespace Microsoft.OpenApi.Validations where T : Microsoft.OpenApi.Interfaces.IOpenApiElement { public ValidationRule(System.Action validate) { } + public ValidationRule(string name, System.Action validate) { } + public override string Name { get; } } } namespace Microsoft.OpenApi.Validations.Rules diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiValidatorTests.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiValidatorTests.cs index 02eba9347..75f5543aa 100644 --- a/test/Microsoft.OpenApi.Tests/Services/OpenApiValidatorTests.cs +++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiValidatorTests.cs @@ -96,7 +96,7 @@ public void ValidateCustomExtension() var ruleset = ValidationRuleSet.GetDefaultRuleSet(); ruleset.Add( - new ValidationRule( + new ValidationRule("FooExtensionRule", (context, item) => { if (item.Bar == "hey") @@ -133,6 +133,16 @@ public void ValidateCustomExtension() new OpenApiValidatorError("FooExtensionRule", "#/info/x-foo", "Don't say hey") }); } + + [Fact] + public void RemoveRule() + { + var ruleset = ValidationRuleSet.GetDefaultRuleSet(); + int expected = ruleset.Rules.Count - 1; + ruleset.Remove("KeyMustBeRegularExpression"); + + Assert.Equal(expected, ruleset.Rules.Count); + } } internal class FooExtension : IOpenApiExtension, IOpenApiElement diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs index 4c252716f..11e5edc9e 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs @@ -152,7 +152,7 @@ public void UnresolvedSchemaReferencedShouldNotBeValidated() public class AlwaysFailRule : ValidationRule where T : IOpenApiElement { - public AlwaysFailRule() : base((c, _) => c.CreateError("x", "y")) + public AlwaysFailRule() : base("AlwaysFailRule", (c, _) => c.CreateError("x", "y")) { } } From 01e3a602be4e73639a885c7b648c8f216cf937c8 Mon Sep 17 00:00:00 2001 From: Luc Genetier Date: Mon, 22 Jan 2024 21:51:18 +0100 Subject: [PATCH 2/5] Updates following Vincent's comments --- .../Validations/ValidationRule.cs | 19 ++++++++++--------- .../Validations/ValidationRuleSet.cs | 13 +++---------- .../PublicApi/PublicApi.approved.txt | 5 ++--- 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/src/Microsoft.OpenApi/Validations/ValidationRule.cs b/src/Microsoft.OpenApi/Validations/ValidationRule.cs index 9f5c78105..b8e9a8055 100644 --- a/src/Microsoft.OpenApi/Validations/ValidationRule.cs +++ b/src/Microsoft.OpenApi/Validations/ValidationRule.cs @@ -20,7 +20,7 @@ public abstract class ValidationRule /// /// Validation rule Name. /// - public abstract string Name { get; } + public string Name { get; } /// /// Validate the object. @@ -28,6 +28,11 @@ public abstract class ValidationRule /// The context. /// The object item. internal abstract void Evaluate(IValidationContext context, object item); + + internal ValidationRule(string name) + { + Name = name; + } } /// @@ -37,11 +42,12 @@ public abstract class ValidationRule public class ValidationRule : ValidationRule where T : IOpenApiElement { private readonly Action _validate; - + /// /// Initializes a new instance of the class. /// /// Action to perform the validation. + [Obsolete("Please use the other constructor and specify a name")] public ValidationRule(Action validate) : this (null, validate) { @@ -53,16 +59,11 @@ public ValidationRule(Action validate) /// Validation rule name. /// Action to perform the validation. public ValidationRule(string name, Action validate) + : base(name) { - _validate = Utils.CheckArgumentNull(validate); - Name = name ?? "UnnamedRule"; + _validate = Utils.CheckArgumentNull(validate); } - /// - /// Validation Rule Name. - /// - public override string Name { get; } - internal override Type ElementType { get { return typeof(T); } diff --git a/src/Microsoft.OpenApi/Validations/ValidationRuleSet.cs b/src/Microsoft.OpenApi/Validations/ValidationRuleSet.cs index 4f578b0fb..4128e22ea 100644 --- a/src/Microsoft.OpenApi/Validations/ValidationRuleSet.cs +++ b/src/Microsoft.OpenApi/Validations/ValidationRuleSet.cs @@ -142,18 +142,11 @@ public void Remove(string ruleName) { foreach (KeyValuePair> rule in _rules) { - var validationRule = rule.Value.FirstOrDefault(vr => vr.Name.Equals(ruleName, StringComparison.Ordinal)); - if (validationRule != null) - { - rule.Value.Remove(validationRule); - } + _rules[rule.Key] = rule.Value.Where(vr => !vr.Name.Equals(ruleName, StringComparison.Ordinal)).ToList(); } - var r = _rules.FirstOrDefault(kvp => !kvp.Value.Any()); - if (r.Key != null) - { - _rules.Remove(r.Key); - } + // Remove types with no rule + _rules = _rules.Where(r => r.Value.Any()).ToDictionary(r => r.Key, r => r.Value); } /// diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 79425084f..5f893bee0 100755 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -1347,8 +1347,7 @@ namespace Microsoft.OpenApi.Validations } public abstract class ValidationRule { - protected ValidationRule() { } - public abstract string Name { get; } + public string Name { get; } } public sealed class ValidationRuleSet : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable { @@ -1366,9 +1365,9 @@ namespace Microsoft.OpenApi.Validations public class ValidationRule : Microsoft.OpenApi.Validations.ValidationRule where T : Microsoft.OpenApi.Interfaces.IOpenApiElement { + [System.Obsolete("Please use the other constructor and specify a name")] public ValidationRule(System.Action validate) { } public ValidationRule(string name, System.Action validate) { } - public override string Name { get; } } } namespace Microsoft.OpenApi.Validations.Rules From cefbe9f50f6e8349499162910af0dd34e39faa58 Mon Sep 17 00:00:00 2001 From: Luc Genetier Date: Sun, 21 Jan 2024 17:01:21 +0100 Subject: [PATCH 3/5] Updates following Vincent's comments Add ValidationRuleSet.Remove --- .../Rules/OpenApiComponentsRules.cs | 2 +- .../Validations/Rules/OpenApiContactRules.cs | 2 +- .../Validations/Rules/OpenApiDocumentRules.cs | 2 +- .../Rules/OpenApiExtensionRules.cs | 2 +- .../Rules/OpenApiExternalDocsRules.cs | 2 +- .../Validations/Rules/OpenApiHeaderRules.cs | 2 +- .../Validations/Rules/OpenApiInfoRules.cs | 2 +- .../Validations/Rules/OpenApiLicenseRules.cs | 2 +- .../Rules/OpenApiMediaTypeRules.cs | 2 +- .../Rules/OpenApiOAuthFlowRules.cs | 2 +- .../Rules/OpenApiParameterRules.cs | 8 +++--- .../Validations/Rules/OpenApiPathsRules.cs | 4 +-- .../Validations/Rules/OpenApiResponseRules.cs | 2 +- .../Rules/OpenApiResponsesRules.cs | 6 ++--- .../Validations/Rules/OpenApiSchemaRules.cs | 4 +-- .../Validations/Rules/OpenApiServerRules.cs | 2 +- .../Validations/Rules/OpenApiTagRules.cs | 2 +- .../Validations/ValidationRule.cs | 27 ++++++++++++++++--- .../Validations/ValidationRuleSet.cs | 15 +++++++++++ .../PublicApi/PublicApi.approved.txt | 5 +++- .../Services/OpenApiValidatorTests.cs | 12 ++++++++- .../OpenApiReferenceValidationTests.cs | 2 +- 22 files changed, 79 insertions(+), 30 deletions(-) diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiComponentsRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiComponentsRules.cs index f2f3a649c..93eba5c71 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiComponentsRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiComponentsRules.cs @@ -24,7 +24,7 @@ public static class OpenApiComponentsRules /// that MUST use keys that match the regular expression: ^[a-zA-Z0-9\.\-_]+$. /// public static ValidationRule KeyMustBeRegularExpression => - new( + new(nameof(KeyMustBeRegularExpression), (context, components) => { ValidateKeys(context, components.Schemas?.Keys, "schemas"); diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiContactRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiContactRules.cs index cfa8d9927..e31dc1e07 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiContactRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiContactRules.cs @@ -17,7 +17,7 @@ public static class OpenApiContactRules /// Email field MUST be email address. /// public static ValidationRule EmailMustBeEmailFormat => - new( + new(nameof(EmailMustBeEmailFormat), (context, item) => { context.Enter("email"); diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiDocumentRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiDocumentRules.cs index be0dc1538..f38e2530f 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiDocumentRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiDocumentRules.cs @@ -17,7 +17,7 @@ public static class OpenApiDocumentRules /// The Info field is required. /// public static ValidationRule OpenApiDocumentFieldIsMissing => - new( + new(nameof(OpenApiDocumentFieldIsMissing), (context, item) => { // info diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiExtensionRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiExtensionRules.cs index 5d124e8de..890be82d7 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiExtensionRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiExtensionRules.cs @@ -17,7 +17,7 @@ public static class OpenApiExtensibleRules /// Extension name MUST start with "x-". /// public static ValidationRule ExtensionNameMustStartWithXDash => - new( + new(nameof(ExtensionNameMustStartWithXDash), (context, item) => { context.Enter("extensions"); diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiExternalDocsRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiExternalDocsRules.cs index ff4fde4a2..1754dbee2 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiExternalDocsRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiExternalDocsRules.cs @@ -17,7 +17,7 @@ public static class OpenApiExternalDocsRules /// Validate the field is required. /// public static ValidationRule UrlIsRequired => - new( + new(nameof(UrlIsRequired), (context, item) => { // url diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiHeaderRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiHeaderRules.cs index c446a7b56..194e426cc 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiHeaderRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiHeaderRules.cs @@ -16,7 +16,7 @@ public static class OpenApiHeaderRules /// Validate the data matches with the given data type. /// public static ValidationRule HeaderMismatchedDataType => - new( + new(nameof(HeaderMismatchedDataType), (context, header) => { // example diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiInfoRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiInfoRules.cs index 88b534c02..337bf8687 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiInfoRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiInfoRules.cs @@ -17,7 +17,7 @@ public static class OpenApiInfoRules /// Validate the field is required. /// public static ValidationRule InfoRequiredFields => - new( + new(nameof(InfoRequiredFields), (context, item) => { // title diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiLicenseRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiLicenseRules.cs index edbf19bf5..08f67d209 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiLicenseRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiLicenseRules.cs @@ -17,7 +17,7 @@ public static class OpenApiLicenseRules /// REQUIRED. /// public static ValidationRule LicenseRequiredFields => - new( + new(nameof(LicenseRequiredFields), (context, license) => { context.Enter("name"); diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiMediaTypeRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiMediaTypeRules.cs index 6f7b65a6c..7ac09cbbf 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiMediaTypeRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiMediaTypeRules.cs @@ -24,7 +24,7 @@ public static class OpenApiMediaTypeRules /// Validate the data matches with the given data type. /// public static ValidationRule MediaTypeMismatchedDataType => - new( + new(nameof(MediaTypeMismatchedDataType), (context, mediaType) => { // example diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiOAuthFlowRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiOAuthFlowRules.cs index de31d933d..c6db49d7c 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiOAuthFlowRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiOAuthFlowRules.cs @@ -17,7 +17,7 @@ public static class OpenApiOAuthFlowRules /// Validate the field is required. /// public static ValidationRule OAuthFlowRequiredFields => - new( + new(nameof(OAuthFlowRequiredFields), (context, flow) => { // authorizationUrl diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs index 5c19ce1d9..a1a228134 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs @@ -17,7 +17,7 @@ public static class OpenApiParameterRules /// Validate the field is required. /// public static ValidationRule ParameterRequiredFields => - new( + new(nameof(ParameterRequiredFields), (context, item) => { // name @@ -43,7 +43,7 @@ public static class OpenApiParameterRules /// Validate the "required" field is true when "in" is path. /// public static ValidationRule RequiredMustBeTrueWhenInIsPath => - new( + new(nameof(RequiredMustBeTrueWhenInIsPath), (context, item) => { // required @@ -62,7 +62,7 @@ public static class OpenApiParameterRules /// Validate the data matches with the given data type. /// public static ValidationRule ParameterMismatchedDataType => - new( + new(nameof(ParameterMismatchedDataType), (context, parameter) => { // example @@ -100,7 +100,7 @@ public static class OpenApiParameterRules /// Validate that a path parameter should always appear in the path /// public static ValidationRule PathParameterShouldBeInThePath => - new( + new(nameof(PathParameterShouldBeInThePath), (context, parameter) => { if (parameter.In == ParameterLocation.Path && diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiPathsRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiPathsRules.cs index d248edb3c..9c23f7220 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiPathsRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiPathsRules.cs @@ -18,7 +18,7 @@ public static class OpenApiPathsRules /// A relative path to an individual endpoint. The field name MUST begin with a slash. /// public static ValidationRule PathNameMustBeginWithSlash => - new( + new(nameof(PathNameMustBeginWithSlash), (context, item) => { foreach (var pathName in item.Keys) @@ -39,7 +39,7 @@ public static class OpenApiPathsRules /// A relative path to an individual endpoint. The field name MUST begin with a slash. /// public static ValidationRule PathMustBeUnique => - new ValidationRule( + new ValidationRule(nameof(PathMustBeUnique), (context, item) => { var hashSet = new HashSet(); diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiResponseRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiResponseRules.cs index 0f725c90e..f30b49ea0 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiResponseRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiResponseRules.cs @@ -17,7 +17,7 @@ public static class OpenApiResponseRules /// Validate the field is required. /// public static ValidationRule ResponseRequiredFields => - new( + new(nameof(ResponseRequiredFields), (context, response) => { // description diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiResponsesRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiResponsesRules.cs index 1afe9a388..a2b91dc31 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiResponsesRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiResponsesRules.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System.Linq; @@ -17,7 +17,7 @@ public static class OpenApiResponsesRules /// An OpenAPI operation must contain at least one response /// public static ValidationRule ResponsesMustContainAtLeastOneResponse => - new( + new(nameof(ResponsesMustContainAtLeastOneResponse), (context, responses) => { if (!responses.Keys.Any()) @@ -31,7 +31,7 @@ public static class OpenApiResponsesRules /// The response key must either be "default" or an HTTP status code (1xx, 2xx, 3xx, 4xx, 5xx). /// public static ValidationRule ResponsesMustBeIdentifiedByDefaultOrStatusCode => - new( + new(nameof(ResponsesMustBeIdentifiedByDefaultOrStatusCode), (context, responses) => { foreach (var key in responses.Keys) diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs index a936766c8..411f26fd0 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs @@ -17,7 +17,7 @@ public static class OpenApiSchemaRules /// Validate the data matches with the given data type. /// public static ValidationRule SchemaMismatchedDataType => - new( + new(nameof(SchemaMismatchedDataType), (context, schema) => { // default @@ -60,7 +60,7 @@ public static class OpenApiSchemaRules /// Validates Schema Discriminator /// public static ValidationRule ValidateSchemaDiscriminator => - new( + new(nameof(ValidateSchemaDiscriminator), (context, schema) => { // discriminator diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiServerRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiServerRules.cs index 292fd1fd0..dd11a661d 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiServerRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiServerRules.cs @@ -17,7 +17,7 @@ public static class OpenApiServerRules /// Validate the field is required. /// public static ValidationRule ServerRequiredFields => - new( + new(nameof(ServerRequiredFields), (context, server) => { context.Enter("url"); diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiTagRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiTagRules.cs index f28732e1e..cc006f971 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiTagRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiTagRules.cs @@ -17,7 +17,7 @@ public static class OpenApiTagRules /// Validate the field is required. /// public static ValidationRule TagRequiredFields => - new( + new(nameof(TagRequiredFields), (context, tag) => { context.Enter("name"); diff --git a/src/Microsoft.OpenApi/Validations/ValidationRule.cs b/src/Microsoft.OpenApi/Validations/ValidationRule.cs index 48907635d..b8e9a8055 100644 --- a/src/Microsoft.OpenApi/Validations/ValidationRule.cs +++ b/src/Microsoft.OpenApi/Validations/ValidationRule.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. using System; -using System.Globalization; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Properties; @@ -18,12 +17,22 @@ public abstract class ValidationRule /// internal abstract Type ElementType { get; } + /// + /// Validation rule Name. + /// + public string Name { get; } + /// /// Validate the object. /// /// The context. /// The object item. internal abstract void Evaluate(IValidationContext context, object item); + + internal ValidationRule(string name) + { + Name = name; + } } /// @@ -33,14 +42,26 @@ public abstract class ValidationRule public class ValidationRule : ValidationRule where T : IOpenApiElement { private readonly Action _validate; + + /// + /// Initializes a new instance of the class. + /// + /// Action to perform the validation. + [Obsolete("Please use the other constructor and specify a name")] + public ValidationRule(Action validate) + : this (null, validate) + { + } /// /// Initializes a new instance of the class. /// + /// Validation rule name. /// Action to perform the validation. - public ValidationRule(Action validate) + public ValidationRule(string name, Action validate) + : base(name) { - _validate = Utils.CheckArgumentNull(validate); + _validate = Utils.CheckArgumentNull(validate); } internal override Type ElementType diff --git a/src/Microsoft.OpenApi/Validations/ValidationRuleSet.cs b/src/Microsoft.OpenApi/Validations/ValidationRuleSet.cs index a5c6fee83..4128e22ea 100644 --- a/src/Microsoft.OpenApi/Validations/ValidationRuleSet.cs +++ b/src/Microsoft.OpenApi/Validations/ValidationRuleSet.cs @@ -134,6 +134,21 @@ public void Add(ValidationRule rule) item.Add(rule); } + /// + /// Remove a rule by name. + /// + /// Name of the rule. + public void Remove(string ruleName) + { + foreach (KeyValuePair> rule in _rules) + { + _rules[rule.Key] = rule.Value.Where(vr => !vr.Name.Equals(ruleName, StringComparison.Ordinal)).ToList(); + } + + // Remove types with no rule + _rules = _rules.Where(r => r.Value.Any()).ToDictionary(r => r.Key, r => r.Value); + } + /// /// Get the enumerator. /// diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index a5309e46d..5f893bee0 100755 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -1347,7 +1347,7 @@ namespace Microsoft.OpenApi.Validations } public abstract class ValidationRule { - protected ValidationRule() { } + public string Name { get; } } public sealed class ValidationRuleSet : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable { @@ -1358,13 +1358,16 @@ namespace Microsoft.OpenApi.Validations public void Add(Microsoft.OpenApi.Validations.ValidationRule rule) { } public System.Collections.Generic.IList FindRules(System.Type type) { } public System.Collections.Generic.IEnumerator GetEnumerator() { } + public void Remove(string ruleName) { } public static Microsoft.OpenApi.Validations.ValidationRuleSet GetDefaultRuleSet() { } public static Microsoft.OpenApi.Validations.ValidationRuleSet GetEmptyRuleSet() { } } public class ValidationRule : Microsoft.OpenApi.Validations.ValidationRule where T : Microsoft.OpenApi.Interfaces.IOpenApiElement { + [System.Obsolete("Please use the other constructor and specify a name")] public ValidationRule(System.Action validate) { } + public ValidationRule(string name, System.Action validate) { } } } namespace Microsoft.OpenApi.Validations.Rules diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiValidatorTests.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiValidatorTests.cs index 02eba9347..75f5543aa 100644 --- a/test/Microsoft.OpenApi.Tests/Services/OpenApiValidatorTests.cs +++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiValidatorTests.cs @@ -96,7 +96,7 @@ public void ValidateCustomExtension() var ruleset = ValidationRuleSet.GetDefaultRuleSet(); ruleset.Add( - new ValidationRule( + new ValidationRule("FooExtensionRule", (context, item) => { if (item.Bar == "hey") @@ -133,6 +133,16 @@ public void ValidateCustomExtension() new OpenApiValidatorError("FooExtensionRule", "#/info/x-foo", "Don't say hey") }); } + + [Fact] + public void RemoveRule() + { + var ruleset = ValidationRuleSet.GetDefaultRuleSet(); + int expected = ruleset.Rules.Count - 1; + ruleset.Remove("KeyMustBeRegularExpression"); + + Assert.Equal(expected, ruleset.Rules.Count); + } } internal class FooExtension : IOpenApiExtension, IOpenApiElement diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs index 4c252716f..11e5edc9e 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs @@ -152,7 +152,7 @@ public void UnresolvedSchemaReferencedShouldNotBeValidated() public class AlwaysFailRule : ValidationRule where T : IOpenApiElement { - public AlwaysFailRule() : base((c, _) => c.CreateError("x", "y")) + public AlwaysFailRule() : base("AlwaysFailRule", (c, _) => c.CreateError("x", "y")) { } } From d8419f22351c831c65184540f4ad392622c69ae0 Mon Sep 17 00:00:00 2001 From: Luc Genetier Date: Wed, 24 Jan 2024 14:22:06 +0100 Subject: [PATCH 4/5] Update --- .../Validations/ValidationRule.cs | 5 +-- .../Validations/ValidationRuleSet.cs | 9 ++++++ .../PublicApi/PublicApi.approved.txt | 1 + .../Services/OpenApiValidatorTests.cs | 31 ++++++++++++++++++- 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.OpenApi/Validations/ValidationRule.cs b/src/Microsoft.OpenApi/Validations/ValidationRule.cs index b8e9a8055..4f0f00383 100644 --- a/src/Microsoft.OpenApi/Validations/ValidationRule.cs +++ b/src/Microsoft.OpenApi/Validations/ValidationRule.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using System; +using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Properties; @@ -31,7 +32,7 @@ public abstract class ValidationRule internal ValidationRule(string name) { - Name = name; + Name = !string.IsNullOrEmpty(name) ? name : throw new ArgumentNullException(nameof(name)); } } @@ -49,7 +50,7 @@ public class ValidationRule : ValidationRule where T : IOpenApiElement /// Action to perform the validation. [Obsolete("Please use the other constructor and specify a name")] public ValidationRule(Action validate) - : this (null, validate) + : this (Guid.NewGuid().ToString("D"), validate) { } diff --git a/src/Microsoft.OpenApi/Validations/ValidationRuleSet.cs b/src/Microsoft.OpenApi/Validations/ValidationRuleSet.cs index 4128e22ea..264bad6a9 100644 --- a/src/Microsoft.OpenApi/Validations/ValidationRuleSet.cs +++ b/src/Microsoft.OpenApi/Validations/ValidationRuleSet.cs @@ -149,6 +149,15 @@ public void Remove(string ruleName) _rules = _rules.Where(r => r.Value.Any()).ToDictionary(r => r.Key, r => r.Value); } + /// + /// Remove a rule by type. + /// + /// Type of the rule. + public void Remove(Type type) + { + _rules.Remove(type); + } + /// /// Get the enumerator. /// diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 5f893bee0..e0abf365a 100755 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -1359,6 +1359,7 @@ namespace Microsoft.OpenApi.Validations public System.Collections.Generic.IList FindRules(System.Type type) { } public System.Collections.Generic.IEnumerator GetEnumerator() { } public void Remove(string ruleName) { } + public void Remove(System.Type type) { } public static Microsoft.OpenApi.Validations.ValidationRuleSet GetDefaultRuleSet() { } public static Microsoft.OpenApi.Validations.ValidationRuleSet GetEmptyRuleSet() { } } diff --git a/test/Microsoft.OpenApi.Tests/Services/OpenApiValidatorTests.cs b/test/Microsoft.OpenApi.Tests/Services/OpenApiValidatorTests.cs index 75f5543aa..d027f40b8 100644 --- a/test/Microsoft.OpenApi.Tests/Services/OpenApiValidatorTests.cs +++ b/test/Microsoft.OpenApi.Tests/Services/OpenApiValidatorTests.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using FluentAssertions; +using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Properties; @@ -135,13 +136,41 @@ public void ValidateCustomExtension() } [Fact] - public void RemoveRule() + public void RemoveRuleByName_Invalid() + { + Assert.Throws(() => new ValidationRule(null, (vc, oaa) => { })); + Assert.Throws(() => new ValidationRule(string.Empty, (vc, oaa) => { })); + } + + [Fact] + public void RemoveRuleByName() { var ruleset = ValidationRuleSet.GetDefaultRuleSet(); int expected = ruleset.Rules.Count - 1; ruleset.Remove("KeyMustBeRegularExpression"); Assert.Equal(expected, ruleset.Rules.Count); + + ruleset.Remove("KeyMustBeRegularExpression"); + ruleset.Remove("UnknownName"); + + Assert.Equal(expected, ruleset.Rules.Count); + } + + [Fact] + public void RemoveRuleByType() + { + var ruleset = ValidationRuleSet.GetDefaultRuleSet(); + int expected = ruleset.Rules.Count - 1; + + ruleset.Remove(typeof(OpenApiComponents)); + + Assert.Equal(expected, ruleset.Rules.Count); + + ruleset.Remove(typeof(OpenApiComponents)); + ruleset.Remove(typeof(int)); + + Assert.Equal(expected, ruleset.Rules.Count); } } From e2b0aa3752c5445156eb3f86202d9a3180ebf4c8 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Wed, 24 Jan 2024 08:27:03 -0500 Subject: [PATCH 5/5] Apply suggestions from code review --- src/Microsoft.OpenApi/Validations/ValidationRuleSet.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.OpenApi/Validations/ValidationRuleSet.cs b/src/Microsoft.OpenApi/Validations/ValidationRuleSet.cs index 264bad6a9..3dd916755 100644 --- a/src/Microsoft.OpenApi/Validations/ValidationRuleSet.cs +++ b/src/Microsoft.OpenApi/Validations/ValidationRuleSet.cs @@ -135,7 +135,7 @@ public void Add(ValidationRule rule) } /// - /// Remove a rule by name. + /// Remove a rule by its name from all types it is used by. /// /// Name of the rule. public void Remove(string ruleName) @@ -150,7 +150,7 @@ public void Remove(string ruleName) } /// - /// Remove a rule by type. + /// Remove a rule by element type. /// /// Type of the rule. public void Remove(Type type)