protected bool TestType <T>(JSchema currentSchema, JSchemaType currentType, T value) { if (!JSchemaTypeHelpers.HasFlag(currentSchema.Type, currentType)) { RaiseError($"Invalid type. Expected {currentSchema.Type.Value.GetDisplayText()} but got {currentType.GetDisplayText()}.", ErrorType.Type, currentSchema, value, null); return(false); } return(true); }
internal static bool TestType <T>(SchemaScope scope, JSchema currentSchema, JSchemaType currentType, T?value) { if (!JSchemaTypeHelpers.HasFlag(currentSchema.Type, currentType)) { scope.RaiseError($"Invalid type. Expected {currentSchema.Type.GetValueOrDefault().GetDisplayText()} but got {currentType.GetDisplayText()}.", ErrorType.Type, currentSchema, value, null); return(false); } return(true); }
protected override bool EvaluateTokenCore(JsonToken token, object value, int depth) { switch (token) { case JsonToken.Integer: { if (!ValidateInteger(Schema, value)) { return(true); } break; } case JsonToken.Float: { if (!ValidateNumber(Schema, value)) { return(true); } break; } case JsonToken.String: { Uri uri = value as Uri; string s = (uri != null) ? uri.OriginalString : value.ToString(); if (!ValidateString(Schema, s)) { return(true); } break; } case JsonToken.Boolean: { if (!ValidateBoolean(Schema, value)) { return(true); } break; } case JsonToken.Null: { if (!ValidateNull(Schema, value)) { return(true); } break; } case JsonToken.Bytes: { byte[] data = value as byte[]; if (data == null) { data = ((Guid)value).ToByteArray(); } string s = Convert.ToBase64String(data); if (!ValidateString(Schema, s)) { return(true); } break; } case JsonToken.Undefined: { JSchemaType schemaType = Schema.Type.GetValueOrDefault(JSchemaType.None); if (schemaType != JSchemaType.None) { RaiseError($"Invalid type. Expected {schemaType.GetDisplayText()} but got {token}.", ErrorType.Type, Schema, value, null); } break; } default: { throw new ArgumentOutOfRangeException("Unexpected token: " + token); } } EnsureEnum(token, value); return(true); }
protected override bool EvaluateTokenCore(JsonToken token, object value, int depth) { int relativeDepth = depth - InitialDepth; if (relativeDepth == 0) { EnsureEnum(token, value); switch (token) { case JsonToken.StartArray: EnsureValid(value); TestType(Schema, JSchemaType.Array); return(false); case JsonToken.StartConstructor: JSchemaType schemaType = Schema.Type.GetValueOrDefault(JSchemaType.None); if (schemaType != JSchemaType.None) { RaiseError($"Invalid type. Expected {schemaType.GetDisplayText()} but got Constructor.", ErrorType.Type, Schema, value, null); } return(false); case JsonToken.EndArray: case JsonToken.EndConstructor: ValidateConditionalChildren(token, value, depth); int itemCount = _index + 1; if (Schema.MaximumItems != null && itemCount > Schema.MaximumItems) { RaiseError($"Array item count {itemCount} exceeds maximum count of {Schema.MaximumItems}.", ErrorType.MaximumItems, Schema, itemCount, null); } if (Schema.MinimumItems != null && itemCount < Schema.MinimumItems) { RaiseError($"Array item count {itemCount} is less than minimum count of {Schema.MinimumItems}.", ErrorType.MinimumItems, Schema, itemCount, null); } if (Schema.Contains != null) { // MinimumContains overrides default contains behavior if (Schema.MinimumContains != null) { if (_matchCount < Schema.MinimumContains) { RaiseError($"Contains match count {_matchCount} is less than minimum contains count of {Schema.MinimumContains}.", ErrorType.MinimumContains, Schema, null, GetValidationErrors(_containsContexts)); } } else { if (_matchCount == 0) { RaiseError($"No items match contains.", ErrorType.Contains, Schema, null, GetValidationErrors(_containsContexts)); } } if (_matchCount > Schema.MaximumContains) { RaiseError($"Contains match count {_matchCount} exceeds maximum contains count of {Schema.MaximumContains}.", ErrorType.MaximumContains, Schema, null, GetValidationErrors(_containsContexts)); } } if (!_unevaluatedScopes.IsNullOrEmpty()) { foreach (KeyValuePair <int, UnevaluatedContext> item in _unevaluatedScopes) { if (!item.Value.Evaluated) { IFormattable message = $"Item at index {item.Key} has not been successfully evaluated and the schema does not allow unevaluated items."; RaiseError(message, ErrorType.UnevaluatedItems, Schema, item.Key, item.Value.SchemaScope.GetValidationErrors()); } } } return(true); default: throw new InvalidOperationException("Unexpected token when evaluating array: " + token); } } if (relativeDepth == 1) { if (JsonTokenHelpers.IsPrimitiveOrStartToken(token)) { _index++; if (Schema.UniqueItems || !Schema._validators.IsNullOrEmpty()) { if (Context.TokenWriter == null) { Context.TokenWriter = new JTokenWriter(); Context.TokenWriter.WriteToken(token, value); } } bool matched = false; if (Schema.ItemsPositionValidation) { // TODO: Remove LINQ JSchema itemSchema = Schema._items?.ElementAtOrDefault(_index); if (itemSchema != null) { CreateScopesAndEvaluateToken(token, value, depth, itemSchema); matched = true; } else { if (!Schema.AllowAdditionalItems) { RaiseError($"Index {_index + 1} has not been defined and the schema does not allow additional items.", ErrorType.AdditionalItems, Schema, value, null); } else if (Schema.AdditionalItems != null) { CreateScopesAndEvaluateToken(token, value, depth, Schema.AdditionalItems); matched = true; } } } else { if (!Schema._items.IsNullOrEmpty()) { CreateScopesAndEvaluateToken(token, value, depth, Schema._items[0]); matched = true; } } if (ShouldEvaluateContains()) { ConditionalContext containsContext = CreateConditionalContext(); _containsContexts.Add(containsContext); // contains scope should not have the current scope the parent // do not want contain failures setting the current scope's IsValid CreateScopesAndEvaluateToken(token, value, depth, Schema.Contains, null, containsContext); } if (!matched) { if (ShouldValidateUnevaluated()) { _unevaluatedScopes[_index] = Schema.UnevaluatedItems != null ? new UnevaluatedContext(CreateScopesAndEvaluateToken(token, value, depth, Schema.UnevaluatedItems, this, CreateConditionalContext())) : new UnevaluatedContext(AlwaysFalseScope.Instance); } } } if (JsonTokenHelpers.IsPrimitiveOrEndToken(token)) { if (Schema.UniqueItems) { JToken currentToken = Context.TokenWriter.CurrentToken; bool isDuplicate = JsonTokenHelpers.Contains(_uniqueArrayItems, currentToken); if (isDuplicate) { object v = (currentToken is JValue valueToken) ? valueToken.Value : currentToken; RaiseError($"Non-unique array item at index {_index}.", ErrorType.UniqueItems, Schema, v, null); } else { _uniqueArrayItems.Add(Context.TokenWriter.CurrentToken); } } if (ShouldEvaluateContains()) { ConditionalContext currentContainsContext = _containsContexts[_containsContexts.Count - 1]; if (!currentContainsContext.HasErrors) { _matchCount++; } } if (ShouldValidateUnevaluated() && _unevaluatedScopes.TryGetValue(_index, out UnevaluatedContext unevaluatedContext)) { // Property is valid against unevaluatedItems schema so no need to search further bool isValid = unevaluatedContext.SchemaScope.IsValid; unevaluatedContext.Evaluated = isValid; if (!isValid) { for (int i = Context.Scopes.Count - 1; i >= 0; i--) { Scope scope = Context.Scopes[i]; if (scope.InitialDepth == InitialDepth + 1) { // Schema for a item if (scope.Parent != null && scope is SchemaScope schemaScope && schemaScope.IsValid) { unevaluatedContext.AddValidScope(schemaScope.Parent.Schema); } } else if (scope.InitialDepth == InitialDepth) { // Schema for the current array. // Need to check these for oneOf, allOf, etc. if (scope is SchemaScope schemaScope) { if (schemaScope.Schema._allowAdditionalItems.GetValueOrDefault() || schemaScope.Schema.AdditionalItems != null || schemaScope.Schema.AllowUnevaluatedItems.GetValueOrDefault()) { unevaluatedContext.AddValidScope(schemaScope.Schema); } } } else if (scope.InitialDepth < InitialDepth) { break; } } } } } } return(false); }
protected override bool EvaluateTokenCore(JsonToken token, object value, int depth) { int relativeDepth = depth - InitialDepth; if (relativeDepth == 0) { EnsureEnum(token, value); switch (token) { case JsonToken.StartArray: EnsureValid(value); TestType(Schema, JSchemaType.Array); return(false); case JsonToken.StartConstructor: JSchemaType schemaType = Schema.Type.GetValueOrDefault(JSchemaType.None); if (schemaType != JSchemaType.None) { RaiseError($"Invalid type. Expected {schemaType.GetDisplayText()} but got Constructor.", ErrorType.Type, Schema, value, null); } return(false); case JsonToken.EndArray: case JsonToken.EndConstructor: ValidateConditionalChildren(token, value, depth); int itemCount = _index + 1; if (Schema.MaximumItems != null && itemCount > Schema.MaximumItems) { RaiseError($"Array item count {itemCount} exceeds maximum count of {Schema.MaximumItems}.", ErrorType.MaximumItems, Schema, itemCount, null); } if (Schema.MinimumItems != null && itemCount < Schema.MinimumItems) { RaiseError($"Array item count {itemCount} is less than minimum count of {Schema.MinimumItems}.", ErrorType.MinimumItems, Schema, itemCount, null); } if (Schema.Contains != null && !_matchContains) { List <ValidationError> containsErrors = new List <ValidationError>(); foreach (ConditionalContext containsContext in _containsContexts) { containsErrors.AddRange(containsContext.Errors); } RaiseError($"No items match contains.", ErrorType.Contains, Schema, null, containsErrors); } return(true); default: throw new InvalidOperationException("Unexpected token when evaluating array: " + token); } } if (relativeDepth == 1) { if (JsonTokenHelpers.IsPrimitiveOrStartToken(token)) { _index++; if (Schema.UniqueItems || !Schema._validators.IsNullOrEmpty()) { if (Context.TokenWriter == null) { Context.TokenWriter = new JTokenWriter(); Context.TokenWriter.WriteToken(token, value); } } if (Schema.ItemsPositionValidation) { JSchema itemSchema = Schema._items?.ElementAtOrDefault(_index); if (itemSchema != null) { CreateScopesAndEvaluateToken(token, value, depth, itemSchema); } else { if (!Schema.AllowAdditionalItems) { RaiseError($"Index {_index + 1} has not been defined and the schema does not allow additional items.", ErrorType.AdditionalItems, Schema, value, null); } else if (Schema.AdditionalItems != null) { CreateScopesAndEvaluateToken(token, value, depth, Schema.AdditionalItems); } } } else { if (!Schema._items.IsNullOrEmpty()) { CreateScopesAndEvaluateToken(token, value, depth, Schema._items[0]); } } // no longer need to check contains schema after match if (Schema.Contains != null && !_matchContains) { ConditionalContext containsContext = ConditionalContext.Create(Context); _containsContexts.Add(containsContext); // contains scope should not have the current scope the parent // do not want contain failures setting the current scope's IsValid CreateScopesAndEvaluateToken(token, value, depth, Schema.Contains, null, containsContext); } } if (JsonTokenHelpers.IsPrimitiveOrEndToken(token)) { if (Schema.UniqueItems) { JToken currentToken = Context.TokenWriter.CurrentToken; bool isDuplicate = JsonTokenHelpers.Contains(_uniqueArrayItems, currentToken); if (isDuplicate) { object v = (currentToken is JValue valueToken) ? valueToken.Value : currentToken; RaiseError($"Non-unique array item at index {_index}.", ErrorType.UniqueItems, Schema, v, null); } else { _uniqueArrayItems.Add(Context.TokenWriter.CurrentToken); } } if (Schema.Contains != null && !_matchContains) { ConditionalContext currentContainsContext = _containsContexts[_containsContexts.Count - 1]; if (!currentContainsContext.HasErrors) { _matchContains = true; // no longer need previous errors after match _containsContexts.Clear(); } } } } return(false); }
protected override bool EvaluateTokenCore(JsonToken token, object value, int depth) { EnsureValid(value); switch (token) { case JsonToken.Integer: { if (!ValidateInteger(Schema, value)) { return(true); } break; } case JsonToken.Float: { if (!ValidateNumber(Schema, value)) { return(true); } break; } case JsonToken.String: case JsonToken.PropertyName: { if (value == null) { // This can happen with a JTokenReader when a JValue has a String type // and a null value goto case JsonToken.Null; } string s = (value is Uri uri) ? uri.OriginalString : value.ToString(); if (!ValidateString(this, Schema, s)) { return(true); } break; } case JsonToken.Boolean: { if (!ValidateBoolean(Schema, value)) { return(true); } break; } case JsonToken.Null: { if (!ValidateNull(Schema, value)) { return(true); } break; } case JsonToken.Bytes: { byte[] data = value as byte[]; if (data == null) { data = ((Guid)value).ToByteArray(); } string s = Convert.ToBase64String(data); if (!ValidateString(this, Schema, s)) { return(true); } break; } case JsonToken.Undefined: { JSchemaType schemaType = Schema.Type.GetValueOrDefault(JSchemaType.None); if (schemaType != JSchemaType.None) { RaiseError($"Invalid type. Expected {schemaType.GetDisplayText()} but got {token}.", ErrorType.Type, Schema, value, null); } break; } default: { throw new ArgumentOutOfRangeException("Unexpected token: " + token); } } EnsureEnum(token, value); ValidateConditionalChildren(token, value, depth); return(true); }
protected override bool EvaluateTokenCore(JsonToken token, object?value, int depth) { int relativeDepth = depth - InitialDepth; if (relativeDepth == 0) { EnsureEnum(token, value); switch (token) { case JsonToken.StartArray: EnsureValid(value); TestType(Schema, JSchemaType.Array); return(false); case JsonToken.StartConstructor: JSchemaType schemaType = Schema.Type.GetValueOrDefault(JSchemaType.None); if (schemaType != JSchemaType.None) { RaiseError($"Invalid type. Expected {schemaType.GetDisplayText()} but got Constructor.", ErrorType.Type, Schema, value, null); } return(false); case JsonToken.EndArray: case JsonToken.EndConstructor: ValidateConditionalChildren(token, value, depth); int itemCount = _index + 1; if (Schema.MaximumItems != null && itemCount > Schema.MaximumItems) { RaiseError($"Array item count {itemCount} exceeds maximum count of {Schema.MaximumItems}.", ErrorType.MaximumItems, Schema, itemCount, null); } if (Schema.MinimumItems != null && itemCount < Schema.MinimumItems) { RaiseError($"Array item count {itemCount} is less than minimum count of {Schema.MinimumItems}.", ErrorType.MinimumItems, Schema, itemCount, null); } if (Schema.Contains != null) { ValidationUtils.Assert(_containsContexts != null); // MinimumContains overrides default contains behavior if (Schema.MinimumContains != null) { if (_matchCount < Schema.MinimumContains) { RaiseError($"Contains match count {_matchCount} is less than minimum contains count of {Schema.MinimumContains}.", ErrorType.MinimumContains, Schema, null, GetValidationErrors(_containsContexts)); } } else { if (_matchCount == 0) { RaiseError($"No items match contains.", ErrorType.Contains, Schema, null, GetValidationErrors(_containsContexts)); } } if (_matchCount > Schema.MaximumContains) { RaiseError($"Contains match count {_matchCount} exceeds maximum contains count of {Schema.MaximumContains}.", ErrorType.MaximumContains, Schema, null, GetValidationErrors(_containsContexts)); } } if (!_unevaluatedScopes.IsNullOrEmpty()) { foreach (KeyValuePair <int, UnevaluatedContext> item in _unevaluatedScopes) { if (!item.Value.Evaluated) { IFormattable message = $"Item at index {item.Key} has not been successfully evaluated and the schema does not allow unevaluated items."; RaiseError(message, ErrorType.UnevaluatedItems, Schema, item.Key, item.Value.SchemaScope.GetValidationErrors()); } } } return(true); default: throw new InvalidOperationException("Unexpected token when evaluating array: " + token); } } if (relativeDepth == 1) { if (JsonTokenHelpers.IsPrimitiveOrStartToken(token)) { _index++; if (Schema.UniqueItems || !Schema._validators.IsNullOrEmpty()) { if (Context.TokenWriter == null) { Context.TokenWriter = new JTokenWriter(); Context.TokenWriter.WriteToken(token, value); } } bool matched = false; if (Schema.ItemsPositionValidation) { // TODO: Remove LINQ JSchema?itemSchema = Schema._items?.ElementAtOrDefault(_index); if (itemSchema != null) { CreateScopesAndEvaluateToken(token, value, depth, itemSchema); matched = true; } else { if (!Schema.AllowAdditionalItems) { RaiseError($"Index {_index + 1} has not been defined and the schema does not allow additional items.", ErrorType.AdditionalItems, Schema, value, null); } else if (Schema.AdditionalItems != null) { CreateScopesAndEvaluateToken(token, value, depth, Schema.AdditionalItems); matched = true; } } } else { if (!Schema._items.IsNullOrEmpty()) { CreateScopesAndEvaluateToken(token, value, depth, Schema._items[0]); matched = true; } } if (ShouldEvaluateContains()) { ConditionalContext containsContext = CreateConditionalContext(); _containsContexts.Add(containsContext); // contains scope should not have the current scope the parent // do not want contain failures setting the current scope's IsValid CreateScopesAndEvaluateToken(token, value, depth, Schema.Contains !, null, containsContext); } if (!matched) { if (ShouldValidateUnevaluated()) { _unevaluatedScopes ![_index] = Schema.UnevaluatedItems != null
protected override bool EvaluateTokenCore(JsonToken token, object value, int depth) { int relativeDepth = depth - InitialDepth; if (relativeDepth == 0) { EnsureEnum(token, value); switch (token) { case JsonToken.StartArray: TestType(Schema, JSchemaType.Array); return(false); case JsonToken.StartConstructor: JSchemaType schemaType = Schema.Type.GetValueOrDefault(JSchemaType.None); if (schemaType != JSchemaType.None) { RaiseError($"Invalid type. Expected {schemaType.GetDisplayText()} but got Constructor.", ErrorType.Type, Schema, value, null); } return(false); case JsonToken.EndArray: case JsonToken.EndConstructor: int itemCount = _index + 1; if (Schema.MaximumItems != null && itemCount > Schema.MaximumItems) { RaiseError($"Array item count {itemCount} exceeds maximum count of {Schema.MaximumItems}.", ErrorType.MaximumItems, Schema, itemCount, null); } if (Schema.MinimumItems != null && itemCount < Schema.MinimumItems) { RaiseError($"Array item count {itemCount} is less than minimum count of {Schema.MinimumItems}.", ErrorType.MinimumItems, Schema, itemCount, null); } return(true); default: throw new InvalidOperationException("Unexpected token when evaluating array: " + token); } } if (relativeDepth == 1) { if (JsonTokenHelpers.IsPrimitiveOrStartToken(token)) { _index++; if (Schema.UniqueItems || !Schema._validators.IsNullOrEmpty()) { if (Context.TokenWriter == null) { Context.TokenWriter = new JTokenWriter(); Context.TokenWriter.WriteToken(token, value); } } if (Schema.ItemsPositionValidation) { JSchema itemSchema = (Schema._items != null) ? Schema._items.ElementAtOrDefault(_index) : null; if (itemSchema != null) { CreateScopesAndEvaluateToken(token, value, depth, itemSchema); } else { if (!Schema.AllowAdditionalItems) { RaiseError($"Index {_index + 1} has not been defined and the schema does not allow additional items.", ErrorType.AdditionalItems, Schema, value, null); } else if (Schema.AdditionalItems != null) { CreateScopesAndEvaluateToken(token, value, depth, Schema.AdditionalItems); } } } else { if (!Schema._items.IsNullOrEmpty()) { CreateScopesAndEvaluateToken(token, value, depth, Schema._items[0]); } } } if (JsonTokenHelpers.IsPrimitiveOrEndToken(token)) { if (Schema.UniqueItems) { JToken currentToken = Context.TokenWriter.CurrentToken; bool isDuplicate = JsonTokenHelpers.Contains(_uniqueArrayItems, currentToken); if (isDuplicate) { object v = (currentToken is JValue) ? ((JValue)currentToken).Value : currentToken; RaiseError($"Non-unique array item at index {_index}.", ErrorType.UniqueItems, Schema, v, null); } else { _uniqueArrayItems.Add(Context.TokenWriter.CurrentToken); } } } } return(false); }