Skip to content

Commit

Permalink
Make intra-doc refs work when validating with :fragment
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mpalmer committed Sep 21, 2014
1 parent bf0cde9 commit 743140b
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 3 deletions.
7 changes: 4 additions & 3 deletions lib/json-schema/validator.rb
Expand Up @@ -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
Expand All @@ -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
Expand Down
40 changes: 40 additions & 0 deletions 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
2 changes: 2 additions & 0 deletions test/test_helper.rb
@@ -0,0 +1,2 @@
require 'test/unit'
$:.unshift(File.expand_path('../../lib', __FILE__))

0 comments on commit 743140b

Please sign in to comment.