Exemplo n.º 1
0
        /// <summary>
        /// Provides the validation logic for this keyword.
        /// </summary>
        /// <param name="context">The context object.</param>
        /// <returns>Results object containing a final result and any errors that may have been found.</returns>
        public SchemaValidationResults Validate(SchemaValidationContext context)
        {
            if (context.Instance.Type != JsonValueType.Array)
            {
                return(new SchemaValidationResults(Name, context));
            }

            var itemsKeyword = context.Local.Get <ItemsKeyword?>();

            if (itemsKeyword == null || !itemsKeyword.IsArray)
            {
                return(new SchemaValidationResults(Name, context));
            }

            var nestedResults     = new List <SchemaValidationResults>();
            var array             = context.Instance.Array;
            var results           = new SchemaValidationResults(Name, context);
            var valid             = true;
            var reportChildErrors = context.Options.ShouldReportChildErrors(this, context);
            var startIndex        = context.LocalTierLastEvaluatedIndex + 1;
            var failedIndices     = new JsonArray();

            Log.Schema(() => startIndex == 0
                                                   ? "No indices have been evaluated; process all"
                                                   : $"Indices up to {context.LastEvaluatedIndex} have been evaluated; skipping these");
            if (startIndex < array.Count)
            {
                if (Value == JsonSchema.False)
                {
                    Log.Schema(() => $"Subschema is `false`; all instances after index {startIndex} are invalid");
                    results.IsValid = false;
                    results.Keyword = Name;
                    results.AdditionalInfo["indices"] = Enumerable.Range(startIndex, array.Count - startIndex).ToJson();
                    results.ErrorMessage = ErrorTemplate_False.ResolveTokens(results.AdditionalInfo);
                    return(results);
                }

                var eligibleItems = array.Skip(startIndex);
                var index         = startIndex;
                foreach (var item in eligibleItems)
                {
                    var baseRelativeLocation = context.BaseRelativeLocation?.CloneAndAppend(Name);
                    var relativeLocation     = context.RelativeLocation.CloneAndAppend(Name);
                    var newContext           = new SchemaValidationContext(context)
                    {
                        Instance             = item,
                        BaseRelativeLocation = baseRelativeLocation,
                        RelativeLocation     = relativeLocation,
                        InstanceLocation     = context.InstanceLocation.CloneAndAppend(index.ToString()),
                    };
                    var localResults = Value.Validate(newContext);
                    if (!localResults.IsValid)
                    {
                        failedIndices.Add(index);
                    }
                    else if (context.ShouldTrackValidatedValues)
                    {
                        newContext.LocallyValidatedIndices.Add(index);
                    }
                    valid &= localResults.IsValid;
                    context.LastEvaluatedIndex          = Math.Max(context.LastEvaluatedIndex, index);
                    context.LocalTierLastEvaluatedIndex = Math.Max(context.LastEvaluatedIndex, index);
                    context.UpdateEvaluatedPropertiesAndItemsFromSubschemaValidation(newContext);

                    index++;

                    if (context.Options.OutputFormat == SchemaValidationOutputFormat.Flag)
                    {
                        if (!valid)
                        {
                            Log.Schema(() => "Subschema failed; halting validation early");
                            break;
                        }
                    }
                    else if (reportChildErrors)
                    {
                        nestedResults.Add(localResults);
                    }
                }
            }
            else
            {
                Log.Schema(() => "All items have been validated");
            }
            results.NestedResults = nestedResults;
            results.IsValid       = valid;
            results.Keyword       = Name;

            if (!valid)
            {
                results.AdditionalInfo["indices"] = failedIndices;
                results.ErrorMessage = ErrorTemplate.ResolveTokens(results.AdditionalInfo);
            }

            return(results);
        }
        /// <summary>
        /// Provides the validation logic for this keyword.
        /// </summary>
        /// <param name="context">The context object.</param>
        /// <returns>Results object containing a final result and any errors that may have been found.</returns>
        public SchemaValidationResults Validate(SchemaValidationContext context)
        {
            if (context.Instance.Type != JsonValueType.Object)
            {
                Log.Schema(() => "Instance not an object; not applicable");
                return(new SchemaValidationResults(Name, context));
            }

            var obj        = context.Instance.Object;
            var results    = new SchemaValidationResults(Name, context);
            var toEvaluate = obj.Where(kvp => !context.LocallyEvaluatedPropertyNames.Contains(kvp.Key)) !.ToJson();

            if (toEvaluate.Count == 0)
            {
                Log.Schema(() => "All properties have been evaluated");
                return(results);
            }

            Log.Schema(() => context.LocallyEvaluatedPropertyNames.Count == 0
                                                         ? "No properties have been evaluated; process all"
                                                         : $"Properties {context.LocallyEvaluatedPropertyNames.ToJson()} have been evaluated; skipping these");
            if (Value == JsonSchema.False && toEvaluate.Any())
            {
                Log.Schema(() => "Subschema is `false`; all instances invalid");
                results.IsValid = false;
                results.Keyword = Name;
                results.AdditionalInfo["properties"] = toEvaluate.Keys.ToJson();
                results.ErrorMessage = ErrorTemplate_False.ResolveTokens(results.AdditionalInfo);
                return(results);
            }

            var valid             = true;
            var reportChildErrors = context.Options.ShouldReportChildErrors(this, context);
            var nestedResults     = new List <SchemaValidationResults>();
            var failedProperties  = new JsonArray();

            foreach (var kvp in toEvaluate)
            {
                if (context.ShouldTrackValidatedValues)
                {
                    context.EvaluatedPropertyNames.Add(kvp.Key);
                }

                context.LocallyEvaluatedPropertyNames.Add(kvp.Key);
                var newContext = new SchemaValidationContext(context)
                {
                    Instance             = kvp.Value,
                    BaseRelativeLocation = context.BaseRelativeLocation?.CloneAndAppend(Name),
                    RelativeLocation     = context.RelativeLocation.CloneAndAppend(Name),
                    InstanceLocation     = context.InstanceLocation.CloneAndAppend(kvp.Key),
                };
                var localResults = Value.Validate(newContext);
                if (!localResults.IsValid)
                {
                    failedProperties.Add(kvp.Key);
                }
                else
                {
                    if (context.ShouldTrackValidatedValues)
                    {
                        newContext.LocallyEvaluatedPropertyNames.Add(kvp.Key);
                    }
                    context.UpdateEvaluatedPropertiesAndItemsFromSubschemaValidation(newContext);
                }

                valid &= localResults.IsValid;

                if (context.Options.OutputFormat == SchemaValidationOutputFormat.Flag)
                {
                    if (!valid)
                    {
                        Log.Schema(() => "Subschema failed; halting validation early");
                        break;
                    }
                }
                else if (reportChildErrors)
                {
                    nestedResults.Add(localResults);
                }
            }

            results.NestedResults = nestedResults;

            if (!valid || nestedResults.Any(r => !r.IsValid))
            {
                results.IsValid = false;
                results.Keyword = Name;
                results.AdditionalInfo["properties"] = failedProperties;
                results.ErrorMessage = ErrorTemplate.ResolveTokens(results.AdditionalInfo);
            }

            return(results);
        }