diff --git a/src/Microsoft.OpenApi/Properties/SRResource.Designer.cs b/src/Microsoft.OpenApi/Properties/SRResource.Designer.cs
index bd42672a5..eb88eab6f 100644
--- a/src/Microsoft.OpenApi/Properties/SRResource.Designer.cs
+++ b/src/Microsoft.OpenApi/Properties/SRResource.Designer.cs
@@ -383,7 +383,16 @@ internal static string Validation_RuleAddTwice {
return ResourceManager.GetString("Validation_RuleAddTwice", resourceCulture);
}
}
-
+
+ ///
+ /// Looks up a localized string similar to Schema {0} property {1} is null..
+ ///
+ internal static string Validation_SchemaPropertyObjectRequired {
+ get {
+ return ResourceManager.GetString("Validation_SchemaPropertyObjectRequired", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to The schema reference '{0}' does not point to an existing schema..
///
diff --git a/src/Microsoft.OpenApi/Properties/SRResource.resx b/src/Microsoft.OpenApi/Properties/SRResource.resx
index b758ff89b..c2e953ec4 100644
--- a/src/Microsoft.OpenApi/Properties/SRResource.resx
+++ b/src/Microsoft.OpenApi/Properties/SRResource.resx
@@ -219,6 +219,9 @@
Schema {0} must contain property specified in the discriminator {1} in the required field list.
+
+ Schema {0} property {1} is null.
+
The string '{0}' MUST be in the format of an email address.
diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs
index 826eaa031..81a4ab88f 100644
--- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs
+++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs
@@ -5,12 +5,37 @@
namespace Microsoft.OpenApi
{
+ using System.Linq;
+
///
/// The validation rules for .
///
[OpenApiRule]
public static class OpenApiSchemaRules
{
+ ///
+ /// Validates Schema Property has value
+ ///
+ public static ValidationRule ValidateSchemaPropertyHasValue =>
+ new(nameof(ValidateSchemaPropertyHasValue),
+ (context, schema) =>
+ {
+ if (schema.Properties is not null)
+ {
+ foreach (var property in schema.Properties
+ .Where(entry => entry.Value is null))
+ {
+ context.Enter(property.Key);
+ context.CreateError(nameof(ValidateSchemaPropertyHasValue),
+ string.Format(SRResource.Validation_SchemaPropertyObjectRequired,
+ schema is OpenApiSchemaReference { Reference: not null } schemaReference
+ ? schemaReference.Reference.Id
+ : string.Empty, property.Key));
+ context.Exit();
+ }
+ }
+ });
+
///
/// Validates Schema Discriminator
///
diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt
index f8d83d291..5733eb735 100644
--- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt
+++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt
@@ -1248,6 +1248,7 @@ namespace Microsoft.OpenApi
public static class OpenApiSchemaRules
{
public static Microsoft.OpenApi.ValidationRule ValidateSchemaDiscriminator { get; }
+ public static Microsoft.OpenApi.ValidationRule ValidateSchemaPropertyHasValue { get; }
public static bool TraverseSchemaElements(string discriminatorName, System.Collections.Generic.IList? childSchema) { }
public static bool ValidateChildSchemaAgainstDiscriminator(Microsoft.OpenApi.IOpenApiSchema schema, string? discriminatorName) { }
}
diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs
index 028913e37..f22806825 100644
--- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs
+++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs
@@ -174,6 +174,44 @@ public void ValidateDefaultShouldNotHaveDataTypeMismatchForComplexSchema()
// Assert
Assert.NotEmpty(validator.Warnings);
}
+
+ [Fact]
+ public void ValidateNullProperty()
+ {
+ // Arrange
+ var components = new OpenApiComponents
+ {
+ Schemas = new Dictionary
+ {
+ {
+ "schema1",
+ new OpenApiSchema
+ {
+ Properties = new Dictionary
+ {
+ ["property1"] = null,
+ }
+ }
+ }
+ }
+ };
+
+ // Act
+ var defaultRuleSet = ValidationRuleSet.GetDefaultRuleSet();
+ defaultRuleSet.Add(typeof(IOpenApiSchema), OpenApiNonDefaultRules.SchemaMismatchedDataType);
+ var validator = new OpenApiValidator(defaultRuleSet);
+ var walker = new OpenApiWalker(validator);
+ walker.Walk(components);
+
+ // Assert
+ Assert.NotEmpty(validator.Errors);
+ Assert.Equivalent(new List
+ {
+ new OpenApiValidatorError(nameof(OpenApiSchemaRules.ValidateSchemaPropertyHasValue),"#/schemas/schema1/property1",
+ string.Format(SRResource.Validation_SchemaPropertyObjectRequired,
+ string.Empty, "property1"))
+ }, validator.Errors);
+ }
[Fact]
public void ValidateSchemaRequiredFieldListMustContainThePropertySpecifiedInTheDiscriminator()
diff --git a/test/Microsoft.OpenApi.Tests/Validations/ValidationRuleSetTests.cs b/test/Microsoft.OpenApi.Tests/Validations/ValidationRuleSetTests.cs
index e1414232e..50cf77a1f 100644
--- a/test/Microsoft.OpenApi.Tests/Validations/ValidationRuleSetTests.cs
+++ b/test/Microsoft.OpenApi.Tests/Validations/ValidationRuleSetTests.cs
@@ -53,8 +53,8 @@ public void RuleSetConstructorsReturnsTheCorrectRules()
Assert.Empty(ruleSet_4.Rules);
// Update the number if you add new default rule(s).
- Assert.Equal(20, ruleSet_1.Rules.Count);
- Assert.Equal(20, ruleSet_2.Rules.Count);
+ Assert.Equal(21, ruleSet_1.Rules.Count);
+ Assert.Equal(21, ruleSet_2.Rules.Count);
Assert.Equal(3, ruleSet_3.Rules.Count);
}