From 78bcdd47e18b3ce510261e26deac32030261db80 Mon Sep 17 00:00:00 2001 From: Dominic Collart Date: Thu, 1 Oct 2020 19:25:52 +0200 Subject: [PATCH 1/3] Add validation rule (+ test) to create an error when a path parameter does not appear in the path. --- .../Rules/OpenApiParameterRules.cs | 16 ++++ .../OpenApiParameterValidationTests.cs | 74 +++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs index d1ad41781..7f1a8ec04 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs @@ -96,6 +96,22 @@ public static class OpenApiParameterRules context.Exit(); }); + /// + /// Validate that a path parameter should always appear in the path + /// + public static ValidationRule PathParameterShouldBeInThePath => + new ValidationRule( + (context, parameter) => + { + if (parameter.In == ParameterLocation.Path && !context.PathString.Contains("{" + parameter.Name + "}")) + { + context.Enter("in"); + context.CreateError( + nameof(PathParameterShouldBeInThePath), + $"Declared path parameter \"{parameter.Name}\" needs to be defined as a path parameter at either the path or operation level"); + context.Exit(); + } + }); // add more rule. } } diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs index 667286f0a..a447c1f2a 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs @@ -173,5 +173,79 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() "#/examples/example2/value" }); } + + [Fact] + public void PathParameterNotInThePathShouldReturnAnError() + { + // Arrange + IEnumerable errors; + + var parameter = new OpenApiParameter() + { + Name = "parameter1", + In = ParameterLocation.Path, + Required = true, + Schema = new OpenApiSchema() + { + Type = "string", + } + }; + + // Act + var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet()); + validator.Enter("1"); + + var walker = new OpenApiWalker(validator); + walker.Walk(parameter); + + errors = validator.Errors; + bool result = errors.Any(); + + // Assert + result.Should().BeTrue(); + errors.OfType().Select(e => e.RuleName).Should().BeEquivalentTo(new[] + { + "PathParameterShouldBeInThePath" + }); + errors.Select(e => e.Pointer).Should().BeEquivalentTo(new[] + { + "#/1/in" + }); + } + + [Fact] + public void PathParameterInThePastShouldBeOk() + { + // Arrange + IEnumerable errors; + + var parameter = new OpenApiParameter() + { + Name = "parameter1", + In = ParameterLocation.Path, + Required = true, + Schema = new OpenApiSchema() + { + Type = "string", + } + }; + + // Act + var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet()); + validator.Enter("paths"); + validator.Enter("/{parameter1}"); + validator.Enter("get"); + validator.Enter("parameters"); + validator.Enter("1"); + + var walker = new OpenApiWalker(validator); + walker.Walk(parameter); + + errors = validator.Errors; + bool result = errors.Any(); + + // Assert + result.Should().BeFalse(); + } } } From 481d3bca0462b3c0560e38f9de6491c6b3f3462a Mon Sep 17 00:00:00 2001 From: Dominic Collart Date: Thu, 1 Oct 2020 19:35:58 +0200 Subject: [PATCH 2/3] Fix other tests --- .../OpenApiParameterValidationTests.cs | 20 +++++++++++-------- .../Validations/ValidationRuleSetTests.cs | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs index a447c1f2a..41a9a6ab0 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs @@ -48,8 +48,11 @@ public void ValidateRequiredIsTrueWhenInIsPathInParameter() }; // Act - var errors = parameter.Validate(ValidationRuleSet.GetDefaultRuleSet()); - + var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet()); + validator.Enter("{name}"); + var walker = new OpenApiWalker(validator); + walker.Walk(parameter); + var errors = validator.Errors; // Assert errors.Should().NotBeEmpty(); errors.Select(e => e.Message).Should().BeEquivalentTo(new[] @@ -77,6 +80,7 @@ public void ValidateExampleShouldNotHaveDataTypeMismatchForSimpleSchema() // Act var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet()); + validator.Enter("{parameter1}"); var walker = new OpenApiWalker(validator); walker.Walk(parameter); @@ -91,7 +95,7 @@ public void ValidateExampleShouldNotHaveDataTypeMismatchForSimpleSchema() }); errors.Select(e => e.Pointer).Should().BeEquivalentTo(new[] { - "#/example", + "#/{parameter1}/example", }); } @@ -150,6 +154,7 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() // Act var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet()); + validator.Enter("{parameter1}"); var walker = new OpenApiWalker(validator); walker.Walk(parameter); @@ -168,9 +173,9 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() { // #enum/0 is not an error since the spec allows // representing an object using a string. - "#/examples/example1/value/y", - "#/examples/example1/value/z", - "#/examples/example2/value" + "#/{parameter1}/examples/example1/value/y", + "#/{parameter1}/examples/example1/value/z", + "#/{parameter1}/examples/example2/value" }); } @@ -193,7 +198,6 @@ public void PathParameterNotInThePathShouldReturnAnError() // Act var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet()); - validator.Enter("1"); var walker = new OpenApiWalker(validator); walker.Walk(parameter); @@ -209,7 +213,7 @@ public void PathParameterNotInThePathShouldReturnAnError() }); errors.Select(e => e.Pointer).Should().BeEquivalentTo(new[] { - "#/1/in" + "#/in" }); } diff --git a/test/Microsoft.OpenApi.Tests/Validations/ValidationRuleSetTests.cs b/test/Microsoft.OpenApi.Tests/Validations/ValidationRuleSetTests.cs index af259cf1b..8153e6054 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/ValidationRuleSetTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/ValidationRuleSetTests.cs @@ -43,7 +43,7 @@ public void DefaultRuleSetPropertyReturnsTheCorrectRules() Assert.NotEmpty(rules); // Update the number if you add new default rule(s). - Assert.Equal(21, rules.Count); + Assert.Equal(22, rules.Count); } } } From 92d5c3dfd062a0ab4d876e63d75a11d8bca55019 Mon Sep 17 00:00:00 2001 From: Darrel Miller Date: Sat, 15 May 2021 17:11:43 -0400 Subject: [PATCH 3/3] Added new rule to public API --- test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index e5fd82d46..fe73c25c7 100755 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -1169,6 +1169,7 @@ namespace Microsoft.OpenApi.Validations.Rules { public static Microsoft.OpenApi.Validations.ValidationRule ParameterMismatchedDataType { get; } public static Microsoft.OpenApi.Validations.ValidationRule ParameterRequiredFields { get; } + public static Microsoft.OpenApi.Validations.ValidationRule PathParameterShouldBeInThePath { get; } public static Microsoft.OpenApi.Validations.ValidationRule RequiredMustBeTrueWhenInIsPath { get; } } [Microsoft.OpenApi.Validations.Rules.OpenApiRule]