Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Removed data ivar from JSON::Validator so that multiple validate call become faster #465

Merged
merged 1 commit into from
May 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 12 additions & 10 deletions lib/json-schema/validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class Validator
@@serializer = nil
@@mutex = Mutex.new

def initialize(schema_data, data, opts={})
def initialize(schema_data, opts={})
@options = @@default_opts.clone.merge(opts)
@errors = []

Expand All @@ -51,15 +51,13 @@ def initialize(schema_data, data, opts={})
@validation_options[:clear_cache] = true if !@@cache_schemas || @options[:clear_cache]

@@mutex.synchronize { @base_schema = initialize_schema(schema_data, configured_validator) }
@original_data = data
@data = initialize_data(data)
@@mutex.synchronize { build_schemas(@base_schema) }

# validate the schema, if requested
if @options[:validate_schema]
# Don't clear the cache during metaschema validation!
meta_validator = self.class.new(@base_schema.validator.metaschema, @base_schema.schema, {:clear_cache => false})
meta_validator.validate
meta_validator = self.class.new(@base_schema.validator.metaschema, {:clear_cache => false})
meta_validator.validate(@base_schema.schema)
end

# If the :fragment option is set, try and validate against the fragment
Expand Down Expand Up @@ -103,8 +101,10 @@ def schema_from_fragment(base_schema, fragment)
end

# Run a simple true/false validation of data against a schema
def validate
@base_schema.validate(@data,[],self,@validation_options)
def validate(data)
original_data = data
data = initialize_data(data)
@base_schema.validate(data,[],self,@validation_options)

if @options[:record_errors]
if @options[:errors_as_objects]
Expand All @@ -116,11 +116,13 @@ def validate
true
end
ensure
@errors = []

if @validation_options[:clear_cache] == true
self.class.clear_cache
end
if @validation_options[:insert_defaults]
self.class.merge_missing_values(@data, @original_data)
self.class.merge_missing_values(data, original_data)
end
end

Expand Down Expand Up @@ -244,8 +246,8 @@ def validate_uri(schema, data, opts={})
end

def validate!(schema, data,opts={})
validator = new(schema, data, opts)
validator.validate
validator = new(schema, opts)
validator.validate(data)
end

def validate2(schema, data, opts={})
Expand Down
35 changes: 35 additions & 0 deletions test/full_validation_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,41 @@ def test_full_validation
assert(errors.length == 2)
end

def test_full_validation_with_instantiated_validator
data = {"b" => {"a" => 5}}
schema = {
"type" => "object",
"required" => ["b"],
"properties" => {
"b" => {
}
}
}

validator = JSON::Validator.new(schema, { record_errors: true })
assert(validator.validate(data).empty?)
assert(validator.validate(data).empty?)
assert(validator.validate(data).empty?)

data = {"c" => 5}
schema = {
"type" => "object",
"required" => ["b"],
"properties" => {
"b" => {
},
"c" => {
"type" => "string"
}
}
}

validator = JSON::Validator.new(schema, { record_errors: true })
assert(validator.validate(data).length == 2)
assert(validator.validate(data).length == 2)
assert(validator.validate(data).length == 2)
end

def test_full_validation_with_union_types
data = {"b" => 5}
schema = {
Expand Down
223 changes: 223 additions & 0 deletions test/initialize_data_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,227 @@ def test_parse_hash

assert_raises(TypeError) { JSON::Validator.validate(schema, data, :uri => true) }
end

def test_parse_character_string_with_instantiated_validator
schema = {'type' => 'string'}
data = 'hello world'

v = JSON::Validator.new(schema)
assert(v.validate(data))
assert(v.validate(data))

v = JSON::Validator.new(schema, { :parse_data => false })
assert(v.validate(data))
assert(v.validate(data))

v = JSON::Validator.new(schema, { :json => true })
assert_raises(JSON::Schema::JsonParseError) { v.validate(data) }
assert_raises(JSON::Schema::JsonParseError) { v.validate(data) }

v = JSON::Validator.new(schema, { :uri => true })
assert_raises(JSON::Schema::JsonLoadError) { v.validate(data) }
assert_raises(JSON::Schema::JsonLoadError) { v.validate(data) }
end

def test_parse_integer_string_with_instantiated_validator
schema = {'type' => 'integer'}
data = '42'

v = JSON::Validator.new(schema)
assert(v.validate(data))
assert(v.validate(data))

v = JSON::Validator.new(schema, { :parse_data => false })
assert_raises(JSON::Schema::ValidationError) { v.validate(data) }
assert_raises(JSON::Schema::ValidationError) { v.validate(data) }

v = JSON::Validator.new(schema, { :json => true })
assert(v.validate(data))
assert(v.validate(data))

v = JSON::Validator.new(schema, { :uri => true })
assert_raises(JSON::Schema::JsonLoadError) { v.validate(data) }
assert_raises(JSON::Schema::JsonLoadError) { v.validate(data) }
end

def test_parse_hash_string_with_instantiated_validator
schema = { 'type' => 'object', 'properties' => { 'a' => { 'type' => 'string' } } }
data = '{"a": "b"}'

v = JSON::Validator.new(schema)
assert(v.validate(data))
assert(v.validate(data))

v = JSON::Validator.new(schema, { :parse_data => false })
assert_raises(JSON::Schema::ValidationError) { v.validate(data) }
assert_raises(JSON::Schema::ValidationError) { v.validate(data) }

v = JSON::Validator.new(schema, { :json => true })
assert(v.validate(data))
assert(v.validate(data))

v = JSON::Validator.new(schema, { :uri => true })
assert_raises(JSON::Schema::UriError) { v.validate(data) }
assert_raises(JSON::Schema::UriError) { v.validate(data) }
end

def test_parse_json_string_with_instantiated_validator
schema = {'type' => 'string'}
data = '"hello world"'

v = JSON::Validator.new(schema)
assert(v.validate(data))
assert(v.validate(data))

v = JSON::Validator.new(schema, { :parse_data => false })
assert(v.validate(data))
assert(v.validate(data))

v = JSON::Validator.new(schema, { :json => true })
assert(v.validate(data))
assert(v.validate(data))

v = JSON::Validator.new(schema, { :uri => true })
assert_raises(JSON::Schema::JsonLoadError) { v.validate(data) }
assert_raises(JSON::Schema::JsonLoadError) { v.validate(data) }
end

def test_parse_plain_text_string_with_instantiated_validator
schema = {'type' => 'string'}
data = 'kapow'

v = JSON::Validator.new(schema)
assert(v.validate(data))
assert(v.validate(data))

v = JSON::Validator.new(schema, { :parse_data => false })
assert(v.validate(data))
assert(v.validate(data))

v = JSON::Validator.new(schema, { :json => true })
assert_raises(JSON::Schema::JsonParseError) { v.validate(data) }
assert_raises(JSON::Schema::JsonParseError) { v.validate(data) }

v = JSON::Validator.new(schema, { :uri => true })
assert_raises(JSON::Schema::JsonLoadError) { v.validate(data) }
assert_raises(JSON::Schema::JsonLoadError) { v.validate(data) }
end

def test_parse_valid_uri_string_with_instantiated_validator
schema = {'type' => 'string'}
data = 'http://foo.bar/'

stub_request(:get, "foo.bar").to_return(:body => '"hello world"', :status => 200)

v = JSON::Validator.new(schema)
assert(v.validate(data))
assert(v.validate(data))

v = JSON::Validator.new(schema, { :parse_data => false })
assert(v.validate(data))
assert(v.validate(data))

v = JSON::Validator.new(schema, { :json => true })
assert_raises(JSON::Schema::JsonParseError) { v.validate(data) }
assert_raises(JSON::Schema::JsonParseError) { v.validate(data) }

v = JSON::Validator.new(schema, { :uri => true })
assert(v.validate(data))
assert(v.validate(data))
end

def test_parse_invalid_uri_string_with_instantiated_validator
schema = {'type' => 'string'}
data = 'http://foo.bar/'

stub_request(:get, "foo.bar").to_timeout

v = JSON::Validator.new(schema)
assert(v.validate(data))
assert(v.validate(data))

v = JSON::Validator.new(schema, { :parse_data => false })
assert(v.validate(data))
assert(v.validate(data))

stub_request(:get, "foo.bar").to_return(:status => [500, "Internal Server Error"])

assert(v.validate(data))
assert(v.validate(data))

v = JSON::Validator.new(schema, { :parse_data => false })
assert(v.validate(data))
assert(v.validate(data))

v = JSON::Validator.new(schema, { :json => true })
assert_raises(JSON::Schema::JsonParseError) { v.validate(data) }
assert_raises(JSON::Schema::JsonParseError) { v.validate(data) }

v = JSON::Validator.new(schema, { :uri => true })
assert_raises(JSON::Schema::JsonLoadError) { v.validate(data) }
assert_raises(JSON::Schema::JsonLoadError) { v.validate(data) }
end

def test_parse_invalid_scheme_string_with_instantiated_validator
schema = {'type' => 'string'}
data = 'pick one: [1, 2, 3]'

v = JSON::Validator.new(schema)
assert(v.validate(data))
assert(v.validate(data))

v = JSON::Validator.new(schema, { :parse_data => false })
assert(v.validate(data))
assert(v.validate(data))

v = JSON::Validator.new(schema, { :json => true })
assert_raises(JSON::Schema::JsonParseError) { v.validate(data) }
assert_raises(JSON::Schema::JsonParseError) { v.validate(data) }

v = JSON::Validator.new(schema, { :uri => true })
assert_raises(JSON::Schema::UriError) { v.validate(data) }
assert_raises(JSON::Schema::UriError) { v.validate(data) }
end

def test_parse_integer_with_instantiated_validator
schema = {'type' => 'integer'}
data = 42

v = JSON::Validator.new(schema)
assert(v.validate(data))
assert(v.validate(data))

v = JSON::Validator.new(schema, { :parse_data => false })
assert(v.validate(data))
assert(v.validate(data))

v = JSON::Validator.new(schema, { :json => true })
assert_raises(TypeError) { v.validate(data) }
assert_raises(TypeError) { v.validate(data) }

v = JSON::Validator.new(schema, { :uri => true })
assert_raises(TypeError) { v.validate(data) }
assert_raises(TypeError) { v.validate(data) }
end

def test_parse_hash_with_instantiated_validator
schema = { 'type' => 'object', 'properties' => { 'a' => { 'type' => 'string' } } }
data = { 'a' => 'b' }

v = JSON::Validator.new(schema)
assert(v.validate(data))
assert(v.validate(data))

v = JSON::Validator.new(schema, { :parse_data => false })
assert(v.validate(data))
assert(v.validate(data))

v = JSON::Validator.new(schema, { :json => true })
assert_raises(TypeError) { v.validate(data) }
assert_raises(TypeError) { v.validate(data) }

v = JSON::Validator.new(schema, { :uri => true })
assert_raises(TypeError) { v.validate(data) }
assert_raises(TypeError) { v.validate(data) }
end
end