From 743140b1133037bbf0802e86ab516fb882034dcf Mon Sep 17 00:00:00 2001 From: Matt Palmer Date: Sun, 21 Sep 2014 13:25:36 +1000 Subject: [PATCH] Make intra-doc refs work when validating with :fragment Here's a weird corner-case for you: when calling JSON::Validator.validate and using the :fragment option, any references to other parts of the same schema would fail. Why? Because the handling of :fragment involved creating a *new* schema, with a new URI, with a subset of the original schema. Internal refs (as handled by JSON::Schema::RefAttribute) would try to resolve the ref within this sub-schema, and go *fwackoom* because the structure of the sub-schema wouldn't have the right path in it. I've adjusted the code for schema_from_fragment to not call initialize_schema (and hence not create those new sub-schemas), and instead just create a new JSON::Schema object (which, according to the comments, is the only reason that initialize_schema was being called). This causes no new schemas to be created, and RefAttribute can go looking up its ref in the right place. --- lib/json-schema/validator.rb | 7 ++-- test/test_fragment_validation_with_ref.rb | 40 +++++++++++++++++++++++ test/test_helper.rb | 2 ++ 3 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 test/test_fragment_validation_with_ref.rb create mode 100644 test/test_helper.rb diff --git a/lib/json-schema/validator.rb b/lib/json-schema/validator.rb index d1f3d18b..ee69926d 100644 --- a/lib/json-schema/validator.rb +++ b/lib/json-schema/validator.rb @@ -186,6 +186,7 @@ def initialize(schema_data, data, opts={}) end def schema_from_fragment(base_schema, fragment) + schema_uri = base_schema.uri fragments = fragment.split("/") # ensure the first element was a hash, per the fragment spec @@ -198,17 +199,17 @@ def schema_from_fragment(base_schema, fragment) if !base_schema.schema.has_key?(f) raise JSON::Schema::SchemaError.new("Invalid fragment resolution for :fragment option") end - base_schema = base_schema.schema[f] + base_schema = base_schema.schema[f] elsif base_schema.is_a?(Hash) if !base_schema.has_key?(f) raise JSON::Schema::SchemaError.new("Invalid fragment resolution for :fragment option") end - base_schema = initialize_schema(base_schema[f]) #need to return a Schema instance for validation to work + base_schema = JSON::Schema.new(base_schema[f],schema_uri,@options[:version]) elsif base_schema.is_a?(Array) if base_schema[f.to_i].nil? raise JSON::Schema::SchemaError.new("Invalid fragment resolution for :fragment option") end - base_schema = initialize_schema(base_schema[f.to_i]) + base_schema = JSON::Schema.new(base_schema[f.to_i],schema_uri,@options[:version]) else raise JSON::Schema::SchemaError.new("Invalid schema encountered when resolving :fragment option") end diff --git a/test/test_fragment_validation_with_ref.rb b/test/test_fragment_validation_with_ref.rb new file mode 100644 index 00000000..3f17a955 --- /dev/null +++ b/test/test_fragment_validation_with_ref.rb @@ -0,0 +1,40 @@ +require File.expand_path('../test_helper', __FILE__) +require 'json-schema' + +class FragmentValidationWithRef < Test::Unit::TestCase + def whole_schema + { + "$schema" => "http://json-schema.org/draft-04/schema#", + "type" => "object", + "definitions" => { + "post" => { + "type" => "object", + "properties" => { + "content" => { + "type" => "string" + }, + "author" => { + "type" => "string" + } + } + }, + "posts" => { + "type" => "array", + "items" => { + "$ref" => "#/definitions/post" + } + } + } + } + end + + def test_validation_of_fragment + data = [{"content" => "ohai", "author" => "Bob"}] + v = nil + assert_nothing_raised do + v = JSON::Validator.fully_validate(whole_schema,data,:fragment => "#/definitions/posts") + end + + assert(v.empty?, v.join("\n")) + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 00000000..1acfa6a0 --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,2 @@ +require 'test/unit' +$:.unshift(File.expand_path('../../lib', __FILE__))