pax_global_header00006660000000000000000000000064126437145100014515gustar00rootroot0000000000000052 comment=597952b0328a1c8a82507528eb9e795a323f995e json-schema-2.6.0/000077500000000000000000000000001264371451000137315ustar00rootroot00000000000000json-schema-2.6.0/.gitignore000066400000000000000000000000671264371451000157240ustar00rootroot00000000000000/.project .*.swp pkg *.gem /Gemfile.lock .bundle .idea json-schema-2.6.0/.gitmodules000066400000000000000000000002071264371451000161050ustar00rootroot00000000000000[submodule "test/test-suite"] path = test/test-suite branch = develop url = git://github.com/json-schema/JSON-Schema-Test-Suite.git json-schema-2.6.0/.travis.yml000066400000000000000000000006321264371451000160430ustar00rootroot00000000000000language: "ruby" rvm: - "1.8" - "1.9" - "2.0" - "2.1" - "2.2" - "2.3.0" - "jruby" - "rbx" sudo: false install: - bundle install --retry=3 matrix: include: - rvm: "2.3.0" gemfile: "gemfiles/Gemfile.multi_json.x" - rvm: "2.3.0" gemfile: "gemfiles/Gemfile.yajl-ruby.x" - rvm: "2.3.0" gemfile: "gemfiles/Gemfile.uuidtools.x" allow_failures: - rvm: "1.8" json-schema-2.6.0/CHANGELOG.md000066400000000000000000000007731264371451000155510ustar00rootroot00000000000000# Change Log All notable changes to this project will be documented in this file. Please keep to the changelog format described on [keepachangelog.com](http://keepachangelog.com). This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Added - Added a changelog ### Changed - Improved performance by caching the parsing and normalization of URIs - Made validation failures raise a `JSON::Schema::SchemaParseError` and data loading failures a `JSON::Schema::JsonLoadError` json-schema-2.6.0/CONTRIBUTING.md000066400000000000000000000015761264371451000161730ustar00rootroot00000000000000The Ruby JSON Schema library is meant to be a community effort, and as such, there are no strict guidelines for contributing. All individuals that have a pull request merged will receive collaborator access to the repository. Due to the restrictions on RubyGems authentication, permissions to release a gem must be requested along with the email desired to be associated with the release credentials. Accepting changes to the JSON Schema library shall be made through the use of pull requests on GitHub. A pull request must receive at least two (2) "+1" comments from current contributors, and include a relevant changelog entry, before being accepted and merged. If a breaking issue and fix exists, please feel free to contact the project maintainer at hoxworth@gmail.com or @hoxworth for faster resolution. Releases follow semantic versioning and may be made at a maintainer's discretion. json-schema-2.6.0/CONTRIBUTORS.md000066400000000000000000000015171264371451000162140ustar00rootroot00000000000000CONTRIBUTORS ------------ * Kenny Hoxworth - @hoxworth * Jenny Duckett - @jennyd * Kevin Glowacz - @kjg * Seb Bacon - @sebbacon * Jonathan Chrisp - @jonathanchrisp * James McKinney - @jpmckinney * Kylo Ginsberg - @kylog * Alex Soto - @apsoto * Roger Leite - @rogerleite * Myron Marston - @myronmarston * Jesse Stuart - @jvatic * Brian Hoffman - @lcdhoffman * Simon Waddington - @goodsimon * Chris Baynes - @chris-baynes * David Barri - @japgolly * Tyler Hunt - @tylerhunt * @vapir * Tom May - @tommay * Chris Johnson - @kindkid * David Kellum - @dekellum * Miguel Herranz - @IPGlider * Nick Recobra - @oruen * Vasily Fedoseyev - @Vasfed * Jari Bakken - @jarib * Kyle Hargraves - @pd * Jamie Cobbett - @jamiecobbett * Iain Beeston - @iainbeeston * Matt Palmer - @mpalmer * Ben Kirzhner - @benkirzhner * RST-J - @RST-J * Christian Treppo - @treppo json-schema-2.6.0/Gemfile000066400000000000000000000001371264371451000152250ustar00rootroot00000000000000source "https://rubygems.org" gemspec gem "json", ">= 1.7", :platforms => [:mri_18, :mri_19] json-schema-2.6.0/LICENSE.md000066400000000000000000000020651264371451000153400ustar00rootroot00000000000000Copyright (c) 2010-2011, Lookingglass Cyber Solutions Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.json-schema-2.6.0/README.textile000066400000000000000000000363701264371451000162770ustar00rootroot00000000000000!https://travis-ci.org/ruby-json-schema/json-schema.svg?branch=master!:https://travis-ci.org/ruby-json-schema/json-schema !https://codeclimate.com/github/ruby-json-schema/json-schema/badges/gpa.svg!:https://codeclimate.com/github/ruby-json-schema/json-schema h1. Ruby JSON Schema Validator This library is intended to provide Ruby with an interface for validating JSON objects against a JSON schema conforming to "JSON Schema Draft 4":http://tools.ietf.org/html/draft-zyp-json-schema-04. Legacy support for "JSON Schema Draft 3":http://tools.ietf.org/html/draft-zyp-json-schema-03, "JSON Schema Draft 2":http://tools.ietf.org/html/draft-zyp-json-schema-02, and "JSON Schema Draft 1":http://tools.ietf.org/html/draft-zyp-json-schema-01 is also included. h2. Additional Resources * "Google Groups":https://groups.google.com/forum/#!forum/ruby-json-schema * #ruby-json-schema on chat.freenode.net h2. Version 2.0.0 Upgrade Notes Please be aware that the upgrade to version 2.0.0 will use Draft-04 *by default*, so schemas that do not declare a validator using the $schema keyword will use Draft-04 now instead of Draft-03. This is the reason for the major version upgrade. h2. Installation From rubygems.org:
gem install json-schema
From the git repo:
$ gem build json-schema.gemspec
$ gem install json-schema-2.5.2.gem
h2. Usage Three base validation methods exist: validate, validate!, and fully_validate. The first returns a boolean on whether a validation attempt passes and the second will throw a JSON::Schema::ValidationError with an appropriate message/trace on where the validation failed. The third validation method does not immediately fail upon a validation error and instead builds an array of validation errors return when validation is complete. All methods take two arguments, which can be either a JSON string, a file containing JSON, or a Ruby object representing JSON data. The first argument to these methods is always the schema, the second is always the data to validate. An optional third options argument is also accepted; available options are used in the examples below. By default, the validator uses the "JSON Schema Draft 4":http://tools.ietf.org/html/draft-zyp-json-schema-04 specification for validation; however, the user is free to specify additional specifications or extend existing ones. Legacy support for Draft 1, Draft 2, and Draft 3 is included by either passing an optional :version parameter to the validate method (set either as :draft1 or draft2), or by declaring the $schema attribute in the schema and referencing the appropriate specification URI. Note that the $schema attribute takes precedence over the :version option during parsing and validation. h3. Validate Ruby objects against a Ruby schema For further information on json schema itself refer to Understanding JSON Schema.
require 'rubygems'
require 'json-schema'

schema = {
  "type" => "object",
  "required" => ["a"],
  "properties" => {
    "a" => {"type" => "integer"}
  }
}

data = {
  "a" => 5
}

JSON::Validator.validate(schema, data)
h3. Validate a JSON string against a JSON schema file
require 'rubygems'
require 'json-schema'

JSON::Validator.validate('schema.json', '{"a" : 5}')
h3. Validate a list of objects against a schema that represents the individual objects
require 'rubygems'
require 'json-schema'

data = ['user','user','user']
JSON::Validator.validate('user.json', data, :list => true)
h3. Strictly validate an object's properties With the :strict option, validation fails when an object contains properties that are not defined in the schema's property list or doesn't match the additionalProperties property. Furthermore, all properties are treated as required regardless of required properties set in the schema.
require 'rubygems'
require 'json-schema'

schema = {
  "type" => "object",
  "properties" => {
    "a" => {"type" => "integer"},
    "b" => {"type" => "integer"}
  }
}

JSON::Validator.validate(schema, {"a" => 1, "b" => 2}, :strict => true)            # ==> true
JSON::Validator.validate(schema, {"a" => 1, "b" => 2, "c" => 3}, :strict => true)  # ==> false
JSON::Validator.validate(schema, {"a" => 1}, :strict => true)                      # ==> false
h3. Catch a validation error and print it out
require 'rubygems'
require 'json-schema'

schema = {
  "type" => "object",
  "required" => ["a"],
  "properties" => {
    "a" => {"type" => "integer"}
  }
}

data = {
  "a" => "taco"
}

begin
  JSON::Validator.validate!(schema, data)
rescue JSON::Schema::ValidationError
  puts $!.message
end
h3. Fully validate against a schema and catch all errors
require 'rubygems'
require 'json-schema'

schema = {
  "type" => "object",
  "required" => ["a","b"],
  "properties" => {
    "a" => {"type" => "integer"},
    "b" => {"type" => "string"}
  }
}

data = {
  "a" => "taco"
}

errors = JSON::Validator.fully_validate(schema, data)

# ["The property '#/a' of type String did not match the following type: integer in schema 03179a21-197e-5414-9611-e9f63e8324cd#", "The property '#/' did not contain a required property of 'b' in schema 03179a21-197e-5414-9611-e9f63e8324cd#"]
h3. Fully validate against a schema and catch all errors as objects
require 'rubygems'
require 'json-schema'

schema = {
  "type" => "object",
  "required" => ["a","b"],
  "properties" => {
    "a" => {"type" => "integer"},
    "b" => {"type" => "string"}
  }
}

data = {
  "a" => "taco"
}

errors = JSON::Validator.fully_validate(schema, data, :errors_as_objects => true)

# [{:message=>"The property '#/a' of type String did not match the following type: integer in schema 03179a21-197e-5414-9611-e9f63e8324cd#", :schema=>#, :failed_attribute=>"Type", :fragment=>"#/a"}, {:message=>"The property '#/' did not contain a required property of 'b' in schema 03179a21-197e-5414-9611-e9f63e8324cd#", :schema=>#, :failed_attribute=>"Properties", :fragment=>"#/"}]

h3. Validate against a fragment of a supplied schema
  require 'rubygems'
  require 'json-schema'

  schema = {
    "type" => "object",
    "required" => ["a","b"],
    "properties" => {
      "a" => {"type" => "integer"},
      "b" => {"type" => "string"},
      "c" => {
        "type" => "object",
        "properties" => {
          "z" => {"type" => "integer"}
        }
      }
    }
  }

  data = {
    "z" => 1
  }

  JSON::Validator.validate(schema, data, :fragment => "#/properties/c")
h3. Validate a JSON object against a JSON schema object, while also validating the schema itself
require 'rubygems'
require 'json-schema'

schema = {
  "type" => "object",
  "required" => ["a"],
  "properties" => {
    "a" => {"type" => "integer", "required" => "true"}  # This will fail schema validation!
  }
}

data = {
  "a" => 5
}

JSON::Validator.validate(schema, data, :validate_schema => true)
h3. Validate a JSON object against a JSON schema object, while inserting default values from the schema With the :insert_defaults option set to true any missing property that has a default value specified in the schema will be inserted into the validated data. The inserted default value is validated hence catching a schema that specifies an invalid default value.
require 'rubygems'
require 'json-schema'

schema = {
  "type" => "object",
  "required" => ["a"],
  "properties" => {
    "a" => {"type" => "integer", "default" => 42},
    "b" => {"type" => "integer"}
  }
}

# Would not normally validate because "a" is missing and required by schema,
# but "default" option allows insertion of valid default.
data = {
  "b" => 5
}

JSON::Validator.validate(schema, data)
# false

JSON::Validator.validate(schema, data, :insert_defaults => true)
# true
# data = {
#   "a" => 42,
#   "b" => 5
# }

h3. Validate an object against a JSON Schema Draft 2 schema
require 'rubygems'
require 'json-schema'

schema = {
  "type" => "object",
  "properties" => {
    "a" => {"type" => "integer", "optional" => true}
  }
}

data = {
  "a" => 5
}

JSON::Validator.validate(schema, data, :version => :draft2)
h3. Explicitly specifying the type of the data By default, json-schema accepts a variety of different types for the data parameter, and it will try to work out what to do with it dynamically. You can pass it a string uri (in which case it will download the json from that location before validating), a string of JSON text, or simply a ruby object (such as an array or hash representing parsed json). However, sometimes the nature of the data is ambiguous (for example, is "http://github.com" just a string, or is it a uri?). In other situations, you have already parsed your JSON, and you don't need to re-parse it. If you want to be explict about what kind of data is being parsed, JSON schema supports a number of options:
require 'rubygems'
require 'json-schema'

schema = {
  "type" => "string"
}

# examines the data, determines it's a uri, then tries to load data from it
JSON::Validator.validate(schema, 'https://api.github.com') # returns false

# data is already parsed json - just accept it as-is
JSON::Validator.validate(schema, 'https://api.github.com', :parse_data => false) # returns true

# data is parsed to a json string
JSON::Validator.validate(schema, '"https://api.github.com"', :json => true) # returns true

# loads data from the uri
JSON::Validator.validate(schema, 'https://api.github.com', :uri => true) # returns false
h3. Extend an existing schema and validate against it For this example, we are going to extend the "JSON Schema Draft 3":http://tools.ietf.org/html/draft-zyp-json-schema-03 specification by adding a 'bitwise-and' property for validation.
require 'rubygems'
require 'json-schema'

class BitwiseAndAttribute < JSON::Schema::Attribute
  def self.validate(current_schema, data, fragments, processor, validator, options = {})
    if data.is_a?(Integer) && data & current_schema.schema['bitwise-and'].to_i == 0
      message = "The property '#{build_fragment(fragments)}' did not evaluate  to true when bitwise-AND'd with  #{current_schema.schema['bitwise-or']}"
      raise JSON::Schema::ValidationError.new(message, fragments, current_schema)
    end
  end
end

class ExtendedSchema < JSON::Schema::Validator
  def initialize
    super
    extend_schema_definition("http://json-schema.org/draft-03/schema#")
    @attributes["bitwise-and"] = BitwiseAndAttribute
    @uri = URI.parse("http://test.com/test.json")
  end

  JSON::Validator.register_validator(self.new)
end

schema = {
  "$schema" => "http://test.com/test.json",
  "properties" => {
    "a" => {
      "bitwise-and" => 1
    },
    "b" => {
      "type" => "string"
    }
  }
}

data = {
  "a" => 0
}

data = {"a" => 1, "b" => "taco"}
JSON::Validator.validate(schema,data) # => true
data = {"a" => 1, "b" => 5}
JSON::Validator.validate(schema,data) # => false
data = {"a" => 0, "b" => "taco"}
JSON::Validator.validate(schema,data) # => false
h3. Custom format validation The JSON schema standard allows custom formats in schema definitions which should be ignored by validators that do not support them. JSON::Schema allows registering procs as custom format validators which receive the value to be checked as parameter and must raise a JSON::Schema::CustomFormatError to indicate a format violation. The error message will be prepended by the property name, e.g. "The property '#a'":
require 'rubygems'
require 'json-schema'

format_proc = -> value {
  raise JSON::Schema::CustomFormatError.new("must be 42") unless value == "42"
}

# register the proc for format 'the-answer' for draft4 schema
JSON::Validator.register_format_validator("the-answer", format_proc, ["draft4"])

# omitting the version parameter uses ["draft1", "draft2", "draft3", "draft4"] as default
JSON::Validator.register_format_validator("the-answer", format_proc)

# deregistering the custom validator
# (also ["draft1", "draft2", "draft3", "draft4"] as default version)
JSON::Validator.deregister_format_validator('the-answer', ["draft4"])

# shortcut to restore the default formats for validators (same default as before)
JSON::Validator.restore_default_formats(["draft4"])

# with the validator registered as above, the following results in
# ["The property '#a' must be 42"] as returned errors
schema = {
  "$schema" => "http://json-schema.org/draft-04/schema#",
  "properties" => {
    "a" => {
      "type" => "string",
      "format" => "the-answer",
    }
  }
}
errors = JSON::Validator.fully_validate(schema, {"a" => "23"})

h2. Controlling Remote Schema Reading In some cases, you may wish to prevent the JSON Schema library from making HTTP calls or reading local files in order to resolve $ref schemas. If you fully control all schemas which should be used by validation, this could be accomplished by registering all referenced schemas with the validator in advance:
schema = JSON::Schema.new(some_schema_definition, Addressable::URI.parse('http://example.com/my-schema'))
JSON::Validator.add_schema(schema)
If more extensive control is necessary, the JSON::Schema::Reader instance used can be configured in a few ways:
# Change the default schema reader used
JSON::Validator.schema_reader = JSON::Schema::Reader.new(:accept_uri => true, :accept_file => false)

# For this validation call, use a reader which only accepts URIs from my-website.com
schema_reader = JSON::Schema::Reader.new(
  :accept_uri => proc { |uri| uri.host == 'my-website.com' }
)
JSON::Validator.validate(some_schema, some_object, :schema_reader => schema_reader)
The JSON::Schema::Reader interface requires only an object which responds to read(string) and returns a JSON::Schema instance. See the "API documentation":http://www.rubydoc.info/github/ruby-json-schema/json-schema/master/JSON/Schema/Reader for more information. h2. JSON Backends The JSON Schema library currently supports the json and yajl-ruby backend JSON parsers. If either of these libraries are installed, they will be automatically loaded and used to parse any JSON strings supplied by the user. If more than one of the supported JSON backends are installed, the yajl-ruby parser is used by default. This can be changed by issuing the following before validation:
JSON::Validator.json_backend = :json
Optionally, the JSON Schema library supports using the MultiJSON library for selecting JSON backends. If the MultiJSON library is installed, it will be autoloaded. h2. Notes The 'format' attribute is only validated for the following values: * date-time * date * time * ip-address (IPv4 address in draft1, draft2 and draft3) * ipv4 (IPv4 address in draft4) * ipv6 * uri All other 'format' attribute values are simply checked to ensure the instance value is of the correct datatype (e.g., an instance value is validated to be an integer or a float in the case of 'utc-millisec'). Additionally, JSON::Validator does not handle any json hyperschema attributes. json-schema-2.6.0/Rakefile000066400000000000000000000011161264371451000153750ustar00rootroot00000000000000require 'bundler' require 'rake' require 'rake/testtask' Bundler::GemHelper.install_tasks desc "Updates the json-schema common test suite to the latest version" task :update_common_tests do unless File.read(".git/config").include?('submodule "test/test-suite"') sh "git submodule init" end sh "git submodule update --remote --quiet" end Rake::TestTask.new do |t| t.libs << "." t.warning = true t.verbose = true t.test_files = FileList.new('test/test*.rb') do |fl| fl.exclude(/test_helper\.rb$/) end end task :test => :update_common_tests task :default => :test json-schema-2.6.0/VERSION.yml000066400000000000000000000000331264371451000155750ustar00rootroot00000000000000major: 2 minor: 6 patch: 0 json-schema-2.6.0/gemfiles/000077500000000000000000000000001264371451000155245ustar00rootroot00000000000000json-schema-2.6.0/gemfiles/Gemfile.multi_json.x000066400000000000000000000001101264371451000214370ustar00rootroot00000000000000source "https://rubygems.org" gemspec :path => "../" gem "multi_json" json-schema-2.6.0/gemfiles/Gemfile.uuidtools.x000066400000000000000000000001071264371451000213110ustar00rootroot00000000000000source "https://rubygems.org" gemspec :path => "../" gem "uuidtools" json-schema-2.6.0/gemfiles/Gemfile.yajl-ruby.x000066400000000000000000000001071264371451000212000ustar00rootroot00000000000000source "https://rubygems.org" gemspec :path => "../" gem "yajl-ruby" json-schema-2.6.0/json-schema.gemspec000066400000000000000000000016071264371451000175110ustar00rootroot00000000000000require 'yaml' version_yaml = YAML.load(File.open('VERSION.yml').read) version = "#{version_yaml['major']}.#{version_yaml['minor']}.#{version_yaml['patch']}" gem_name = "json-schema" Gem::Specification.new do |s| s.name = gem_name s.version = version s.authors = ["Kenny Hoxworth"] s.email = "hoxworth@gmail.com" s.homepage = "http://github.com/ruby-json-schema/json-schema/tree/master" s.summary = "Ruby JSON Schema Validator" s.files = Dir[ "lib/**/*", "resources/*.json" ] s.require_path = "lib" s.extra_rdoc_files = ["README.textile","LICENSE.md"] s.required_ruby_version = ">= 1.8.7" s.license = "MIT" s.required_rubygems_version = ">= 1.8" s.add_development_dependency "rake" s.add_development_dependency "minitest", '~> 5.0' s.add_development_dependency "webmock" s.add_development_dependency "bundler" s.add_runtime_dependency "addressable", '~> 2.3.8' end json-schema-2.6.0/lib/000077500000000000000000000000001264371451000144775ustar00rootroot00000000000000json-schema-2.6.0/lib/json-schema.rb000066400000000000000000000015251264371451000172360ustar00rootroot00000000000000require 'rubygems' if Gem::Specification::find_all_by_name('multi_json').any? require 'multi_json' # Force MultiJson to load an engine before we define the JSON constant here; otherwise, # it looks for things that are under the JSON namespace that aren't there (since we have defined it here) MultiJson.respond_to?(:adapter) ? MultiJson.adapter : MultiJson.engine end require 'json-schema/util/array_set' require 'json-schema/util/uri' require 'json-schema/schema' require 'json-schema/schema/reader' require 'json-schema/validator' Dir[File.join(File.dirname(__FILE__), "json-schema/attributes/*.rb")].each {|file| require file } Dir[File.join(File.dirname(__FILE__), "json-schema/attributes/formats/*.rb")].each {|file| require file } Dir[File.join(File.dirname(__FILE__), "json-schema/validators/*.rb")].sort!.each {|file| require file } json-schema-2.6.0/lib/json-schema/000077500000000000000000000000001264371451000167065ustar00rootroot00000000000000json-schema-2.6.0/lib/json-schema/attribute.rb000066400000000000000000000022411264371451000212350ustar00rootroot00000000000000require 'json-schema/errors/validation_error' module JSON class Schema class Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) end def self.build_fragment(fragments) "#/#{fragments.join('/')}" end def self.validation_error(processor, message, fragments, current_schema, failed_attribute, record_errors) error = ValidationError.new(message, fragments, failed_attribute, current_schema) if record_errors processor.validation_error(error) else raise error end end def self.validation_errors(validator) validator.validation_errors end TYPE_CLASS_MAPPINGS = { "string" => String, "number" => Numeric, "integer" => Integer, "boolean" => [TrueClass, FalseClass], "object" => Hash, "array" => Array, "null" => NilClass, "any" => Object } def self.data_valid_for_type?(data, type) valid_classes = TYPE_CLASS_MAPPINGS.fetch(type) { return true } Array(valid_classes).any? { |c| data.is_a?(c) } end end end end json-schema-2.6.0/lib/json-schema/attributes/000077500000000000000000000000001264371451000210745ustar00rootroot00000000000000json-schema-2.6.0/lib/json-schema/attributes/additionalitems.rb000066400000000000000000000020641264371451000245750ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class AdditionalItemsAttribute < Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) return unless data.is_a?(Array) schema = current_schema.schema return unless schema['items'].is_a?(Array) case schema['additionalItems'] when false if schema['items'].length != data.length message = "The property '#{build_fragment(fragments)}' contains additional array elements outside of the schema when none are allowed" validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) end when Hash additional_items_schema = JSON::Schema.new(schema['additionalItems'], current_schema.uri, validator) data.each_with_index do |item, i| next if i < schema['items'].length additional_items_schema.validate(item, fragments + [i.to_s], processor, options) end end end end end end json-schema-2.6.0/lib/json-schema/attributes/additionalproperties.rb000066400000000000000000000044711264371451000256540ustar00rootroot00000000000000require 'json-schema/attribute' require 'json-schema/attributes/extends' module JSON class Schema class AdditionalPropertiesAttribute < Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) schema = current_schema.schema return unless data.is_a?(Hash) && (schema['type'].nil? || schema['type'] == 'object') extra_properties = remove_valid_properties(data.keys, current_schema, validator) addprop = schema['additionalProperties'] if addprop.is_a?(Hash) matching_properties = extra_properties # & addprop.keys matching_properties.each do |key| additional_property_schema = JSON::Schema.new(addprop[key] || addprop, current_schema.uri, validator) additional_property_schema.validate(data[key], fragments + [key], processor, options) end extra_properties -= matching_properties end if extra_properties.any? && (addprop == false || (addprop.is_a?(Hash) && !addprop.empty?)) message = "The property '#{build_fragment(fragments)}' contains additional properties #{extra_properties.inspect} outside of the schema when none are allowed" validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) end end def self.remove_valid_properties(extra_properties, current_schema, validator) schema = current_schema.schema if schema['properties'] extra_properties = extra_properties - schema['properties'].keys end if schema['patternProperties'] schema['patternProperties'].each_key do |key| regexp = Regexp.new(key) extra_properties.reject! { |prop| regexp.match(prop) } end end if extended_schemas = schema['extends'] extended_schemas = [extended_schemas] unless extended_schemas.is_a?(Array) extended_schemas.each do |schema_value| _, extended_schema = JSON::Schema::ExtendsAttribute.get_extended_uri_and_schema(schema_value, current_schema, validator) if extended_schema extra_properties = remove_valid_properties(extra_properties, extended_schema, validator) end end end extra_properties end end end end json-schema-2.6.0/lib/json-schema/attributes/allof.rb000066400000000000000000000031071264371451000225170ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class AllOfAttribute < Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) # Create an hash to hold errors that are generated during validation errors = Hash.new { |hsh, k| hsh[k] = [] } valid = true current_schema.schema['allOf'].each_with_index do |element, schema_index| schema = JSON::Schema.new(element,current_schema.uri,validator) # We're going to add a little cruft here to try and maintain any validation errors that occur in the allOf # We'll handle this by keeping an error count before and after validation, extracting those errors and pushing them onto an error array pre_validation_error_count = validation_errors(processor).count begin schema.validate(data,fragments,processor,options) rescue ValidationError valid = false end diff = validation_errors(processor).count - pre_validation_error_count while diff > 0 diff = diff - 1 errors["allOf ##{schema_index}"].push(validation_errors(processor).pop) end end if !valid || !errors.empty? message = "The property '#{build_fragment(fragments)}' of type #{data.class} did not match all of the required schemas" validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) validation_errors(processor).last.sub_errors = errors end end end end end json-schema-2.6.0/lib/json-schema/attributes/anyof.rb000066400000000000000000000034671264371451000225470ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class AnyOfAttribute < Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) # Create a hash to hold errors that are generated during validation errors = Hash.new { |hsh, k| hsh[k] = [] } valid = false original_data = data.is_a?(Hash) ? data.clone : data current_schema.schema['anyOf'].each_with_index do |element, schema_index| schema = JSON::Schema.new(element,current_schema.uri,validator) # We're going to add a little cruft here to try and maintain any validation errors that occur in the anyOf # We'll handle this by keeping an error count before and after validation, extracting those errors and pushing them onto a union error pre_validation_error_count = validation_errors(processor).count begin schema.validate(data,fragments,processor,options) valid = true rescue ValidationError # We don't care that these schemas don't validate - we only care that one validated end diff = validation_errors(processor).count - pre_validation_error_count valid = false if diff > 0 while diff > 0 diff = diff - 1 errors["anyOf ##{schema_index}"].push(validation_errors(processor).pop) end break if valid data = original_data end if !valid message = "The property '#{build_fragment(fragments)}' of type #{data.class} did not match one or more of the required schemas" validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) validation_errors(processor).last.sub_errors = errors end end end end end json-schema-2.6.0/lib/json-schema/attributes/dependencies.rb000066400000000000000000000032311264371451000240460ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class DependenciesAttribute < Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) return unless data.is_a?(Hash) current_schema.schema['dependencies'].each do |property, dependency_value| next unless data.has_key?(property.to_s) next unless accept_value?(dependency_value) case dependency_value when String validate_dependency(current_schema, data, property, dependency_value, fragments, processor, self, options) when Array dependency_value.each do |value| validate_dependency(current_schema, data, property, value, fragments, processor, self, options) end else schema = JSON::Schema.new(dependency_value, current_schema.uri, validator) schema.validate(data, fragments, processor, options) end end end def self.validate_dependency(schema, data, property, value, fragments, processor, attribute, options) return if data.key?(value.to_s) message = "The property '#{build_fragment(fragments)}' has a property '#{property}' that depends on a missing property '#{value}'" validation_error(processor, message, fragments, schema, attribute, options[:record_errors]) end def self.accept_value?(value) value.is_a?(String) || value.is_a?(Array) || value.is_a?(Hash) end end class DependenciesV4Attribute < DependenciesAttribute def self.accept_value?(value) value.is_a?(Array) || value.is_a?(Hash) end end end end json-schema-2.6.0/lib/json-schema/attributes/disallow.rb000066400000000000000000000006061264371451000232410ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class DisallowAttribute < Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) return unless type = validator.attributes['type'] type.validate(current_schema, data, fragments, processor, validator, options.merge(:disallow => true)) end end end end json-schema-2.6.0/lib/json-schema/attributes/divisibleby.rb000066400000000000000000000012711264371451000237270ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class DivisibleByAttribute < Attribute def self.keyword 'divisibleBy' end def self.validate(current_schema, data, fragments, processor, validator, options = {}) return unless data.is_a?(Numeric) factor = current_schema.schema[keyword] if factor == 0 || factor == 0.0 || (BigDecimal.new(data.to_s) % BigDecimal.new(factor.to_s)).to_f != 0 message = "The property '#{build_fragment(fragments)}' was not divisible by #{factor}" validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) end end end end end json-schema-2.6.0/lib/json-schema/attributes/enum.rb000066400000000000000000000013661264371451000223730ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class EnumAttribute < Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) enum = current_schema.schema['enum'] return if enum.include?(data) values = enum.map { |val| case val when nil then 'null' when Array then 'array' when Hash then 'object' else val.to_s end }.join(', ') message = "The property '#{build_fragment(fragments)}' value #{data.inspect} did not match one of the following values: #{values}" validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) end end end end json-schema-2.6.0/lib/json-schema/attributes/extends.rb000066400000000000000000000033431264371451000230760ustar00rootroot00000000000000require 'json-schema/attribute' require 'json-schema/attributes/ref' module JSON class Schema class ExtendsAttribute < Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) schemas = current_schema.schema['extends'] schemas = [schemas] if !schemas.is_a?(Array) schemas.each do |s| uri,schema = get_extended_uri_and_schema(s, current_schema, validator) if schema schema.validate(data, fragments, processor, options) elsif uri message = "The extended schema '#{uri.to_s}' cannot be found" validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) else message = "The property '#{build_fragment(fragments)}' was not a valid schema" validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) end end end def self.get_extended_uri_and_schema(s, current_schema, validator) uri,schema = nil,nil s = {'$ref' => s} if s.is_a?(String) if s.is_a?(Hash) uri = current_schema.uri if s['$ref'] ref_uri,ref_schema = JSON::Schema::RefAttribute.get_referenced_uri_and_schema(s, current_schema, validator) if ref_schema if s.size == 1 # Check if anything else apart from $ref uri,schema = ref_uri,ref_schema else s = s.dup s.delete '$ref' s = ref_schema.schema.merge(s) end end end schema ||= JSON::Schema.new(s,uri,validator) end [uri,schema] end end end end json-schema-2.6.0/lib/json-schema/attributes/format.rb000066400000000000000000000010001264371451000227000ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class FormatAttribute < Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) return unless data_valid_for_type?(data, current_schema.schema['type']) format = current_schema.schema['format'].to_s validator = validator.formats[format] validator.validate(current_schema, data, fragments, processor, validator, options) unless validator.nil? end end end end json-schema-2.6.0/lib/json-schema/attributes/formats/000077500000000000000000000000001264371451000225475ustar00rootroot00000000000000json-schema-2.6.0/lib/json-schema/attributes/formats/custom.rb000066400000000000000000000012471264371451000244120ustar00rootroot00000000000000require 'json-schema/attribute' require 'json-schema/errors/custom_format_error' module JSON class Schema class CustomFormat < FormatAttribute def initialize(validation_proc) @validation_proc = validation_proc end def validate(current_schema, data, fragments, processor, validator, options = {}) begin @validation_proc.call data rescue JSON::Schema::CustomFormatError => e message = "The property '#{self.class.build_fragment(fragments)}' #{e.message}" self.class.validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) end end end end end json-schema-2.6.0/lib/json-schema/attributes/formats/date.rb000066400000000000000000000015421264371451000240130ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class DateFormat < FormatAttribute REGEXP = /\A\d{4}-\d{2}-\d{2}\z/ def self.validate(current_schema, data, fragments, processor, validator, options = {}) if data.is_a?(String) error_message = "The property '#{build_fragment(fragments)}' must be a date in the format of YYYY-MM-DD" if REGEXP.match(data) begin Date.parse(data) rescue ArgumentError => e raise e unless e.message == 'invalid date' validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) end else validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) end end end end end end json-schema-2.6.0/lib/json-schema/attributes/formats/date_time.rb000066400000000000000000000032761264371451000250370ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class DateTimeFormat < FormatAttribute REGEXP = /\A\d{4}-\d{2}-\d{2}T(\d{2}):(\d{2}):(\d{2})([\.,]\d+)?(Z|[+-](\d{2})(:?\d{2})?)?\z/ def self.validate(current_schema, data, fragments, processor, validator, options = {}) # Timestamp in restricted ISO-8601 YYYY-MM-DDThh:mm:ssZ with optional decimal fraction of the second if data.is_a?(String) error_message = "The property '#{build_fragment(fragments)}' must be a date/time in the ISO-8601 format of YYYY-MM-DDThh:mm:ssZ or YYYY-MM-DDThh:mm:ss.ssZ" if (m = REGEXP.match(data)) parts = data.split("T") begin Date.parse(parts[0]) rescue ArgumentError => e raise e unless e.message == 'invalid date' validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) return end validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) and return if m.length < 4 validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) and return if m[1].to_i > 23 validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) and return if m[2].to_i > 59 validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) and return if m[3].to_i > 59 else validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) end end end end end end json-schema-2.6.0/lib/json-schema/attributes/formats/date_time_v4.rb000066400000000000000000000010411264371451000254340ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class DateTimeV4Format < FormatAttribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) return unless data.is_a?(String) DateTime.rfc3339(data) rescue ArgumentError error_message = "The property '#{build_fragment(fragments)}' must be a valid RFC3339 date/time string" validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) end end end end json-schema-2.6.0/lib/json-schema/attributes/formats/ip.rb000066400000000000000000000020211264371451000234770ustar00rootroot00000000000000require 'json-schema/attributes/format' require 'ipaddr' require 'socket' module JSON class Schema class IPFormat < FormatAttribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) return unless data.is_a?(String) begin ip = IPAddr.new(data) rescue ArgumentError => e raise e unless e.message == 'invalid address' end family = ip_version == 6 ? Socket::AF_INET6 : Socket::AF_INET unless ip && ip.family == family error_message = "The property '#{build_fragment(fragments)}' must be a valid IPv#{ip_version} address" validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) end end def self.ip_version raise NotImplementedError end end class IP4Format < IPFormat def self.ip_version 4 end end class IP6Format < IPFormat def self.ip_version 6 end end end end json-schema-2.6.0/lib/json-schema/attributes/formats/time.rb000066400000000000000000000020031264371451000240250ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class TimeFormat < FormatAttribute REGEXP = /\A(\d{2}):(\d{2}):(\d{2})\z/ def self.validate(current_schema, data, fragments, processor, validator, options = {}) if data.is_a?(String) error_message = "The property '#{build_fragment(fragments)}' must be a time in the format of hh:mm:ss" if (m = REGEXP.match(data)) validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) and return if m[1].to_i > 23 validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) and return if m[2].to_i > 59 validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) and return if m[3].to_i > 59 else validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) end end end end end end json-schema-2.6.0/lib/json-schema/attributes/formats/uri.rb000066400000000000000000000011321264371451000236700ustar00rootroot00000000000000require 'json-schema/attribute' require 'json-schema/errors/uri_error' module JSON class Schema class UriFormat < FormatAttribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) return unless data.is_a?(String) error_message = "The property '#{build_fragment(fragments)}' must be a valid URI" begin JSON::Util::URI.parse(data) rescue JSON::Schema::UriError validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) end end end end end json-schema-2.6.0/lib/json-schema/attributes/items.rb000066400000000000000000000014521264371451000225440ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class ItemsAttribute < Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) return unless data.is_a?(Array) items = current_schema.schema['items'] case items when Hash schema = JSON::Schema.new(items, current_schema.uri, validator) data.each_with_index do |item, i| schema.validate(item, fragments + [i.to_s], processor, options) end when Array items.each_with_index do |item_schema, i| schema = JSON::Schema.new(item_schema, current_schema.uri, validator) schema.validate(data[i], fragments + [i.to_s], processor, options) end end end end end end json-schema-2.6.0/lib/json-schema/attributes/limit.rb000066400000000000000000000077041264371451000225470ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class LimitAttribute < Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) schema = current_schema.schema return unless data.is_a?(acceptable_type) && invalid?(schema, value(data)) property = build_fragment(fragments) description = error_message(schema) message = format("The property '%s' %s", property, description) validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) end def self.invalid?(schema, data) exclusive = exclusive?(schema) limit = limit(schema) if limit_name.start_with?('max') exclusive ? data >= limit : data > limit else exclusive ? data <= limit : data < limit end end def self.limit(schema) schema[limit_name] end def self.exclusive?(schema) false end def self.value(data) data end def self.acceptable_type raise NotImplementedError end def self.error_message(schema) raise NotImplementedError end def self.limit_name raise NotImplementedError end end class MinLengthAttribute < LimitAttribute def self.acceptable_type String end def self.limit_name 'minLength' end def self.error_message(schema) "was not of a minimum string length of #{limit(schema)}" end def self.value(data) data.length end end class MaxLengthAttribute < MinLengthAttribute def self.limit_name 'maxLength' end def self.error_message(schema) "was not of a maximum string length of #{limit(schema)}" end end class MinItemsAttribute < LimitAttribute def self.acceptable_type Array end def self.value(data) data.length end def self.limit_name 'minItems' end def self.error_message(schema) "did not contain a minimum number of items #{limit(schema)}" end end class MaxItemsAttribute < MinItemsAttribute def self.limit_name 'maxItems' end def self.error_message(schema) "had more items than the allowed #{limit(schema)}" end end class MinPropertiesAttribute < LimitAttribute def self.acceptable_type Hash end def self.value(data) data.size end def self.limit_name 'minProperties' end def self.error_message(schema) "did not contain a minimum number of properties #{limit(schema)}" end end class MaxPropertiesAttribute < MinPropertiesAttribute def self.limit_name 'maxProperties' end def self.error_message(schema) "had more properties than the allowed #{limit(schema)}" end end class NumericLimitAttribute < LimitAttribute def self.acceptable_type Numeric end def self.error_message(schema) exclusivity = exclusive?(schema) ? 'exclusively' : 'inclusively' format("did not have a %s value of %s, %s", limit_name, limit(schema), exclusivity) end end class MaximumAttribute < NumericLimitAttribute def self.limit_name 'maximum' end def self.exclusive?(schema) schema['exclusiveMaximum'] end end class MaximumInclusiveAttribute < MaximumAttribute def self.exclusive?(schema) schema['maximumCanEqual'] == false end end class MinimumAttribute < NumericLimitAttribute def self.limit_name 'minimum' end def self.exclusive?(schema) schema['exclusiveMinimum'] end end class MinimumInclusiveAttribute < MinimumAttribute def self.exclusive?(schema) schema['minimumCanEqual'] == false end end end end json-schema-2.6.0/lib/json-schema/attributes/maxdecimal.rb000066400000000000000000000012231264371451000235230ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class MaxDecimalAttribute < Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) return unless data.is_a?(Numeric) max_decimal_places = current_schema.schema['maxDecimal'] s = data.to_s.split(".")[1] if s && s.length > max_decimal_places message = "The property '#{build_fragment(fragments)}' had more decimal places than the allowed #{max_decimal_places}" validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) end end end end end json-schema-2.6.0/lib/json-schema/attributes/multipleof.rb000066400000000000000000000003061264371451000236000ustar00rootroot00000000000000require 'json-schema/attributes/divisibleby' module JSON class Schema class MultipleOfAttribute < DivisibleByAttribute def self.keyword 'multipleOf' end end end end json-schema-2.6.0/lib/json-schema/attributes/not.rb000066400000000000000000000021451264371451000222230ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class NotAttribute < Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) schema = JSON::Schema.new(current_schema.schema['not'],current_schema.uri,validator) failed = true errors_copy = processor.validation_errors.clone begin schema.validate(data,fragments,processor,options) # If we're recording errors, we don't throw an exception. Instead, check the errors array length if options[:record_errors] && errors_copy.length != processor.validation_errors.length processor.validation_errors.replace(errors_copy) else message = "The property '#{build_fragment(fragments)}' of type #{data.class} matched the disallowed schema" failed = false end rescue ValidationError # Yay, we failed validation. end unless failed validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) end end end end end json-schema-2.6.0/lib/json-schema/attributes/oneof.rb000066400000000000000000000035761264371451000225420ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class OneOfAttribute < Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) errors = Hash.new { |hsh, k| hsh[k] = [] } validation_error_count = 0 one_of = current_schema.schema['oneOf'] original_data = data.is_a?(Hash) ? data.clone : data success_data = nil valid = false one_of.each_with_index do |element, schema_index| schema = JSON::Schema.new(element,current_schema.uri,validator) pre_validation_error_count = validation_errors(processor).count begin schema.validate(data,fragments,processor,options) success_data = data.is_a?(Hash) ? data.clone : data valid = true rescue ValidationError valid = false end diff = validation_errors(processor).count - pre_validation_error_count valid = false if diff > 0 validation_error_count += 1 if !valid while diff > 0 diff = diff - 1 errors["oneOf ##{schema_index}"].push(validation_errors(processor).pop) end data = original_data end if validation_error_count == one_of.length - 1 data = success_data return end if validation_error_count == one_of.length message = "The property '#{build_fragment(fragments)}' of type #{data.class} did not match any of the required schemas" else message = "The property '#{build_fragment(fragments)}' of type #{data.class} matched more than one of the required schemas" end validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) if message validation_errors(processor).last.sub_errors = errors if message end end end end json-schema-2.6.0/lib/json-schema/attributes/pattern.rb000066400000000000000000000011631264371451000230770ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class PatternAttribute < Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) return unless data.is_a?(String) pattern = current_schema.schema['pattern'] regexp = Regexp.new(pattern) unless regexp.match(data) message = "The property '#{build_fragment(fragments)}' value #{data.inspect} did not match the regex '#{pattern}'" validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) end end end end end json-schema-2.6.0/lib/json-schema/attributes/patternproperties.rb000066400000000000000000000013451264371451000252160ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class PatternPropertiesAttribute < Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) return unless data.is_a?(Hash) current_schema.schema['patternProperties'].each do |property, property_schema| regexp = Regexp.new(property) # Check each key in the data hash to see if it matches the regex data.each do |key, value| next unless regexp.match(key) schema = JSON::Schema.new(property_schema, current_schema.uri, validator) schema.validate(data[key], fragments + [key], processor, options) end end end end end end json-schema-2.6.0/lib/json-schema/attributes/properties.rb000066400000000000000000000051661264371451000236250ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class PropertiesAttribute < Attribute def self.required?(schema, options) schema.fetch('required') { options[:strict] } end def self.validate(current_schema, data, fragments, processor, validator, options = {}) return unless data.is_a?(Hash) schema = current_schema.schema schema['properties'].each do |property, property_schema| property = property.to_s if !data.key?(property) && options[:insert_defaults] && property_schema.has_key?('default') && !property_schema['readonly'] default = property_schema['default'] data[property] = default.is_a?(Hash) ? default.clone : default end if required?(property_schema, options) && !data.has_key?(property) message = "The property '#{build_fragment(fragments)}' did not contain a required property of '#{property}'" validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) end if data.has_key?(property) expected_schema = JSON::Schema.new(property_schema, current_schema.uri, validator) expected_schema.validate(data[property], fragments + [property], processor, options) end end # When strict is true, ensure no undefined properties exist in the data return unless options[:strict] == true && !schema.key?('additionalProperties') diff = data.select do |k, v| k = k.to_s if schema.has_key?('patternProperties') match = false schema['patternProperties'].each do |property, property_schema| regexp = Regexp.new(property) if regexp.match(k) match = true break end end !schema['properties'].has_key?(k) && !match else !schema['properties'].has_key?(k) end end if diff.size > 0 properties = diff.keys.join(', ') message = "The property '#{build_fragment(fragments)}' contained undefined properties: '#{properties}'" validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) end end end class PropertiesV4Attribute < PropertiesAttribute # draft4 relies on its own RequiredAttribute validation at a higher level, rather than # as an attribute of individual properties. def self.required?(schema, options) options[:strict] == true end end end end json-schema-2.6.0/lib/json-schema/attributes/properties_optional.rb000066400000000000000000000017171264371451000255300ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class PropertiesOptionalAttribute < Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) return unless data.is_a?(Hash) schema = current_schema.schema schema['properties'].each do |property, property_schema| property = property.to_s if !property_schema['optional'] && !data.key?(property) message = "The property '#{build_fragment(fragments)}' did not contain a required property of '#{property}'" validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) end if data.has_key?(property) expected_schema = JSON::Schema.new(property_schema, current_schema.uri, validator) expected_schema.validate(data[property], fragments + [property], processor, options) end end end end end end json-schema-2.6.0/lib/json-schema/attributes/ref.rb000066400000000000000000000055511264371451000222030ustar00rootroot00000000000000require 'json-schema/attribute' require 'json-schema/errors/schema_error' require 'json-schema/util/uri' module JSON class Schema class RefAttribute < Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) uri,schema = get_referenced_uri_and_schema(current_schema.schema, current_schema, validator) if schema schema.validate(data, fragments, processor, options) elsif uri message = "The referenced schema '#{uri.to_s}' cannot be found" validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) else message = "The property '#{build_fragment(fragments)}' was not a valid schema" validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) end end def self.get_referenced_uri_and_schema(s, current_schema, validator) uri,schema = nil,nil temp_uri = JSON::Util::URI.parse(s['$ref']) temp_uri.defer_validation do if temp_uri.relative? temp_uri.merge!(current_schema.uri) # Check for absolute path path, fragment = s['$ref'].split("#") if path.nil? || path == '' temp_uri.path = current_schema.uri.path elsif path[0,1] == "/" temp_uri.path = Pathname.new(path).cleanpath.to_s else temp_uri.join!(path) end temp_uri.fragment = fragment end temp_uri.fragment = "" if temp_uri.fragment.nil? || temp_uri.fragment.empty? end # Grab the parent schema from the schema list schema_key = temp_uri.to_s.split("#")[0] + "#" ref_schema = JSON::Validator.schema_for_uri(schema_key) if ref_schema # Perform fragment resolution to retrieve the appropriate level for the schema target_schema = ref_schema.schema fragments = temp_uri.fragment.split("/") fragment_path = '' fragments.each do |fragment| if fragment && fragment != '' fragment = JSON::Util::URI.unescaped_uri(fragment.gsub('~0', '~').gsub('~1', '/')) if target_schema.is_a?(Array) target_schema = target_schema[fragment.to_i] else target_schema = target_schema[fragment] end fragment_path = fragment_path + "/#{fragment}" if target_schema.nil? raise SchemaError.new("The fragment '#{fragment_path}' does not exist on schema #{ref_schema.uri.to_s}") end end end # We have the schema finally, build it and validate! uri = temp_uri schema = JSON::Schema.new(target_schema,temp_uri,validator) end [uri,schema] end end end end json-schema-2.6.0/lib/json-schema/attributes/required.rb000066400000000000000000000020301264371451000232340ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class RequiredAttribute < Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) return unless data.is_a?(Hash) schema = current_schema.schema defined_properties = schema['properties'] schema['required'].each do |property, property_schema| next if data.has_key?(property.to_s) prop_defaults = options[:insert_defaults] && defined_properties && defined_properties[property] && !defined_properties[property]["default"].nil? && !defined_properties[property]["readonly"] if !prop_defaults message = "The property '#{build_fragment(fragments)}' did not contain a required property of '#{property}'" validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) end end end end end end json-schema-2.6.0/lib/json-schema/attributes/type.rb000066400000000000000000000064311264371451000224060ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class TypeAttribute < Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) union = true if options[:disallow] types = current_schema.schema['disallow'] else types = current_schema.schema['type'] end if !types.is_a?(Array) types = [types] union = false end valid = false # Create a hash to hold errors that are generated during union validation union_errors = Hash.new { |hsh, k| hsh[k] = [] } types.each_with_index do |type, type_index| if type.is_a?(String) valid = data_valid_for_type?(data, type) elsif type.is_a?(Hash) && union # Validate as a schema schema = JSON::Schema.new(type,current_schema.uri,validator) # We're going to add a little cruft here to try and maintain any validation errors that occur in this union type # We'll handle this by keeping an error count before and after validation, extracting those errors and pushing them onto a union error pre_validation_error_count = validation_errors(processor).count begin schema.validate(data,fragments,processor,options.merge(:disallow => false)) valid = true rescue ValidationError # We don't care that these schemas don't validate - we only care that one validated end diff = validation_errors(processor).count - pre_validation_error_count valid = false if diff > 0 while diff > 0 diff = diff - 1 union_errors["type ##{type_index}"].push(validation_errors(processor).pop) end end break if valid end if options[:disallow] return if !valid message = "The property '#{build_fragment(fragments)}' matched one or more of the following types: #{list_types(types)}" validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) elsif !valid if union message = "The property '#{build_fragment(fragments)}' of type #{type_of_data(data)} did not match one or more of the following types: #{list_types(types)}" validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) validation_errors(processor).last.sub_errors = union_errors else message = "The property '#{build_fragment(fragments)}' of type #{type_of_data(data)} did not match the following type: #{list_types(types)}" validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) end end end def self.list_types(types) types.map { |type| type.is_a?(String) ? type : '(schema)' }.join(', ') end # Lookup Schema type of given class instance def self.type_of_data(data) type, _ = TYPE_CLASS_MAPPINGS.map { |k,v| [k,v] }.sort_by { |(_, v)| -Array(v).map { |klass| klass.ancestors.size }.max }.find { |(_, v)| Array(v).any? { |klass| data.kind_of?(klass) } } type end end end end json-schema-2.6.0/lib/json-schema/attributes/type_v4.rb000066400000000000000000000016021264371451000230120ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class TypeV4Attribute < Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) union = true types = current_schema.schema['type'] if !types.is_a?(Array) types = [types] union = false end return if types.any? { |type| data_valid_for_type?(data, type) } types = types.map { |type| type.is_a?(String) ? type : '(schema)' }.join(', ') message = format( "The property '%s' of type %s did not match %s: %s", build_fragment(fragments), data.class, union ? 'one or more of the following types' : 'the following type', types ) validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) end end end end json-schema-2.6.0/lib/json-schema/attributes/uniqueitems.rb000066400000000000000000000007761264371451000240030ustar00rootroot00000000000000require 'json-schema/attribute' module JSON class Schema class UniqueItemsAttribute < Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) return unless data.is_a?(Array) if data.clone.uniq! message = "The property '#{build_fragment(fragments)}' contained duplicated array values" validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) end end end end end json-schema-2.6.0/lib/json-schema/errors/000077500000000000000000000000001264371451000202225ustar00rootroot00000000000000json-schema-2.6.0/lib/json-schema/errors/custom_format_error.rb000066400000000000000000000001311264371451000246350ustar00rootroot00000000000000module JSON class Schema class CustomFormatError < StandardError end end end json-schema-2.6.0/lib/json-schema/errors/json_load_error.rb000066400000000000000000000001251264371451000237260ustar00rootroot00000000000000module JSON class Schema class JsonLoadError < StandardError end end end json-schema-2.6.0/lib/json-schema/errors/json_parse_error.rb000066400000000000000000000001261264371451000241220ustar00rootroot00000000000000module JSON class Schema class JsonParseError < StandardError end end end json-schema-2.6.0/lib/json-schema/errors/schema_error.rb000066400000000000000000000001231264371451000232140ustar00rootroot00000000000000module JSON class Schema class SchemaError < StandardError end end end json-schema-2.6.0/lib/json-schema/errors/schema_parse_error.rb000066400000000000000000000001631264371451000244120ustar00rootroot00000000000000require 'json/common' module JSON class Schema class SchemaParseError < JSON::ParserError end end end json-schema-2.6.0/lib/json-schema/errors/uri_error.rb000066400000000000000000000001201264371451000225500ustar00rootroot00000000000000module JSON class Schema class UriError < StandardError end end end json-schema-2.6.0/lib/json-schema/errors/validation_error.rb000066400000000000000000000031371264371451000241160ustar00rootroot00000000000000module JSON class Schema class ValidationError < StandardError INDENT = " " attr_accessor :fragments, :schema, :failed_attribute, :sub_errors, :message def initialize(message, fragments, failed_attribute, schema) @fragments = fragments.clone @schema = schema @sub_errors = {} @failed_attribute = failed_attribute @message = message super(message_with_schema) end def to_string(subschema_level = 0) if @sub_errors.empty? subschema_level == 0 ? message_with_schema : message else messages = ["#{message}. The schema specific errors were:\n"] @sub_errors.each do |subschema, errors| messages.push "- #{subschema}:" messages.concat Array(errors).map { |e| "#{INDENT}- #{e.to_string(subschema_level + 1)}" } end messages.map { |m| (INDENT * subschema_level) + m }.join("\n") end end def to_hash base = {:schema => @schema.uri, :fragment => ::JSON::Schema::Attribute.build_fragment(fragments), :message => message_with_schema, :failed_attribute => @failed_attribute.to_s.split(":").last.split("Attribute").first} if !@sub_errors.empty? base[:errors] = @sub_errors.inject({}) do |hsh, (subschema, errors)| subschema_sym = subschema.downcase.gsub(/\W+/, '_').to_sym hsh[subschema_sym] = Array(errors).map{|e| e.to_hash} hsh end end base end def message_with_schema "#{message} in schema #{schema.uri}" end end end end json-schema-2.6.0/lib/json-schema/schema.rb000066400000000000000000000032761264371451000205030ustar00rootroot00000000000000require 'pathname' module JSON class Schema attr_accessor :schema, :uri, :validator def initialize(schema,uri,parent_validator=nil) @schema = schema @uri = uri # If there is an ID on this schema, use it to generate the URI if @schema['id'] && @schema['id'].kind_of?(String) temp_uri = JSON::Util::URI.parse(@schema['id']) if temp_uri.relative? temp_uri = uri.join(temp_uri) end @uri = temp_uri end @uri = JSON::Util::URI.strip_fragment(@uri) # If there is a $schema on this schema, use it to determine which validator to use if @schema['$schema'] @validator = JSON::Validator.validator_for(@schema['$schema']) elsif parent_validator @validator = parent_validator else @validator = JSON::Validator.default_validator end end def validate(data, fragments, processor, options = {}) @validator.validate(self, data, fragments, processor, options) end def self.stringify(schema) case schema when Hash then Hash[schema.map { |key, value| [key.to_s, stringify(schema[key])] }] when Array then schema.map do |schema_item| stringify(schema_item) end when Symbol then schema.to_s else schema end end # @return [JSON::Schema] a new schema matching an array whose items all match this schema. def to_array_schema array_schema = { 'type' => 'array', 'items' => schema } array_schema['$schema'] = schema['$schema'] unless schema['$schema'].nil? JSON::Schema.new(array_schema, uri, validator) end def to_s @schema.to_json end end end json-schema-2.6.0/lib/json-schema/schema/000077500000000000000000000000001264371451000201465ustar00rootroot00000000000000json-schema-2.6.0/lib/json-schema/schema/reader.rb000066400000000000000000000072231264371451000217410ustar00rootroot00000000000000require 'open-uri' require 'pathname' module JSON class Schema # Raised by {JSON::Schema::Reader} when one of its settings indicate # a schema should not be readed. class ReadRefused < StandardError # @return [String] the requested schema location which was refused attr_reader :location # @return [Symbol] either +:uri+ or +:file+ attr_reader :type def initialize(location, type) @location = location @type = type super("Read of #{type == :uri ? 'URI' : type} at #{location} refused!") end end # When an unregistered schema is encountered, the {JSON::Schema::Reader} is # used to fetch its contents and register it with the {JSON::Validator}. # # This default reader will read schemas from the filesystem or from a URI. class Reader # The behavior of the schema reader can be controlled by providing # callbacks to determine whether to permit reading referenced schemas. # The options +accept_uri+ and +accept_file+ should be procs which # accept a +URI+ or +Pathname+ object, and return a boolean value # indicating whether to read the referenced schema. # # URIs using the +file+ scheme will be normalized into +Pathname+ objects # and passed to the +accept_file+ callback. # # @param options [Hash] # @option options [Boolean, #call] accept_uri (true) # @option options [Boolean, #call] accept_file (true) # # @example Reject all unregistered schemas # JSON::Validator.schema_reader = JSON::Schema::Reader.new( # :accept_uri => false, # :accept_file => false # ) # # @example Only permit URIs from certain hosts # JSON::Validator.schema_reader = JSON::Schema::Reader.new( # :accept_file => false, # :accept_uri => proc { |uri| ['mycompany.com', 'json-schema.org'].include?(uri.host) } # ) def initialize(options = {}) @accept_uri = options.fetch(:accept_uri, true) @accept_file = options.fetch(:accept_file, true) end # @param location [#to_s] The location from which to read the schema # @return [JSON::Schema] # @raise [JSON::Schema::ReadRefused] if +accept_uri+ or +accept_file+ # indicated the schema could not be read # @raise [JSON::Schema::ParseError] if the schema was not a valid JSON object def read(location) uri = JSON::Util::URI.parse(location.to_s) body = if uri.scheme.nil? || uri.scheme == 'file' uri = JSON::Util::URI.file_uri(uri) read_file(Pathname.new(uri.path).expand_path) else read_uri(uri) end JSON::Schema.new(JSON::Validator.parse(body), uri) end # @param uri [Addressable::URI] # @return [Boolean] def accept_uri?(uri) if @accept_uri.respond_to?(:call) @accept_uri.call(uri) else @accept_uri end end # @param pathname [Pathname] # @return [Boolean] def accept_file?(pathname) if @accept_file.respond_to?(:call) @accept_file.call(pathname) else @accept_file end end private def read_uri(uri) if accept_uri?(uri) open(uri.to_s).read else raise JSON::Schema::ReadRefused.new(uri.to_s, :uri) end end def read_file(pathname) if accept_file?(pathname) File.read(JSON::Util::URI.unescaped_uri(pathname.to_s)) else raise JSON::Schema::ReadRefused.new(pathname.to_s, :file) end end end end end json-schema-2.6.0/lib/json-schema/schema/validator.rb000066400000000000000000000017511264371451000224640ustar00rootroot00000000000000module JSON class Schema class Validator attr_accessor :attributes, :formats, :uri, :names attr_reader :default_formats def initialize() @attributes = {} @formats = {} @default_formats = {} @uri = nil @names = [] @metaschema_name = '' end def extend_schema_definition(schema_uri) validator = JSON::Validator.validator_for(schema_uri) @attributes.merge!(validator.attributes) end def validate(current_schema, data, fragments, processor, options = {}) current_schema.schema.each do |attr_name,attribute| if @attributes.has_key?(attr_name.to_s) @attributes[attr_name.to_s].validate(current_schema, data, fragments, processor, self, options) end end data end def metaschema resources = File.expand_path('../../../../resources', __FILE__) File.join(resources, @metaschema_name) end end end end json-schema-2.6.0/lib/json-schema/util/000077500000000000000000000000001264371451000176635ustar00rootroot00000000000000json-schema-2.6.0/lib/json-schema/util/array_set.rb000066400000000000000000000010051264371451000221750ustar00rootroot00000000000000require 'set' # This is a hack that I don't want to ever use anywhere else or repeat EVER, but we need enums to be # an Array to pass schema validation. But we also want fast lookup! class ArraySet < Array def include?(obj) if !defined? @values @values = Set.new self.each { |x| @values << convert_to_float_if_fixnum(x) } end @values.include?(convert_to_float_if_fixnum(obj)) end private def convert_to_float_if_fixnum(value) value.is_a?(Fixnum) ? value.to_f : value end end json-schema-2.6.0/lib/json-schema/util/uri.rb000066400000000000000000000032021264371451000210040ustar00rootroot00000000000000require 'addressable/uri' module JSON module Util module URI SUPPORTED_PROTOCOLS = %w(http https ftp tftp sftp ssh svn+ssh telnet nntp gopher wais ldap prospero) def self.normalized_uri(uri, base_path = Dir.pwd) @normalize_cache ||= {} normalized_uri = @normalize_cache[uri] if !normalized_uri normalized_uri = parse(uri) # Check for absolute path if normalized_uri.relative? data = normalized_uri data = File.join(base_path, data) if data.path[0,1] != "/" normalized_uri = file_uri(data) end @normalize_cache[uri] = normalized_uri.freeze end normalized_uri end def self.parse(uri) if uri.is_a?(Addressable::URI) return uri.dup else @parse_cache ||= {} parsed_uri = @parse_cache[uri] if parsed_uri parsed_uri.dup else @parse_cache[uri] = Addressable::URI.parse(uri) end end rescue Addressable::URI::InvalidURIError => e raise JSON::Schema::UriError.new(e.message) end def self.strip_fragment(uri) parsed_uri = parse(uri) if parsed_uri.fragment.nil? || parsed_uri.fragment.empty? parsed_uri else parsed_uri.merge(:fragment => "") end end def self.file_uri(uri) parsed_uri = parse(uri) Addressable::URI.convert_path(parsed_uri.path) end def self.unescaped_uri(uri) parsed_uri = parse(uri) Addressable::URI.unescape(parsed_uri.path) end end end end json-schema-2.6.0/lib/json-schema/util/uuid.rb000066400000000000000000000205201264371451000211550ustar00rootroot00000000000000#!/usr/bin/env ruby ### http://mput.dip.jp/mput/uuid.txt # Copyright(c) 2005 URABE, Shyouhei. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this code, to deal in the code without restriction, including without # limitation the rights to use, copy, modify, merge, publish, distribute, # sublicense, and/or sell copies of the code, and to permit persons to whom the # code is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the code. # # THE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHOR OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE CODE OR THE USE OR OTHER DEALINGS IN THE # CODE. # # 2009-02-20: Modified by Pablo Lorenzoni to correctly # include the version in the raw_bytes. require 'digest/md5' require 'digest/sha1' require 'tmpdir' module JSON module Util # Pure ruby UUID generator, which is compatible with RFC4122 UUID = Struct.new :raw_bytes class UUID private_class_method :new class << self def mask19 v, str # :nodoc nstr = str.bytes.to_a version = [0, 16, 32, 48, 64, 80][v] nstr[6] &= 0b00001111 nstr[6] |= version # nstr[7] &= 0b00001111 # nstr[7] |= 0b01010000 nstr[8] &= 0b00111111 nstr[8] |= 0b10000000 str = '' nstr.each { |s| str << s.chr } str end def mask18 v, str # :nodoc version = [0, 16, 32, 48, 64, 80][v] str[6] &= 0b00001111 str[6] |= version # str[7] &= 0b00001111 # str[7] |= 0b01010000 str[8] &= 0b00111111 str[8] |= 0b10000000 str end def mask v, str if RUBY_VERSION >= "1.9.0" return mask19 v, str else return mask18 v, str end end private :mask, :mask18, :mask19 # UUID generation using SHA1. Recommended over create_md5. # Namespace object is another UUID, some of them are pre-defined below. def create_sha1 str, namespace sha1 = Digest::SHA1.new sha1.update namespace.raw_bytes sha1.update str sum = sha1.digest raw = mask 5, sum[0..15] ret = new raw ret.freeze ret end alias :create_v5 :create_sha1 # UUID generation using MD5 (for backward compat.) def create_md5 str, namespace md5 = Digest::MD5.new md5.update namespace.raw_bytes md5.update str sum = md5.digest raw = mask 3, sum[0..16] ret = new raw ret.freeze ret end alias :create_v3 :create_md5 # UUID generation using random-number generator. From it's random # nature, there's no warranty that the created ID is really universaly # unique. def create_random rnd = [ rand(0x100000000), rand(0x100000000), rand(0x100000000), rand(0x100000000), ].pack "N4" raw = mask 4, rnd ret = new raw ret.freeze ret end alias :create_v4 :create_random def read_state fp # :nodoc: fp.rewind Marshal.load fp.read end def write_state fp, c, m # :nodoc: fp.rewind str = Marshal.dump [c, m] fp.write str end private :read_state, :write_state STATE_FILE = 'ruby-uuid' # create the "version 1" UUID with current system clock, current UTC # timestamp, and the IEEE 802 address (so-called MAC address). # # Speed notice: it's slow. It writes some data into hard drive on every # invokation. If you want to speed this up, try remounting tmpdir with a # memory based filesystem (such as tmpfs). STILL slow? then no way but # rewrite it with c :) def create clock=nil, time=nil, mac_addr=nil c = t = m = nil Dir.chdir Dir.tmpdir do unless FileTest.exist? STATE_FILE then # Generate a pseudo MAC address because we have no pure-ruby way # to know the MAC address of the NIC this system uses. Note # that cheating with pseudo arresses here is completely legal: # see Section 4.5 of RFC4122 for details. sha1 = Digest::SHA1.new 256.times do r = [rand(0x100000000)].pack "N" sha1.update r end str = sha1.digest r = rand 14 # 20-6 node = str[r, 6] || str if RUBY_VERSION >= "1.9.0" nnode = node.bytes.to_a nnode[0] |= 0x01 node = '' nnode.each { |s| node << s.chr } else node[0] |= 0x01 # multicast bit end k = rand 0x40000 open STATE_FILE, 'w' do |fp| fp.flock IO::LOCK_EX write_state fp, k, node fp.chmod 0o777 # must be world writable end end open STATE_FILE, 'r+' do |fp| fp.flock IO::LOCK_EX c, m = read_state fp c = clock % 0x4000 if clock m = mac_addr if mac_addr t = time if t.nil? then # UUID epoch is 1582/Oct/15 tt = Time.now t = tt.to_i*10000000 + tt.tv_usec*10 + 0x01B21DD213814000 end c = c.succ # important; increment here write_state fp, c, m end end tl = t & 0xFFFF_FFFF tm = t >> 32 tm = tm & 0xFFFF th = t >> 48 th = th & 0x0FFF th = th | 0x1000 cl = c & 0xFF ch = c & 0x3F00 ch = ch >> 8 ch = ch | 0x80 pack tl, tm, th, cl, ch, m end alias :create_v1 :create # A simple GUID parser: just ignores unknown characters and convert # hexadecimal dump into 16-octet object. def parse obj str = obj.to_s.sub %r/\Aurn:uuid:/, '' str.gsub! %r/[^0-9A-Fa-f]/, '' raw = str[0..31].lines.to_a.pack 'H*' ret = new raw ret.freeze ret end # The 'primitive constructor' of this class # Note UUID.pack(uuid.unpack) == uuid def pack tl, tm, th, ch, cl, n raw = [tl, tm, th, ch, cl, n].pack "NnnCCa6" ret = new raw ret.freeze ret end end # The 'primitive deconstructor', or the dual to pack. # Note UUID.pack(uuid.unpack) == uuid def unpack raw_bytes.unpack "NnnCCa6" end # Generate the string representation (a.k.a GUID) of this UUID def to_s a = unpack tmp = a[-1].unpack 'C*' a[-1] = sprintf '%02x%02x%02x%02x%02x%02x', *tmp "%08x-%04x-%04x-%02x%02x-%s" % a end alias guid to_s # Convert into a RFC4122-comforming URN representation def to_uri "urn:uuid:" + self.to_s end alias urn to_uri # Convert into 128-bit unsigned integer # Typically a Bignum instance, but can be a Fixnum. def to_int tmp = self.raw_bytes.unpack "C*" tmp.inject do |r, i| r * 256 | i end end alias to_i to_int # Gets the version of this UUID # returns nil if bad version def version a = unpack v = (a[2] & 0xF000).to_s(16)[0].chr.to_i return v if (1..5).include? v return nil end # Two UUIDs are said to be equal if and only if their (byte-order # canonicalized) integer representations are equivallent. Refer RFC4122 for # details. def == other to_i == other.to_i end include Comparable # UUIDs are comparable (don't know what benefits are there, though). def <=> other to_s <=> other.to_s end # Pre-defined UUID Namespaces described in RFC4122 Appendix C. NameSpace_DNS = parse "6ba7b810-9dad-11d1-80b4-00c04fd430c8" NameSpace_URL = parse "6ba7b811-9dad-11d1-80b4-00c04fd430c8" NameSpace_OID = parse "6ba7b812-9dad-11d1-80b4-00c04fd430c8" NameSpace_X500 = parse "6ba7b814-9dad-11d1-80b4-00c04fd430c8" # The Nil UUID in RFC4122 Section 4.1.7 Nil = parse "00000000-0000-0000-0000-000000000000" end end endjson-schema-2.6.0/lib/json-schema/validator.rb000066400000000000000000000465371264371451000212370ustar00rootroot00000000000000require 'open-uri' require 'pathname' require 'bigdecimal' require 'digest/sha1' require 'date' require 'thread' require 'yaml' require 'json-schema/schema/reader' require 'json-schema/errors/schema_error' require 'json-schema/errors/schema_parse_error' require 'json-schema/errors/json_load_error' require 'json-schema/errors/json_parse_error' require 'json-schema/util/uri' module JSON class Validator @@schemas = {} @@cache_schemas = false @@default_opts = { :list => false, :version => nil, :validate_schema => false, :record_errors => false, :errors_as_objects => false, :insert_defaults => false, :clear_cache => true, :strict => false, :parse_data => true } @@validators = {} @@default_validator = nil @@available_json_backends = [] @@json_backend = nil @@serializer = nil @@mutex = Mutex.new def initialize(schema_data, data, opts={}) @options = @@default_opts.clone.merge(opts) @errors = [] validator = JSON::Validator.validator_for_name(@options[:version]) @options[:version] = validator @options[:schema_reader] ||= JSON::Validator.schema_reader @validation_options = @options[:record_errors] ? {:record_errors => true} : {} @validation_options[:insert_defaults] = true if @options[:insert_defaults] @validation_options[:strict] = true if @options[:strict] == true @validation_options[:clear_cache] = false if @options[:clear_cache] == false @@mutex.synchronize { @base_schema = initialize_schema(schema_data) } @original_data = data @data = initialize_data(data) @@mutex.synchronize { build_schemas(@base_schema) } # validate the schema, if requested if @options[:validate_schema] if @base_schema.schema["$schema"] base_validator = JSON::Validator.validator_for_name(@base_schema.schema["$schema"]) end metaschema = base_validator ? base_validator.metaschema : validator.metaschema # Don't clear the cache during metaschema validation! meta_validator = JSON::Validator.new(metaschema, @base_schema.schema, {:clear_cache => false}) meta_validator.validate end # If the :fragment option is set, try and validate against the fragment if opts[:fragment] @base_schema = schema_from_fragment(@base_schema, opts[:fragment]) end 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 if fragments.shift != "#" raise JSON::Schema::SchemaError.new("Invalid fragment syntax in :fragment option") end fragments.each do |f| if base_schema.is_a?(JSON::Schema) #test if fragment is a JSON:Schema instance 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] 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 = 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 = 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 end if @options[:list] base_schema.to_array_schema else base_schema end end # Run a simple true/false validation of data against a schema def validate() @base_schema.validate(@data,[],self,@validation_options) if @options[:errors_as_objects] return @errors.map{|e| e.to_hash} else return @errors.map{|e| e.to_string} end ensure if @validation_options[:clear_cache] == true Validator.clear_cache end if @validation_options[:insert_defaults] JSON::Validator.merge_missing_values(@data, @original_data) end end def load_ref_schema(parent_schema, ref) schema_uri = absolutize_ref_uri(ref, parent_schema.uri) return true if self.class.schema_loaded?(schema_uri) schema = @options[:schema_reader].read(schema_uri) self.class.add_schema(schema) build_schemas(schema) end def absolutize_ref_uri(ref, parent_schema_uri) ref_uri = JSON::Util::URI.strip_fragment(ref) return ref_uri if ref_uri.absolute? # This is a self reference and thus the schema does not need to be re-loaded return parent_schema_uri if ref_uri.path.empty? uri = JSON::Util::URI.strip_fragment(parent_schema_uri.dup) Util::URI.normalized_uri(uri.join(ref_uri.path)) end # Build all schemas with IDs, mapping out the namespace def build_schemas(parent_schema) schema = parent_schema.schema # Build ref schemas if they exist if schema["$ref"] load_ref_schema(parent_schema, schema["$ref"]) end case schema["extends"] when String load_ref_schema(parent_schema, schema["extends"]) when Array schema['extends'].each do |type| handle_schema(parent_schema, type) end end # Check for schemas in union types ["type", "disallow"].each do |key| if schema[key].is_a?(Array) schema[key].each do |type| if type.is_a?(Hash) handle_schema(parent_schema, type) end end end end # Schema properties whose values are objects, the values of which # are themselves schemas. %w[definitions properties patternProperties].each do |key| next unless value = schema[key] value.each do |k, inner_schema| handle_schema(parent_schema, inner_schema) end end # Schema properties whose values are themselves schemas. %w[additionalProperties additionalItems dependencies extends].each do |key| next unless schema[key].is_a?(Hash) handle_schema(parent_schema, schema[key]) end # Schema properties whose values may be an array of schemas. %w[allOf anyOf oneOf not].each do |key| next unless value = schema[key] Array(value).each do |inner_schema| handle_schema(parent_schema, inner_schema) end end # Items are always schemas if schema["items"] items = schema["items"].clone items = [items] unless items.is_a?(Array) items.each do |item| handle_schema(parent_schema, item) end end # Convert enum to a ArraySet if schema["enum"].is_a?(Array) schema["enum"] = ArraySet.new(schema["enum"]) end end # Either load a reference schema or create a new schema def handle_schema(parent_schema, obj) if obj.is_a?(Hash) schema_uri = parent_schema.uri.dup schema = JSON::Schema.new(obj, schema_uri, parent_schema.validator) if obj['id'] Validator.add_schema(schema) end build_schemas(schema) end end def validation_error(error) @errors.push(error) end def validation_errors @errors end class << self def validate(schema, data,opts={}) begin validator = JSON::Validator.new(schema, data, opts) validator.validate return true rescue JSON::Schema::ValidationError, JSON::Schema::SchemaError return false end end def validate_json(schema, data, opts={}) validate(schema, data, opts.merge(:json => true)) end def validate_uri(schema, data, opts={}) validate(schema, data, opts.merge(:uri => true)) end def validate!(schema, data,opts={}) validator = JSON::Validator.new(schema, data, opts) validator.validate return true end alias_method 'validate2', 'validate!' def validate_json!(schema, data, opts={}) validate!(schema, data, opts.merge(:json => true)) end def validate_uri!(schema, data, opts={}) validate!(schema, data, opts.merge(:uri => true)) end def fully_validate(schema, data, opts={}) opts[:record_errors] = true validator = JSON::Validator.new(schema, data, opts) validator.validate end def fully_validate_schema(schema, opts={}) data = schema schema = JSON::Validator.validator_for_name(opts[:version]).metaschema fully_validate(schema, data, opts) end def fully_validate_json(schema, data, opts={}) fully_validate(schema, data, opts.merge(:json => true)) end def fully_validate_uri(schema, data, opts={}) fully_validate(schema, data, opts.merge(:uri => true)) end def schema_reader @@schema_reader ||= JSON::Schema::Reader.new end def schema_reader=(reader) @@schema_reader = reader end def clear_cache @@schemas = {} if @@cache_schemas == false end def schemas @@schemas end def add_schema(schema) @@schemas[schema_key_for(schema.uri)] ||= schema end def schema_for_uri(uri) # We only store normalized uris terminated with fragment #, so we can try whether # normalization can be skipped @@schemas[uri] || @@schemas[schema_key_for(uri)] end def schema_loaded?(schema_uri) !schema_for_uri(schema_uri).nil? end def schema_key_for(uri) key = Util::URI.normalized_uri(uri).to_s key.end_with?('#') ? key : "#{key}#" end def cache_schemas=(val) warn "[DEPRECATION NOTICE] Schema caching is now a validation option. Schemas will still be cached if this is set to true, but this method will be removed in version >= 3. Please use the :clear_cache validation option instead." @@cache_schemas = val == true ? true : false end def validators @@validators end def default_validator @@default_validator end def validator_for_uri(schema_uri) return default_validator unless schema_uri u = JSON::Util::URI.parse(schema_uri) validator = validators["#{u.scheme}://#{u.host}#{u.path}"] if validator.nil? raise JSON::Schema::SchemaError.new("Schema not found: #{schema_uri}") else validator end end def validator_for_name(schema_name) return default_validator unless schema_name validator = validators_for_names([schema_name]).first if validator.nil? raise JSON::Schema::SchemaError.new("The requested JSON schema version is not supported") else validator end end alias_method :validator_for, :validator_for_uri def register_validator(v) @@validators["#{v.uri.scheme}://#{v.uri.host}#{v.uri.path}"] = v end def register_default_validator(v) @@default_validator = v end def register_format_validator(format, validation_proc, versions = ["draft1", "draft2", "draft3", "draft4", nil]) custom_format_validator = JSON::Schema::CustomFormat.new(validation_proc) validators_for_names(versions).each do |validator| validator.formats[format.to_s] = custom_format_validator end end def deregister_format_validator(format, versions = ["draft1", "draft2", "draft3", "draft4", nil]) validators_for_names(versions).each do |validator| validator.formats[format.to_s] = validator.default_formats[format.to_s] end end def restore_default_formats(versions = ["draft1", "draft2", "draft3", "draft4", nil]) validators_for_names(versions).each do |validator| validator.formats = validator.default_formats.clone end end def json_backend if defined?(MultiJson) MultiJson.respond_to?(:adapter) ? MultiJson.adapter : MultiJson.engine else @@json_backend end end def json_backend=(backend) if defined?(MultiJson) backend = backend == 'json' ? 'json_gem' : backend MultiJson.respond_to?(:use) ? MultiJson.use(backend) : MultiJson.engine = backend else backend = backend.to_s if @@available_json_backends.include?(backend) @@json_backend = backend else raise JSON::Schema::JsonParseError.new("The JSON backend '#{backend}' could not be found.") end end end def parse(s) if defined?(MultiJson) begin MultiJson.respond_to?(:adapter) ? MultiJson.load(s) : MultiJson.decode(s) rescue MultiJson::ParseError => e raise JSON::Schema::JsonParseError.new(e.message) end else case @@json_backend.to_s when 'json' begin JSON.parse(s, :quirks_mode => true) rescue JSON::ParserError => e raise JSON::Schema::JsonParseError.new(e.message) end when 'yajl' begin json = StringIO.new(s) parser = Yajl::Parser.new parser.parse(json) or raise JSON::Schema::JsonParseError.new("The JSON could not be parsed by yajl") rescue Yajl::ParseError => e raise JSON::Schema::JsonParseError.new(e.message) end else raise JSON::Schema::JsonParseError.new("No supported JSON parsers found. The following parsers are suported:\n * yajl-ruby\n * json") end end end def merge_missing_values(source, destination) case destination when Hash source.each do |key, source_value| destination_value = destination[key] || destination[key.to_sym] if destination_value.nil? destination[key] = source_value else merge_missing_values(source_value, destination_value) end end when Array source.each_with_index do |source_value, i| destination_value = destination[i] merge_missing_values(source_value, destination_value) end end end if !defined?(MultiJson) if Gem::Specification::find_all_by_name('json').any? require 'json' @@available_json_backends << 'json' @@json_backend = 'json' else # Try force-loading json for rubies > 1.9.2 begin require 'json' @@available_json_backends << 'json' @@json_backend = 'json' rescue LoadError end end if Gem::Specification::find_all_by_name('yajl-ruby').any? require 'yajl' @@available_json_backends << 'yajl' @@json_backend = 'yajl' end if @@json_backend == 'yajl' @@serializer = lambda{|o| Yajl::Encoder.encode(o) } elsif @@json_backend == 'json' @@serializer = lambda{|o| JSON.dump(o) } else @@serializer = lambda{|o| YAML.dump(o) } end end private def validators_for_names(names) names = names.map { |name| name.to_s } [].tap do |memo| validators.each do |_, validator| if (validator.names & names).any? memo << validator end end if names.include?('') memo << default_validator end end end end private if Gem::Specification::find_all_by_name('uuidtools').any? require 'uuidtools' @@fake_uuid_generator = lambda{|s| UUIDTools::UUID.sha1_create(UUIDTools::UUID_URL_NAMESPACE, s).to_s } else require 'json-schema/util/uuid' @@fake_uuid_generator = lambda{|s| JSON::Util::UUID.create_v5(s,JSON::Util::UUID::Nil).to_s } end def serialize schema if defined?(MultiJson) MultiJson.respond_to?(:dump) ? MultiJson.dump(schema) : MultiJson.encode(schema) else @@serializer.call(schema) end end def fake_uuid schema @@fake_uuid_generator.call(schema) end def initialize_schema(schema) if schema.is_a?(String) begin # Build a fake URI for this schema_uri = JSON::Util::URI.parse(fake_uuid(schema)) schema = JSON::Schema.new(JSON::Validator.parse(schema), schema_uri, @options[:version]) if @options[:list] && @options[:fragment].nil? schema = schema.to_array_schema end Validator.add_schema(schema) rescue JSON::Schema::JsonParseError # Build a uri for it schema_uri = Util::URI.normalized_uri(schema) if !self.class.schema_loaded?(schema_uri) schema = @options[:schema_reader].read(schema_uri) schema = JSON::Schema.stringify(schema) if @options[:list] && @options[:fragment].nil? schema = schema.to_array_schema end Validator.add_schema(schema) else schema = self.class.schema_for_uri(schema_uri) if @options[:list] && @options[:fragment].nil? schema = schema.to_array_schema schema.uri = JSON::Util::URI.parse(fake_uuid(serialize(schema.schema))) Validator.add_schema(schema) end schema end end elsif schema.is_a?(Hash) schema_uri = JSON::Util::URI.parse(fake_uuid(serialize(schema))) schema = JSON::Schema.stringify(schema) schema = JSON::Schema.new(schema, schema_uri, @options[:version]) if @options[:list] && @options[:fragment].nil? schema = schema.to_array_schema end Validator.add_schema(schema) else raise SchemaParseError, "Invalid schema - must be either a string or a hash" end schema end def initialize_data(data) if @options[:parse_data] if @options[:json] data = JSON::Validator.parse(data) elsif @options[:uri] json_uri = Util::URI.normalized_uri(data) data = JSON::Validator.parse(custom_open(json_uri)) elsif data.is_a?(String) begin data = JSON::Validator.parse(data) rescue JSON::Schema::JsonParseError begin json_uri = Util::URI.normalized_uri(data) data = JSON::Validator.parse(custom_open(json_uri)) rescue JSON::Schema::JsonLoadError # Silently discard the error - use the data as-is end end end end JSON::Schema.stringify(data) end def custom_open(uri) uri = Util::URI.normalized_uri(uri) if uri.is_a?(String) if uri.absolute? && Util::URI::SUPPORTED_PROTOCOLS.include?(uri.scheme) begin open(uri.to_s).read rescue OpenURI::HTTPError, Timeout::Error => e raise JSON::Schema::JsonLoadError, e.message end else begin File.read(JSON::Util::URI.unescaped_uri(uri)) rescue SystemCallError => e raise JSON::Schema::JsonLoadError, e.message end end end end end json-schema-2.6.0/lib/json-schema/validators/000077500000000000000000000000001264371451000210565ustar00rootroot00000000000000json-schema-2.6.0/lib/json-schema/validators/draft1.rb000066400000000000000000000031241264371451000225640ustar00rootroot00000000000000require 'json-schema/schema/validator' module JSON class Schema class Draft1 < Validator def initialize super @attributes = { "type" => JSON::Schema::TypeAttribute, "disallow" => JSON::Schema::DisallowAttribute, "format" => JSON::Schema::FormatAttribute, "maximum" => JSON::Schema::MaximumInclusiveAttribute, "minimum" => JSON::Schema::MinimumInclusiveAttribute, "minItems" => JSON::Schema::MinItemsAttribute, "maxItems" => JSON::Schema::MaxItemsAttribute, "minLength" => JSON::Schema::MinLengthAttribute, "maxLength" => JSON::Schema::MaxLengthAttribute, "maxDecimal" => JSON::Schema::MaxDecimalAttribute, "enum" => JSON::Schema::EnumAttribute, "properties" => JSON::Schema::PropertiesOptionalAttribute, "pattern" => JSON::Schema::PatternAttribute, "additionalProperties" => JSON::Schema::AdditionalPropertiesAttribute, "items" => JSON::Schema::ItemsAttribute, "extends" => JSON::Schema::ExtendsAttribute } @default_formats = { 'date-time' => DateTimeFormat, 'date' => DateFormat, 'time' => TimeFormat, 'ip-address' => IP4Format, 'ipv6' => IP6Format, 'uri' => UriFormat } @formats = @default_formats.clone @uri = JSON::Util::URI.parse("http://json-schema.org/draft-01/schema#") @names = ["draft1"] @metaschema_name = "draft-01.json" end JSON::Validator.register_validator(self.new) end end end json-schema-2.6.0/lib/json-schema/validators/draft2.rb000066400000000000000000000032251264371451000225670ustar00rootroot00000000000000require 'json-schema/schema/validator' module JSON class Schema class Draft2 < Validator def initialize super @attributes = { "type" => JSON::Schema::TypeAttribute, "disallow" => JSON::Schema::DisallowAttribute, "format" => JSON::Schema::FormatAttribute, "maximum" => JSON::Schema::MaximumInclusiveAttribute, "minimum" => JSON::Schema::MinimumInclusiveAttribute, "minItems" => JSON::Schema::MinItemsAttribute, "maxItems" => JSON::Schema::MaxItemsAttribute, "uniqueItems" => JSON::Schema::UniqueItemsAttribute, "minLength" => JSON::Schema::MinLengthAttribute, "maxLength" => JSON::Schema::MaxLengthAttribute, "divisibleBy" => JSON::Schema::DivisibleByAttribute, "enum" => JSON::Schema::EnumAttribute, "properties" => JSON::Schema::PropertiesOptionalAttribute, "pattern" => JSON::Schema::PatternAttribute, "additionalProperties" => JSON::Schema::AdditionalPropertiesAttribute, "items" => JSON::Schema::ItemsAttribute, "extends" => JSON::Schema::ExtendsAttribute } @default_formats = { 'date-time' => DateTimeFormat, 'date' => DateFormat, 'time' => TimeFormat, 'ip-address' => IP4Format, 'ipv6' => IP6Format, 'uri' => UriFormat } @formats = @default_formats.clone @uri = JSON::Util::URI.parse("http://json-schema.org/draft-02/schema#") @names = ["draft2"] @metaschema_name = "draft-02.json" end JSON::Validator.register_validator(self.new) end end end json-schema-2.6.0/lib/json-schema/validators/draft3.rb000066400000000000000000000036511264371451000225730ustar00rootroot00000000000000require 'json-schema/schema/validator' module JSON class Schema class Draft3 < Validator def initialize super @attributes = { "type" => JSON::Schema::TypeAttribute, "disallow" => JSON::Schema::DisallowAttribute, "format" => JSON::Schema::FormatAttribute, "maximum" => JSON::Schema::MaximumAttribute, "minimum" => JSON::Schema::MinimumAttribute, "minItems" => JSON::Schema::MinItemsAttribute, "maxItems" => JSON::Schema::MaxItemsAttribute, "uniqueItems" => JSON::Schema::UniqueItemsAttribute, "minLength" => JSON::Schema::MinLengthAttribute, "maxLength" => JSON::Schema::MaxLengthAttribute, "divisibleBy" => JSON::Schema::DivisibleByAttribute, "enum" => JSON::Schema::EnumAttribute, "properties" => JSON::Schema::PropertiesAttribute, "pattern" => JSON::Schema::PatternAttribute, "patternProperties" => JSON::Schema::PatternPropertiesAttribute, "additionalProperties" => JSON::Schema::AdditionalPropertiesAttribute, "items" => JSON::Schema::ItemsAttribute, "additionalItems" => JSON::Schema::AdditionalItemsAttribute, "dependencies" => JSON::Schema::DependenciesAttribute, "extends" => JSON::Schema::ExtendsAttribute, "$ref" => JSON::Schema::RefAttribute } @default_formats = { 'date-time' => DateTimeFormat, 'date' => DateFormat, 'ip-address' => IP4Format, 'ipv6' => IP6Format, 'time' => TimeFormat, 'uri' => UriFormat } @formats = @default_formats.clone @uri = JSON::Util::URI.parse("http://json-schema.org/draft-03/schema#") @names = ["draft3", "http://json-schema.org/draft-03/schema#"] @metaschema_name = "draft-03.json" end JSON::Validator.register_validator(self.new) end end end json-schema-2.6.0/lib/json-schema/validators/draft4.rb000066400000000000000000000044531264371451000225750ustar00rootroot00000000000000require 'json-schema/schema/validator' module JSON class Schema class Draft4 < Validator def initialize super @attributes = { "type" => JSON::Schema::TypeV4Attribute, "allOf" => JSON::Schema::AllOfAttribute, "anyOf" => JSON::Schema::AnyOfAttribute, "oneOf" => JSON::Schema::OneOfAttribute, "not" => JSON::Schema::NotAttribute, "disallow" => JSON::Schema::DisallowAttribute, "format" => JSON::Schema::FormatAttribute, "maximum" => JSON::Schema::MaximumAttribute, "minimum" => JSON::Schema::MinimumAttribute, "minItems" => JSON::Schema::MinItemsAttribute, "maxItems" => JSON::Schema::MaxItemsAttribute, "minProperties" => JSON::Schema::MinPropertiesAttribute, "maxProperties" => JSON::Schema::MaxPropertiesAttribute, "uniqueItems" => JSON::Schema::UniqueItemsAttribute, "minLength" => JSON::Schema::MinLengthAttribute, "maxLength" => JSON::Schema::MaxLengthAttribute, "multipleOf" => JSON::Schema::MultipleOfAttribute, "enum" => JSON::Schema::EnumAttribute, "properties" => JSON::Schema::PropertiesV4Attribute, "required" => JSON::Schema::RequiredAttribute, "pattern" => JSON::Schema::PatternAttribute, "patternProperties" => JSON::Schema::PatternPropertiesAttribute, "additionalProperties" => JSON::Schema::AdditionalPropertiesAttribute, "items" => JSON::Schema::ItemsAttribute, "additionalItems" => JSON::Schema::AdditionalItemsAttribute, "dependencies" => JSON::Schema::DependenciesV4Attribute, "extends" => JSON::Schema::ExtendsAttribute, "$ref" => JSON::Schema::RefAttribute } @default_formats = { 'date-time' => DateTimeV4Format, 'ipv4' => IP4Format, 'ipv6' => IP6Format, 'uri' => UriFormat } @formats = @default_formats.clone @uri = JSON::Util::URI.parse("http://json-schema.org/draft-04/schema#") @names = ["draft4", "http://json-schema.org/draft-04/schema#"] @metaschema_name = "draft-04.json" end JSON::Validator.register_validator(self.new) JSON::Validator.register_default_validator(self.new) end end end json-schema-2.6.0/lib/json-schema/validators/hyper-draft1.rb000066400000000000000000000004041264371451000237070ustar00rootroot00000000000000module JSON class Schema class HyperDraft1 < Draft1 def initialize super @uri = JSON::Util::URI.parse("http://json-schema.org/draft-01/hyper-schema#") end JSON::Validator.register_validator(self.new) end end end json-schema-2.6.0/lib/json-schema/validators/hyper-draft2.rb000066400000000000000000000004041264371451000237100ustar00rootroot00000000000000module JSON class Schema class HyperDraft2 < Draft2 def initialize super @uri = JSON::Util::URI.parse("http://json-schema.org/draft-02/hyper-schema#") end JSON::Validator.register_validator(self.new) end end end json-schema-2.6.0/lib/json-schema/validators/hyper-draft4.rb000066400000000000000000000004041264371451000237120ustar00rootroot00000000000000module JSON class Schema class HyperDraft4 < Draft4 def initialize super @uri = JSON::Util::URI.parse("http://json-schema.org/draft-04/hyper-schema#") end JSON::Validator.register_validator(self.new) end end end json-schema-2.6.0/resources/000077500000000000000000000000001264371451000157435ustar00rootroot00000000000000json-schema-2.6.0/resources/draft-01.json000066400000000000000000000047131264371451000201610ustar00rootroot00000000000000{ "$schema" : "http://json-schema.org/draft-01/hyper-schema#", "id" : "http://json-schema.org/draft-01/schema#", "type" : "object", "properties" : { "type" : { "type" : ["string", "array"], "items" : { "type" : ["string", {"$ref" : "#"}] }, "optional" : true, "default" : "any" }, "properties" : { "type" : "object", "additionalProperties" : {"$ref" : "#"}, "optional" : true, "default" : {} }, "items" : { "type" : [{"$ref" : "#"}, "array"], "items" : {"$ref" : "#"}, "optional" : true, "default" : {} }, "optional" : { "type" : "boolean", "optional" : true, "default" : false }, "additionalProperties" : { "type" : [{"$ref" : "#"}, "boolean"], "optional" : true, "default" : {} }, "requires" : { "type" : ["string", {"$ref" : "#"}], "optional" : true }, "minimum" : { "type" : "number", "optional" : true }, "maximum" : { "type" : "number", "optional" : true }, "minimumCanEqual" : { "type" : "boolean", "optional" : true, "requires" : "minimum", "default" : true }, "maximumCanEqual" : { "type" : "boolean", "optional" : true, "requires" : "maximum", "default" : true }, "minItems" : { "type" : "integer", "optional" : true, "minimum" : 0, "default" : 0 }, "maxItems" : { "type" : "integer", "optional" : true, "minimum" : 0 }, "pattern" : { "type" : "string", "optional" : true, "format" : "regex" }, "minLength" : { "type" : "integer", "optional" : true, "minimum" : 0, "default" : 0 }, "maxLength" : { "type" : "integer", "optional" : true }, "enum" : { "type" : "array", "optional" : true, "minItems" : 1 }, "title" : { "type" : "string", "optional" : true }, "description" : { "type" : "string", "optional" : true }, "format" : { "type" : "string", "optional" : true }, "contentEncoding" : { "type" : "string", "optional" : true }, "default" : { "type" : "any", "optional" : true }, "maxDecimal" : { "type" : "integer", "optional" : true, "minimum" : 0 }, "disallow" : { "type" : ["string", "array"], "items" : {"type" : "string"}, "optional" : true }, "extends" : { "type" : [{"$ref" : "#"}, "array"], "items" : {"$ref" : "#"}, "optional" : true, "default" : {} } }, "optional" : true, "default" : {} }json-schema-2.6.0/resources/draft-02.json000066400000000000000000000052441264371451000201620ustar00rootroot00000000000000{ "$schema" : "http://json-schema.org/draft-02/hyper-schema#", "id" : "http://json-schema.org/draft-02/schema#", "type" : "object", "properties" : { "type" : { "type" : ["string", "array"], "items" : { "type" : ["string", {"$ref" : "#"}] }, "optional" : true, "uniqueItems" : true, "default" : "any" }, "properties" : { "type" : "object", "additionalProperties" : {"$ref" : "#"}, "optional" : true, "default" : {} }, "items" : { "type" : [{"$ref" : "#"}, "array"], "items" : {"$ref" : "#"}, "optional" : true, "default" : {} }, "optional" : { "type" : "boolean", "optional" : true, "default" : false }, "additionalProperties" : { "type" : [{"$ref" : "#"}, "boolean"], "optional" : true, "default" : {} }, "requires" : { "type" : ["string", {"$ref" : "#"}], "optional" : true }, "minimum" : { "type" : "number", "optional" : true }, "maximum" : { "type" : "number", "optional" : true }, "minimumCanEqual" : { "type" : "boolean", "optional" : true, "requires" : "minimum", "default" : true }, "maximumCanEqual" : { "type" : "boolean", "optional" : true, "requires" : "maximum", "default" : true }, "minItems" : { "type" : "integer", "optional" : true, "minimum" : 0, "default" : 0 }, "maxItems" : { "type" : "integer", "optional" : true, "minimum" : 0 }, "uniqueItems" : { "type" : "boolean", "optional" : true, "default" : false }, "pattern" : { "type" : "string", "optional" : true, "format" : "regex" }, "minLength" : { "type" : "integer", "optional" : true, "minimum" : 0, "default" : 0 }, "maxLength" : { "type" : "integer", "optional" : true }, "enum" : { "type" : "array", "optional" : true, "minItems" : 1, "uniqueItems" : true }, "title" : { "type" : "string", "optional" : true }, "description" : { "type" : "string", "optional" : true }, "format" : { "type" : "string", "optional" : true }, "contentEncoding" : { "type" : "string", "optional" : true }, "default" : { "type" : "any", "optional" : true }, "divisibleBy" : { "type" : "number", "minimum" : 0, "minimumCanEqual" : false, "optional" : true, "default" : 1 }, "disallow" : { "type" : ["string", "array"], "items" : {"type" : "string"}, "optional" : true, "uniqueItems" : true }, "extends" : { "type" : [{"$ref" : "#"}, "array"], "items" : {"$ref" : "#"}, "optional" : true, "default" : {} } }, "optional" : true, "default" : {} }json-schema-2.6.0/resources/draft-03.json000066400000000000000000000052141264371451000201600ustar00rootroot00000000000000{ "$schema" : "http://json-schema.org/draft-03/schema#", "id" : "http://json-schema.org/draft-03/schema#", "type" : "object", "properties" : { "type" : { "type" : ["string", "array"], "items" : { "type" : ["string", {"$ref" : "#"}] }, "uniqueItems" : true, "default" : "any" }, "properties" : { "type" : "object", "additionalProperties" : {"$ref" : "#"}, "default" : {} }, "patternProperties" : { "type" : "object", "additionalProperties" : {"$ref" : "#"}, "default" : {} }, "additionalProperties" : { "type" : [{"$ref" : "#"}, "boolean"], "default" : {} }, "items" : { "type" : [{"$ref" : "#"}, "array"], "items" : {"$ref" : "#"}, "default" : {} }, "additionalItems" : { "type" : [{"$ref" : "#"}, "boolean"], "default" : {} }, "required" : { "type" : "boolean", "default" : false }, "dependencies" : { "type" : "object", "additionalProperties" : { "type" : ["string", "array", {"$ref" : "#"}], "items" : { "type" : "string" } }, "default" : {} }, "minimum" : { "type" : "number" }, "maximum" : { "type" : "number" }, "exclusiveMinimum" : { "type" : "boolean", "default" : false }, "exclusiveMaximum" : { "type" : "boolean", "default" : false }, "minItems" : { "type" : "integer", "minimum" : 0, "default" : 0 }, "maxItems" : { "type" : "integer", "minimum" : 0 }, "uniqueItems" : { "type" : "boolean", "default" : false }, "pattern" : { "type" : "string", "format" : "regex" }, "minLength" : { "type" : "integer", "minimum" : 0, "default" : 0 }, "maxLength" : { "type" : "integer" }, "enum" : { "type" : "array", "minItems" : 1, "uniqueItems" : true }, "default" : { "type" : "any" }, "title" : { "type" : "string" }, "description" : { "type" : "string" }, "format" : { "type" : "string" }, "divisibleBy" : { "type" : "number", "minimum" : 0, "exclusiveMinimum" : true, "default" : 1 }, "disallow" : { "type" : ["string", "array"], "items" : { "type" : ["string", {"$ref" : "#"}] }, "uniqueItems" : true }, "extends" : { "type" : [{"$ref" : "#"}, "array"], "items" : {"$ref" : "#"}, "default" : {} }, "id" : { "type" : "string", "format" : "uri" }, "$ref" : { "type" : "string", "format" : "uri" }, "$schema" : { "type" : "string", "format" : "uri" } }, "dependencies" : { "exclusiveMinimum" : "minimum", "exclusiveMaximum" : "maximum" }, "default" : {} }json-schema-2.6.0/resources/draft-04.json000066400000000000000000000104271264371451000201630ustar00rootroot00000000000000{ "id": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#", "description": "Core schema meta-schema", "definitions": { "schemaArray": { "type": "array", "minItems": 1, "items": { "$ref": "#" } }, "positiveInteger": { "type": "integer", "minimum": 0 }, "positiveIntegerDefault0": { "allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ] }, "simpleTypes": { "enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ] }, "stringArray": { "type": "array", "items": { "type": "string" }, "minItems": 1, "uniqueItems": true } }, "type": "object", "properties": { "id": { "type": "string", "format": "uri" }, "$schema": { "type": "string", "format": "uri" }, "title": { "type": "string" }, "description": { "type": "string" }, "default": {}, "multipleOf": { "type": "number", "minimum": 0, "exclusiveMinimum": true }, "maximum": { "type": "number" }, "exclusiveMaximum": { "type": "boolean", "default": false }, "minimum": { "type": "number" }, "exclusiveMinimum": { "type": "boolean", "default": false }, "maxLength": { "$ref": "#/definitions/positiveInteger" }, "minLength": { "$ref": "#/definitions/positiveIntegerDefault0" }, "pattern": { "type": "string", "format": "regex" }, "additionalItems": { "anyOf": [ { "type": "boolean" }, { "$ref": "#" } ], "default": {} }, "items": { "anyOf": [ { "$ref": "#" }, { "$ref": "#/definitions/schemaArray" } ], "default": {} }, "maxItems": { "$ref": "#/definitions/positiveInteger" }, "minItems": { "$ref": "#/definitions/positiveIntegerDefault0" }, "uniqueItems": { "type": "boolean", "default": false }, "maxProperties": { "$ref": "#/definitions/positiveInteger" }, "minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" }, "required": { "$ref": "#/definitions/stringArray" }, "additionalProperties": { "anyOf": [ { "type": "boolean" }, { "$ref": "#" } ], "default": {} }, "definitions": { "type": "object", "additionalProperties": { "$ref": "#" }, "default": {} }, "properties": { "type": "object", "additionalProperties": { "$ref": "#" }, "default": {} }, "patternProperties": { "type": "object", "additionalProperties": { "$ref": "#" }, "default": {} }, "dependencies": { "type": "object", "additionalProperties": { "anyOf": [ { "$ref": "#" }, { "$ref": "#/definitions/stringArray" } ] } }, "enum": { "type": "array", "minItems": 1, "uniqueItems": true }, "type": { "anyOf": [ { "$ref": "#/definitions/simpleTypes" }, { "type": "array", "items": { "$ref": "#/definitions/simpleTypes" }, "minItems": 1, "uniqueItems": true } ] }, "allOf": { "$ref": "#/definitions/schemaArray" }, "anyOf": { "$ref": "#/definitions/schemaArray" }, "oneOf": { "$ref": "#/definitions/schemaArray" }, "not": { "$ref": "#" } }, "dependencies": { "exclusiveMaximum": [ "maximum" ], "exclusiveMinimum": [ "minimum" ] }, "default": {} } json-schema-2.6.0/test/000077500000000000000000000000001264371451000147105ustar00rootroot00000000000000json-schema-2.6.0/test/data/000077500000000000000000000000001264371451000156215ustar00rootroot00000000000000json-schema-2.6.0/test/data/all_of_ref_data.json000066400000000000000000000000261264371451000215730ustar00rootroot00000000000000{ "name" : "john" } json-schema-2.6.0/test/data/any_of_ref_data.json000066400000000000000000000000761264371451000216170ustar00rootroot00000000000000{ "names" : [ "john" , "jane" , "jimmy" ] } json-schema-2.6.0/test/data/bad_data_1.json000066400000000000000000000000221264371451000204450ustar00rootroot00000000000000{ "a" : "poop" }json-schema-2.6.0/test/data/good_data_1.json000066400000000000000000000000151264371451000206510ustar00rootroot00000000000000{ "a" : 5 }json-schema-2.6.0/test/data/one_of_ref_links_data.json000066400000000000000000000002331264371451000230040ustar00rootroot00000000000000{ "links": [{ "rel" : ["self"] , "href":"http://api.example.com/api/object/3" } ,{ "rel" : ["up"] , "href":"http://api.example.com/api/object" } ] } json-schema-2.6.0/test/schemas/000077500000000000000000000000001264371451000163335ustar00rootroot00000000000000json-schema-2.6.0/test/schemas/address_microformat.json000066400000000000000000000012001264371451000232460ustar00rootroot00000000000000{ "description": "An Address following the convention of http://microformats.org/wiki/hcard", "type": "object", "properties": { "post-office-box": { "type": "string" }, "extended-address": { "type": "string" }, "street-address": { "type": "string" }, "locality":{ "type": "string" }, "region": { "type": "string" }, "postal-code": { "type": "string" }, "country-name": { "type": "string"} }, "required": ["locality", "region", "country-name"], "dependencies": { "post-office-box": "street-address", "extended-address": "street-address" } } json-schema-2.6.0/test/schemas/all_of_ref_base_schema.json000066400000000000000000000001211264371451000236220ustar00rootroot00000000000000{ "type": "object", "properties" : { "name" : { "type": "integer" } } } json-schema-2.6.0/test/schemas/all_of_ref_schema.json000066400000000000000000000002201264371451000226300ustar00rootroot00000000000000{ "$schema" : "http://json-schema.org/draft-04/schema#", "type" : "object", "allOf" : [ { "$ref" : "all_of_ref_base_schema.json" } ] } json-schema-2.6.0/test/schemas/any_of_ref_jane_schema.json000066400000000000000000000001431264371451000236500ustar00rootroot00000000000000{ "$schema" : "http://json-schema.org/draft-04/schema#" , "type" : "string" , "pattern" : "jane" } json-schema-2.6.0/test/schemas/any_of_ref_jimmy_schema.json000066400000000000000000000001441264371451000240610ustar00rootroot00000000000000{ "$schema" : "http://json-schema.org/draft-04/schema#" , "type" : "string" , "pattern" : "jimmy" } json-schema-2.6.0/test/schemas/any_of_ref_john_schema.json000066400000000000000000000001431264371451000236710ustar00rootroot00000000000000{ "$schema" : "http://json-schema.org/draft-04/schema#" , "type" : "string" , "pattern" : "john" } json-schema-2.6.0/test/schemas/any_of_ref_schema.json000066400000000000000000000005421264371451000226560ustar00rootroot00000000000000{ "$schema" : "http://json-schema.org/draft-04/schema#" , "type" : "object" , "properties" : { "names" : { "type" : "array" , "items" : { "anyOf" : [ { "$ref" : "any_of_ref_john_schema.json" } , { "$ref" : "any_of_ref_jane_schema.json" } , { "$ref" : "any_of_ref_jimmy_schema.json" } ] } } } } json-schema-2.6.0/test/schemas/definition_schema.json000066400000000000000000000004071264371451000226770ustar00rootroot00000000000000{ "$schema": "http://json-schema.org/draft-04/schema#", "description": "schema with definition", "type": "object", "properties": { "a": { "$ref": "#/definitions/foo" } }, "definitions": { "foo": { "type": "integer" } } } json-schema-2.6.0/test/schemas/extends_and_additionalProperties-1-filename.schema.json000066400000000000000000000013061264371451000311420ustar00rootroot00000000000000{ "$schema": "http://json-schema.org/draft-03/schema#", "type": "object", "extends": "inner.schema.json", "properties": { "outerA": { "description": "blah", "required": false, "additionalProperties": false, "properties": { "outerA1": { "type":"boolean", "required": false } } }, "outerB": { "required": false, "type": "array", "minItems": 1, "maxItems": 50, "items": { "extends": "inner.schema.json", "additionalProperties": false } }, "outerC": { "description": "blah", "type":"boolean", "required": false } }, "additionalProperties": false } json-schema-2.6.0/test/schemas/extends_and_additionalProperties-1-ref.schema.json000066400000000000000000000013321264371451000301350ustar00rootroot00000000000000{ "$schema": "http://json-schema.org/draft-03/schema#", "type": "object", "extends": {"$ref":"inner.schema.json#"}, "properties": { "outerA": { "description": "blah", "required": false, "additionalProperties": false, "properties": { "outerA1": { "type":"boolean", "required": false } } }, "outerB": { "required": false, "type": "array", "minItems": 1, "maxItems": 50, "items": { "extends": {"$ref":"inner.schema.json#"}, "additionalProperties": false } }, "outerC": { "description": "blah", "type":"boolean", "required": false } }, "additionalProperties": false } json-schema-2.6.0/test/schemas/extends_and_additionalProperties-2-filename.schema.json000066400000000000000000000012571264371451000311500ustar00rootroot00000000000000{ "$schema": "http://json-schema.org/draft-03/schema#", "type": "object", "extends": "inner.schema.json", "additionalProperties": { "outerA": { "description": "blah", "required": false, "additionalProperties": false, "properties": { "outerA1": { "type":"boolean", "required": false } } }, "outerB": { "required": false, "type": "array", "minItems": 1, "maxItems": 50, "items": { "extends": "inner.schema.json", "additionalProperties": false } }, "outerC": { "description": "blah", "type":"boolean", "required": false } } } json-schema-2.6.0/test/schemas/extends_and_additionalProperties-2-ref.schema.json000066400000000000000000000013031264371451000301340ustar00rootroot00000000000000{ "$schema": "http://json-schema.org/draft-03/schema#", "type": "object", "extends": {"$ref":"inner.schema.json#"}, "additionalProperties": { "outerA": { "description": "blah", "required": false, "additionalProperties": false, "properties": { "outerA1": { "type":"boolean", "required": false } } }, "outerB": { "required": false, "type": "array", "minItems": 1, "maxItems": 50, "items": { "extends": {"$ref":"inner.schema.json#"}, "additionalProperties": false } }, "outerC": { "description": "blah", "type":"boolean", "required": false } } } json-schema-2.6.0/test/schemas/good_schema_1.json000066400000000000000000000002541264371451000217170ustar00rootroot00000000000000{ "$schema" : "http://json-schema.org/draft-03/schema#", "type" : "object", "properties" : { "a" : { "type" : "integer", "required" : true } } }json-schema-2.6.0/test/schemas/good_schema_2.json000066400000000000000000000002701264371451000217160ustar00rootroot00000000000000{ "$schema" : "http://json-schema.org/draft-03/schema#", "type" : "object", "properties" : { "b" : { "required" : true, "$ref" : "good_schema_1.json" } } } json-schema-2.6.0/test/schemas/good_schema_extends1.json000066400000000000000000000003011264371451000233030ustar00rootroot00000000000000{ "$schema" : "http://json-schema.org/draft-03/schema#", "type" : "object", "extends": {"$ref": "good_schema_1.json"}, "properties" : { "c" : { "required" : false } } } json-schema-2.6.0/test/schemas/good_schema_extends2.json000066400000000000000000000003571264371451000233170ustar00rootroot00000000000000{ "$schema" : "http://json-schema.org/draft-03/schema#", "type" : "object", "extends": [ {"$ref": "good_schema_1.json"}, {"$ref": "good_schema_2.json"} ], "properties" : { "c" : { "required" : false } } } json-schema-2.6.0/test/schemas/inner.schema.json000066400000000000000000000006221264371451000216000ustar00rootroot00000000000000{ "$schema": "http://json-schema.org/draft-03/schema#", "type": "object", "properties": { "innerA": { "description": "blah", "type":"boolean", "required": false }, "innerB": { "description": "blah", "type":"boolean", "required": false }, "innerC": { "description": "blah", "required": false, "type": "boolean" } } } json-schema-2.6.0/test/schemas/one_of_ref_links_schema.json000066400000000000000000000004651264371451000240540ustar00rootroot00000000000000{ "$schema": "http://json-schema.org/draft-04/schema#" , "type": "object" , "properties": { "links" : { "type" : "array" , "items" : { "type" : "object" , "oneOf" : [ { "$ref" : "self_link_schema.json"} , { "$ref" : "up_link_schema.json" } ] } } } } json-schema-2.6.0/test/schemas/ref john with spaces schema.json000066400000000000000000000003061264371451000243340ustar00rootroot00000000000000{ "$schema" : "http://json-schema.org/draft-04/schema#", "type" : "object", "required" : ["first"], "properties": { "first": { "type": "string", "enum": ["john"] } } } json-schema-2.6.0/test/schemas/relative_definition_schema.json000066400000000000000000000002321264371451000245660ustar00rootroot00000000000000{ "$schema": "http://json-schema.org/draft-04/schema#", "properties": { "a": { "$ref": "definition_schema.json#/definitions/foo" } } }json-schema-2.6.0/test/schemas/self_link_schema.json000066400000000000000000000004211264371451000225110ustar00rootroot00000000000000{ "$schema": "http://json-schema.org/draft-04/schema#" , "type": "object" , "properties" : { "rel" : { "type" : "array" , "items" : [ { "type" : "string" , "pattern" : "self" } ] } , "href" : { "type" : "string" } } } json-schema-2.6.0/test/schemas/up_link_schema.json000066400000000000000000000004171264371451000222110ustar00rootroot00000000000000{ "$schema": "http://json-schema.org/draft-04/schema#" , "type": "object" , "properties" : { "rel" : { "type" : "array" , "items" : [ { "type" : "string" , "pattern" : "up" } ] } , "href" : { "type" : "string" } } } json-schema-2.6.0/test/support/000077500000000000000000000000001264371451000164245ustar00rootroot00000000000000json-schema-2.6.0/test/support/array_validation.rb000066400000000000000000000047561264371451000223150ustar00rootroot00000000000000module ArrayValidation module ItemsTests def test_items_single_schema schema = { 'items' => { 'type' => 'string' } } assert_valid schema, [] assert_valid schema, ['a'] assert_valid schema, ['a', 'b'] refute_valid schema, [1] refute_valid schema, ['a', 1] # other types are disregarded assert_valid schema, {'a' => 'foo'} end def test_items_multiple_schemas schema = { 'items' => [ { 'type' => 'string' }, { 'type' => 'integer' } ] } assert_valid schema, ['b', 1] assert_valid schema, ['b', 1, nil] refute_valid schema, [1, 'b'] refute_valid schema, [] end def test_minitems schema = { 'minItems' => 1 } assert_valid schema, [1] assert_valid schema, [1, 2] refute_valid schema, [] # other types are disregarded assert_valid schema, 5 end def test_maxitems schema = { 'maxItems' => 1 } assert_valid schema, [] assert_valid schema, [1] refute_valid schema, [1, 2] # other types are disregarded assert_valid schema, 5 end end module AdditionalItemsTests def test_additional_items_false schema = { 'items' => [ { 'type' => 'integer' }, { 'type' => 'string' } ], 'additionalItems' => false } assert_valid schema, [1, 'string'] refute_valid schema, [1, 'string', 2] refute_valid schema, ['string', 1] end def test_additional_items_schema schema = { 'items' => [ { 'type' => 'integer' }, { 'type' => 'string' } ], 'additionalItems' => { 'type' => 'integer' } } assert_valid schema, [1, 'string'] assert_valid schema, [1, 'string', 2] refute_valid schema, [1, 'string', 'string'] end end module UniqueItemsTests def test_unique_items schema = { 'uniqueItems' => true } assert_valid schema, [nil, 5] refute_valid schema, [nil, nil] assert_valid schema, [true, false] refute_valid schema, [true, true] assert_valid schema, [4, 4.1] refute_valid schema, [4, 4] assert_valid schema, ['a', 'ab'] refute_valid schema, ['a', 'a'] assert_valid schema, [[1], [2]] refute_valid schema, [[1], [1]] assert_valid schema, [{'b' => 1}, {'c' => 2}] assert_valid schema, [{'b' => 1}, {'c' => 1}] refute_valid schema, [{'b' => 1}, {'b' => 1}] end end end json-schema-2.6.0/test/support/enum_validation.rb000066400000000000000000000047521264371451000221370ustar00rootroot00000000000000module EnumValidation module V1_V2 def test_enum_optional schema = { "properties" => { "a" => {"enum" => [1,'boo',[1,2,3],{"a" => "b"}], "optional" => true} } } data = {} assert_valid schema, data end end module V3_V4 def test_enum_optional schema = { "properties" => { "a" => {"enum" => [1,'boo',[1,2,3],{"a" => "b"}]} } } data = {} assert_valid schema, data end end module General def test_enum_general schema = { "properties" => { "a" => {"enum" => [1,'boo',[1,2,3],{"a" => "b"}]} } } data = { "a" => 1 } assert_valid schema, data data["a"] = 'boo' assert_valid schema, data data["a"] = [1,2,3] assert_valid schema, data data["a"] = {"a" => "b"} assert_valid schema, data data["a"] = 'taco' refute_valid schema, data end def test_enum_number_integer_includes_float schema = { "properties" => { "a" => { "type" => "number", "enum" => [0, 1, 2] } } } data = { "a" => 0 } assert_valid schema, data data["a"] = 0.0 assert_valid schema, data data["a"] = 1 assert_valid schema, data data["a"] = 1.0 assert_valid schema, data end def test_enum_number_float_includes_integer schema = { "properties" => { "a" => { "type" => "number", "enum" => [0.0, 1.0, 2.0] } } } data = { "a" => 0.0 } assert_valid schema, data data["a"] = 0 assert_valid schema, data data["a"] = 1.0 assert_valid schema, data data["a"] = 1 assert_valid schema, data end def test_enum_integer_excludes_float schema = { "properties" => { "a" => { "type" => "integer", "enum" => [0, 1, 2] } } } data = { "a" => 0 } assert_valid schema, data data["a"] = 0.0 refute_valid schema, data data["a"] = 1 assert_valid schema, data data["a"] = 1.0 refute_valid schema, data end def test_enum_with_schema_validation schema = { "properties" => { "a" => {"enum" => [1,'boo',[1,2,3],{"a" => "b"}]} } } data = { "a" => 1 } assert_valid(schema, data, :validate_schema => true) end end end json-schema-2.6.0/test/support/number_validation.rb000066400000000000000000000037621264371451000224630ustar00rootroot00000000000000module NumberValidation module MinMaxTests def test_minimum schema = { 'properties' => { 'a' => { 'minimum' => 5 } } } assert_valid schema, {'a' => 5} assert_valid schema, {'a' => 6} refute_valid schema, {'a' => 4} refute_valid schema, {'a' => 4.99999} # other types are disregarded assert_valid schema, {'a' => 'str'} end def test_exclusive_minimum schema = { 'properties' => { 'a' => { 'minimum' => 5 }.merge(exclusive_minimum) } } assert_valid schema, {'a' => 6} assert_valid schema, {'a' => 5.0001} refute_valid schema, {'a' => 5} end def test_maximum schema = { 'properties' => { 'a' => { 'maximum' => 5 } } } assert_valid schema, {'a' => 4} assert_valid schema, {'a' => 5} refute_valid schema, {'a' => 6} refute_valid schema, {'a' => 5.0001} end def test_exclusive_maximum schema = { 'properties' => { 'a' => { 'maximum' => 5 }.merge(exclusive_maximum) } } assert_valid schema, {'a' => 4} assert_valid schema, {'a' => 4.99999} refute_valid schema, {'a' => 5} end end # draft3 introduced `divisibleBy`, renamed to `multipleOf` in draft4. # Favor the newer name, but the behavior should be identical. module MultipleOfTests def multiple_of 'multipleOf' end def test_multiple_of schema = { 'properties' => { 'a' => { multiple_of => 1.1 } } } assert_valid schema, {'a' => 0} assert_valid schema, {'a' => 2.2} refute_valid schema, {'a' => 3.4} # other types are disregarded assert_valid schema, {'a' => 'hi'} end def test_multiple_of_zero schema = { 'properties' => { 'a' => { multiple_of => 0 } } } refute_valid schema, {'a' => 5} refute_valid schema, {'a' => 0} end end end json-schema-2.6.0/test/support/object_validation.rb000066400000000000000000000034561264371451000224410ustar00rootroot00000000000000module ObjectValidation module AdditionalPropertiesTests def test_additional_properties_false schema = { 'properties' => { 'a' => { 'type' => 'integer' } }, 'additionalProperties' => false } assert_valid schema, {'a' => 1} refute_valid schema, {'a' => 1, 'b' => 2} end def test_additional_properties_schema schema = { 'properties' => { 'a' => { 'type' => 'integer' } }, 'additionalProperties' => { 'type' => 'string' } } assert_valid schema, {'a' => 1} assert_valid schema, {'a' => 1, 'b' => 'hi'} refute_valid schema, {'a' => 1, 'b' => 2} end end module PatternPropertiesTests def test_pattern_properties schema = { 'patternProperties' => { "\\d+ taco" => { 'type' => 'integer' } } } assert_valid schema, {'1 taco' => 1, '20 taco' => 20} assert_valid schema, {'foo' => true, '1 taco' => 1} refute_valid schema, {'1 taco' => 'yum'} end def test_pattern_properties_additional_properties_false schema = { 'patternProperties' => { "\\d+ taco" => { 'type' => 'integer' } }, 'additionalProperties' => false } assert_valid schema, {'1 taco' => 1} refute_valid schema, {'1 taco' => 'yum'} refute_valid schema, {'1 taco' => 1, 'foo' => true} end def test_pattern_properties_additional_properties_schema schema = { 'patternProperties' => { "\\d+ taco" => { 'type' => 'integer' } }, 'additionalProperties' => { 'type' => 'string' } } assert_valid schema, {'1 taco' => 1} assert_valid schema, {'1 taco' => 1, 'foo' => 'bar'} refute_valid schema, {'1 taco' => 1, 'foo' => 2} end end end json-schema-2.6.0/test/support/strict_validation.rb000066400000000000000000000054631264371451000225030ustar00rootroot00000000000000module StrictValidation def test_strict_properties schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "properties" => { "a" => {"type" => "string"}, "b" => {"type" => "string"} } } data = {"a" => "a"} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"b" => "b"} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b"} assert(JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b", "c" => "c"} assert(!JSON::Validator.validate(schema,data,:strict => true)) end def test_strict_error_message schema = { :type => 'object', :properties => { :a => { :type => 'string' } } } data = { :a => 'abc', :b => 'abc' } errors = JSON::Validator.fully_validate(schema,data,:strict => true) assert_match("The property '#/' contained undefined properties: 'b' in schema", errors[0]) end def test_strict_properties_additional_props schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "properties" => { "a" => {"type" => "string"}, "b" => {"type" => "string"} }, "additionalProperties" => {"type" => "integer"} } data = {"a" => "a"} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"b" => "b"} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b"} assert(JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b", "c" => "c"} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b", "c" => 3} assert(JSON::Validator.validate(schema,data,:strict => true)) end def test_strict_properties_pattern_props schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "properties" => { "a" => {"type" => "string"}, "b" => {"type" => "string"} }, "patternProperties" => {"\\d+ taco" => {"type" => "integer"}} } data = {"a" => "a"} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"b" => "b"} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b"} assert(JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b", "c" => "c"} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b", "c" => 3} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b", "23 taco" => 3} assert(JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b", "23 taco" => "cheese"} assert(!JSON::Validator.validate(schema,data,:strict => true)) end end json-schema-2.6.0/test/support/string_validation.rb000066400000000000000000000100251264371451000224670ustar00rootroot00000000000000module StringValidation module ValueTests def test_minlength schema = { 'properties' => { 'a' => { 'minLength' => 1 } } } assert_valid schema, {'a' => 't'} refute_valid schema, {'a' => ''} # other types are disregarded assert_valid schema, {'a' => 5} end def test_maxlength schema = { 'properties' => { 'a' => { 'maxLength' => 2 } } } assert_valid schema, {'a' => 'tt'} assert_valid schema, {'a' => ''} refute_valid schema, {'a' => 'ttt'} # other types are disregarded assert_valid schema, {'a' => 5} end def test_pattern schema = { 'properties' => { 'a' => { 'pattern' => "\\d+ taco" } } } assert_valid schema, {'a' => '156 taco bell'} refute_valid schema, {'a' => 'x taco'} # other types are disregarded assert_valid schema, {'a' => 5} end end module FormatTests # Draft1..3 use the format name `ip-address`; draft4 changed it to `ipv4`. def ipv4_format 'ip-address' end def test_format_unknown schema = { 'properties' => { 'a' => { 'format' => 'unknown' } } } assert_valid schema, {'a' => 'absolutely anything!'} assert_valid schema, {'a' => ''} end def test_format_union schema = { 'properties' => { 'a' => { 'type' => ['string', 'null'], 'format' => 'date-time' } } } assert_valid schema, {'a' => nil} refute_valid schema, {'a' => 'wrong'} end def test_format_ipv4 schema = { 'properties' => { 'a' => { 'format' => ipv4_format } } } assert_valid schema, {"a" => "1.1.1.1"} refute_valid schema, {"a" => "1.1.1"} refute_valid schema, {"a" => "1.1.1.300"} refute_valid schema, {"a" => "1.1.1"} refute_valid schema, {"a" => "1.1.1.1b"} # other types are disregarded assert_valid schema, {'a' => 5} end def test_format_ipv6 schema = { 'properties' => { 'a' => { 'format' => 'ipv6' } } } assert_valid schema, {"a" => "1111:2222:8888:9999:aaaa:cccc:eeee:ffff"} assert_valid schema, {"a" => "1111:0:8888:0:0:0:eeee:ffff"} assert_valid schema, {"a" => "1111:2222:8888::eeee:ffff"} assert_valid schema, {"a" => "::1"} refute_valid schema, {"a" => "1111:2222:8888:99999:aaaa:cccc:eeee:ffff"} refute_valid schema, {"a" => "1111:2222:8888:9999:aaaa:cccc:eeee:gggg"} refute_valid schema, {"a" => "1111:2222::9999::cccc:eeee:ffff"} refute_valid schema, {"a" => "1111:2222:8888:9999:aaaa:cccc:eeee:ffff:bbbb"} refute_valid schema, {"a" => "42"} refute_valid schema, {"a" => "b"} end end # Draft1..3 explicitly support `date`, `time` formats in addition to # the `date-time` format. module DateAndTimeFormatTests def test_format_time schema = { 'properties' => { 'a' => { 'format' => 'time' } } } assert_valid schema, {"a" => "12:00:00"} refute_valid schema, {"a" => "12:00"} refute_valid schema, {"a" => "12:00:60"} refute_valid schema, {"a" => "12:60:00"} refute_valid schema, {"a" => "24:00:00"} refute_valid schema, {"a" => "0:00:00"} refute_valid schema, {"a" => "-12:00:00"} refute_valid schema, {"a" => "12:00:00b"} assert_valid schema, {"a" => "12:00:00"} refute_valid schema, {"a" => "12:00:00\nabc"} end def test_format_date schema = { 'properties' => { 'a' => { 'format' => 'date' } } } assert_valid schema, {"a" => "2010-01-01"} refute_valid schema, {"a" => "2010-01-32"} refute_valid schema, {"a" => "n2010-01-01"} refute_valid schema, {"a" => "2010-1-01"} refute_valid schema, {"a" => "2010-01-1"} refute_valid schema, {"a" => "2010-01-01n"} refute_valid schema, {"a" => "2010-01-01\nabc"} end end end json-schema-2.6.0/test/support/type_validation.rb000066400000000000000000000040261264371451000221460ustar00rootroot00000000000000module TypeValidation # The draft4 schema refers to the JSON types as 'simple types'; # see draft4#/definitions/simpleTypes module SimpleTypeTests TYPES = { 'integer' => 5, 'number' => 5.0, 'string' => 'str', 'boolean' => true, 'object' => {}, 'array' => [], 'null' => nil } TYPES.each do |name, value| other_values = TYPES.values.reject { |v| v == value } define_method(:"test_#{name}_type_property") do schema = { 'properties' => { 'a' => { 'type' => name } } } assert_valid schema, {'a' => value} other_values.each do |other_value| refute_valid schema, {'a' => other_value} end end define_method(:"test_#{name}_type_value") do schema = { 'type' => name } assert_valid schema, value other_values.each do |other_value| schema = { 'type' => name } refute_valid schema, other_value end end end def test_type_union schema = { 'type' => ['integer', 'string'] } assert_valid schema, 5 assert_valid schema, 'str' refute_valid schema, nil refute_valid schema, [5, 'str'] end end # The draft1..3 schemas support an additional type, `any`. module AnyTypeTests def test_any_type schema = { 'type' => 'any' } SimpleTypeTests::TYPES.values.each do |value| assert_valid schema, value end end end # The draft1..3 schemas support schemas as values for `type`. module SchemaUnionTypeTests def test_union_type_with_schemas schema = { 'properties' => { 'a' => { 'type' => [ {'type' => 'string'}, {'type' => 'object', 'properties' => { 'b' => { 'type' => 'integer' }}} ] } } } assert_valid schema, {'a' => 'test'} refute_valid schema, {'a' => 5} assert_valid schema, {'a' => {'b' => 5}} refute_valid schema, {'a' => {'b' => 'taco'}} end end end json-schema-2.6.0/test/test-suite/000077500000000000000000000000001264371451000170165ustar00rootroot00000000000000json-schema-2.6.0/test/test_all_of_ref_schema.rb000066400000000000000000000022331264371451000217040ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) class AllOfRefSchemaTest < Minitest::Test def schema schema_fixture_path('all_of_ref_schema.json') end def data data_fixture_path('all_of_ref_data.json') end def test_all_of_ref_schema_fails refute_valid schema, data end def test_all_of_ref_schema_succeeds assert_valid schema, %({"name": 42}) end def test_all_of_ref_subschema_errors errors = JSON::Validator.fully_validate(schema, data, :errors_as_objects => true) nested_errors = errors[0][:errors] assert_equal([:allof_0], nested_errors.keys, 'should have nested errors for each allOf subschema') assert_match(/the property '#\/name' of type String did not match the following type: integer/i, nested_errors[:allof_0][0][:message]) end def test_all_of_ref_message errors = JSON::Validator.fully_validate(schema, data) expected_message = """The property '#/' of type Hash did not match all of the required schemas. The schema specific errors were: - allOf #0: - The property '#/name' of type String did not match the following type: integer""" assert_equal(expected_message, errors[0]) end end json-schema-2.6.0/test/test_any_of_ref_schema.rb000066400000000000000000000030641264371451000217260ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) class AnyOfRefSchemaTest < Minitest::Test def schema schema_fixture_path('any_of_ref_schema.json') end def test_any_of_ref_schema assert_valid schema, data_fixture_path('any_of_ref_data.json') end def test_any_of_ref_subschema_errors data = %({"names": ["jack"]}) errors = JSON::Validator.fully_validate(schema, data, :errors_as_objects => true) nested_errors = errors[0][:errors] assert_equal([:anyof_0, :anyof_1, :anyof_2], nested_errors.keys, 'should have nested errors for each anyOf subschema') assert_match(/the property '#\/names\/0' value "jack" did not match the regex 'john'/i, nested_errors[:anyof_0][0][:message]) assert_match(/the property '#\/names\/0' value "jack" did not match the regex 'jane'/i, nested_errors[:anyof_1][0][:message]) assert_match(/the property '#\/names\/0' value "jack" did not match the regex 'jimmy'/i, nested_errors[:anyof_2][0][:message]) end def test_any_of_ref_message data = %({"names": ["jack"]}) errors = JSON::Validator.fully_validate(schema, data) expected_message = """The property '#/names/0' of type String did not match one or more of the required schemas. The schema specific errors were: - anyOf #0: - The property '#/names/0' value \"jack\" did not match the regex 'john' - anyOf #1: - The property '#/names/0' value \"jack\" did not match the regex 'jane' - anyOf #2: - The property '#/names/0' value \"jack\" did not match the regex 'jimmy'""" assert_equal(expected_message, errors[0]) end end json-schema-2.6.0/test/test_bad_schema_ref.rb000066400000000000000000000015541264371451000212030ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) require 'socket' class BadSchemaRefTest < Minitest::Test def setup WebMock.allow_net_connect! end def teardown WebMock.disable_net_connect! end def test_bad_uri_ref schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "type" => "array", "items" => { "$ref" => "../google.json"} } data = [1,2,3] assert_raises(Errno::ENOENT) do JSON::Validator.validate(schema,data) end end def test_bad_host_ref schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "type" => "array", "items" => { "$ref" => "http://ppcheesecheseunicornnuuuurrrrr.example.invalid/json.schema"} } data = [1,2,3] assert_raises(SocketError, OpenURI::HTTPError) do JSON::Validator.validate(schema,data) end end end json-schema-2.6.0/test/test_common_test_suite.rb000066400000000000000000000043521264371451000220400ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) require 'json' class CommonTestSuiteTest < Minitest::Test TEST_DIR = File.expand_path('../test-suite/tests', __FILE__) # These are test files which we know fail spectacularly, either because we # don't support that functionality or because they require external # dependencies. To allow finer-grained control over which tests to run, # you can replace `:all` with an array containing the names of individual # tests to skip. IGNORED_TESTS = Hash.new { |h,k| h[k] = [] }.merge({ "draft3/optional/jsregex.json" => :all, "draft3/optional/format.json" => [ "validation of regular expressions", "validation of e-mail addresses", "validation of URIs", "validation of host names", "validation of CSS colors" ], "draft4/optional/format.json" => [ "validation of URIs", "validation of e-mail addresses", "validation of host names" ] }) def setup Dir["#{TEST_DIR}/../remotes/**/*.json"].each do |path| schema = path.sub(%r{^.*/remotes/}, '') stub_request(:get, "http://localhost:1234/#{schema}"). to_return(:body => File.read(path), :status => 200) end end Dir["#{TEST_DIR}/*"].each do |suite| version = File.basename(suite).to_sym Dir["#{suite}/**/*.json"].each do |tfile| test_list = JSON.parse(File.read(tfile)) rel_file = tfile[TEST_DIR.length+1..-1] test_list.each do |test| schema = test["schema"] base_description = test["description"] test["tests"].each do |t| next if IGNORED_TESTS[rel_file] == :all next if IGNORED_TESTS[rel_file].any? { |ignored| base_description == ignored || "#{base_description}/#{t['description']}" == ignored } err_id = "#{rel_file}: #{base_description}/#{t['description']}" define_method("test_#{err_id}") do errors = JSON::Validator.fully_validate(schema, t["data"], :parse_data => false, :validate_schema => true, :version => version ) assert_equal t["valid"], errors.empty?, "Common test suite case failed: #{err_id}" end end end end end end json-schema-2.6.0/test/test_custom_format.rb000066400000000000000000000124011264371451000211540ustar00rootroot00000000000000# encoding: utf-8 require File.expand_path('../test_helper', __FILE__) class JSONSchemaCustomFormatTest < Minitest::Test def setup @all_versions = ['draft1', 'draft2', 'draft3', 'draft4', nil] @format_proc = lambda { |value| raise JSON::Schema::CustomFormatError.new("must be 42") unless value == "42" } @schema_4 = { "$schema" => "http://json-schema.org/draft-04/schema#", "properties" => { "a" => { "type" => "string", "format" => "custom", }, } } @schema_3 = @schema_4.clone @schema_3["$schema"] = "http://json-schema.org/draft-03/schema#" @schema_2 = @schema_4.clone @schema_2["$schema"] = "http://json-schema.org/draft-02/schema#" @schema_1 = @schema_4.clone @schema_1["$schema"] = "http://json-schema.org/draft-01/schema#" @default = @schema_4.clone @default.delete("$schema") @schemas = { "draft1" => @schema_1, "draft2" => @schema_2, "draft3" => @schema_3, "draft4" => @schema_4, nil => @default, } JSON::Validator.restore_default_formats end def test_single_registration @all_versions.each do |version| assert(JSON::Validator.validator_for_name(version).formats['custom'].nil?, "Format 'custom' for #{version || 'default'} should be nil") JSON::Validator.register_format_validator("custom", @format_proc, [version]) assert(JSON::Validator.validator_for_name(version).formats['custom'].is_a?(JSON::Schema::CustomFormat), "Format 'custom' should be registered for #{version || 'default'}") (@all_versions - [version]).each do |other_version| assert(JSON::Validator.validator_for_name(other_version).formats['custom'].nil?, "Format 'custom' should still be nil for #{other_version || 'default'}") end JSON::Validator.deregister_format_validator("custom", [version]) assert(JSON::Validator.validator_for_name(version).formats['custom'].nil?, "Format 'custom' should be deregistered for #{version || 'default'}") end end def test_register_for_all_by_default JSON::Validator.register_format_validator("custom", @format_proc) @all_versions.each do |version| assert(JSON::Validator.validator_for_name(version).formats['custom'].is_a?(JSON::Schema::CustomFormat), "Format 'custom' should be registered for #{version || 'default'}") end JSON::Validator.restore_default_formats @all_versions.each do |version| assert(JSON::Validator.validator_for_name(version).formats['custom'].nil?, "Format 'custom' should still be nil for #{version || 'default'}") end end def test_multi_registration unregistered_version = @all_versions.delete("draft1") JSON::Validator.register_format_validator("custom", @format_proc, @all_versions) @all_versions.each do |version| assert(JSON::Validator.validator_for_name(version).formats['custom'].is_a?(JSON::Schema::CustomFormat), "Format 'custom' should be registered for #{version || 'default'}") end assert(JSON::Validator.validator_for_name(unregistered_version).formats['custom'].nil?, "Format 'custom' should still be nil for #{unregistered_version}") end def test_format_validation @all_versions.each do |version| data = { "a" => "23" } schema = @schemas[version] prefix = "Validation for '#{version || 'default'}'" assert(JSON::Validator.validate(schema, data), "#{prefix} succeeds with no 'custom' format validator registered") JSON::Validator.register_format_validator("custom", @format_proc, [version]) data["a"] = "42" assert(JSON::Validator.validate(schema, data), "#{prefix} succeeds with 'custom' format validator and correct data") data["a"] = "23" assert(!JSON::Validator.validate(schema, data), "#{prefix} fails with 'custom' format validator and wrong data") errors = JSON::Validator.fully_validate(schema, data) assert(errors.count == 1 && errors.first.match(/The property '#\/a' must be 42 in schema/), "#{prefix} records fromat error") data["a"] = 23 errors = JSON::Validator.fully_validate(schema, data) assert(errors.count == 1 && errors.first.match(/The property '#\/a' of type (?:integer|Fixnum) did not match the following type: string/), "#{prefix} records no fromat error on type mismatch") end end def test_override_default_format @all_versions.each do |version| data = { "a" => "2001:db8:85a3:0:0:8a2e:370:7334" } schema = @schemas[version] schema["properties"]["a"]["format"] = "ipv6" prefix = "Validation for '#{version || 'default'}'" assert(JSON::Validator.validate(schema, data), "#{prefix} succeeds for default format with correct data") data["a"] = "no_ip6_address" assert(!JSON::Validator.validate(schema, data), "#{prefix} fails for default format and wrong data") data["a"] = "42" JSON::Validator.register_format_validator("ipv6", @format_proc, [version]) assert(JSON::Validator.validate(schema, data), "#{prefix} succeeds with overriden default format and correct data") JSON::Validator.deregister_format_validator("ipv6", [version]) data["a"] = "2001:db8:85a3:0:0:8a2e:370:7334" assert(JSON::Validator.validate(schema, data), "#{prefix} restores the default format on deregistration") end end end json-schema-2.6.0/test/test_definition.rb000066400000000000000000000006161264371451000204270ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) class RelativeDefinitionTest < Minitest::Test def test_definition_schema assert_valid schema_fixture_path('definition_schema.json'), {"a" => 5} end def test_relative_definition schema = schema_fixture_path('relative_definition_schema.json') assert_valid schema, {"a" => 5} refute_valid schema, {"a" => "foo"} end end json-schema-2.6.0/test/test_extended_schema.rb000066400000000000000000000034531264371451000214210ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) class BitwiseAndAttribute < JSON::Schema::Attribute def self.validate(current_schema, data, fragments, processor, validator, options = {}) return unless data.is_a?(Integer) if data & current_schema.schema['bitwise-and'].to_i == 0 message = "The property '#{build_fragment(fragments)}' did not evaluate to true when bitwise-AND'd with #{current_schema.schema['bitwise-and']}" validation_error(processor, message, fragments, current_schema, self, options[:record_errors]) end end end class ExtendedSchema < JSON::Schema::Validator def initialize super extend_schema_definition("http://json-schema.org/draft-03/schema#") @attributes["bitwise-and"] = BitwiseAndAttribute @uri = Addressable::URI.parse("http://test.com/test.json") end JSON::Validator.register_validator(self.new) end class TestExtendedSchema < Minitest::Test def test_extended_schema_validation schema = { "$schema" => "http://test.com/test.json", "properties" => { "a" => { "bitwise-and" => 1 }, "b" => { "type" => "string" } } } assert_valid schema, {"a" => 1, "b" => "taco"} refute_valid schema, {"a" => 0, "b" => "taco"} refute_valid schema, {"a" => 1, "b" => 5} end def test_unextended_schema # Verify that using the original schema disregards the `bitwise-and` property schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "properties" => { "a" => { "bitwise-and" => 1 }, "b" => { "type" => "string" } } } assert_valid schema, {"a" => 0, "b" => "taco"} assert_valid schema, {"a" => 1, "b" => "taco"} refute_valid schema, {"a" => 1, "b" => 5} end end json-schema-2.6.0/test/test_extends_and_additionalProperties.rb000066400000000000000000000033701264371451000250400ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) class ExtendsNestedTest < Minitest::Test def assert_validity(valid, schema_name, data, msg) msg = "Schema should be #{valid ? :valid : :invalid}.\n(#{schema_name}) #{msg}" schema = schema_fixture_path("#{schema_name}.schema.json") errors = JSON::Validator.fully_validate(schema, data) if valid assert_equal([], errors, msg) else refute_equal([], errors, msg) end end %w[ extends_and_additionalProperties-1-filename extends_and_additionalProperties-1-ref extends_and_additionalProperties-2-filename extends_and_additionalProperties-2-ref ].each do |schema_name| test_prefix = 'test_' + schema_name.gsub('-','_') class_eval <<-EOB def #{test_prefix}_valid_outer assert_validity true, '#{schema_name}', {"outerC"=>true}, "Outer defn is broken, maybe the outer extends overrode it" end def #{test_prefix}_valid_outer_extended assert_validity true, '#{schema_name}', {"innerA"=>true}, "Extends at the root level isn't working" end def #{test_prefix}_valid_inner assert_validity true, '#{schema_name}', {"outerB"=>[{"innerA"=>true}]}, "Extends isn't working in the array element defn" end def #{test_prefix}_invalid_inner assert_validity false, '#{schema_name}', {"outerB"=>[{"whaaaaat"=>true}]}, "Array element defn allowing anything when it should only allow what's in inner.schema" end EOB if schema_name['extends_and_additionalProperties-1'] class_eval <<-EOB def #{test_prefix}_invalid_outer assert_validity false, '#{schema_name}', {"whaaaaat"=>true}, "Outer defn allowing anything when it shouldn't" end EOB end end end json-schema-2.6.0/test/test_files_v3.rb000066400000000000000000000032511264371451000200070ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) class JSONSchemaTest < Minitest::Test # # These tests are ONLY run if there is an appropriate JSON backend parser available # def test_schema_from_file assert_valid schema_fixture_path('good_schema_1.json'), { "a" => 5 } refute_valid schema_fixture_path('good_schema_1.json'), { "a" => "bad" } end def test_data_from_file schema = {"$schema" => "http://json-schema.org/draft-03/schema#","type" => "object", "properties" => {"a" => {"type" => "integer"}}} assert_valid schema, data_fixture_path('good_data_1.json'), :uri => true refute_valid schema, data_fixture_path('bad_data_1.json'), :uri => true end def test_data_from_json if JSON::Validator.json_backend != nil schema = {"$schema" => "http://json-schema.org/draft-03/schema#","type" => "object", "properties" => {"a" => {"type" => "integer"}}} assert_valid schema, %Q({"a": 5}), :json => true refute_valid schema, %Q({"a": "poop"}), :json => true end end def test_both_from_file assert_valid schema_fixture_path('good_schema_1.json'), data_fixture_path('good_data_1.json'), :uri => true refute_valid schema_fixture_path('good_schema_1.json'), data_fixture_path('bad_data_1.json'), :uri => true end def test_file_ref assert_valid schema_fixture_path('good_schema_2.json'), { "b" => { "a" => 5 } } refute_valid schema_fixture_path('good_schema_1.json'), { "b" => { "a" => "boo" } } end def test_file_extends assert_valid schema_fixture_path('good_schema_extends1.json'), { "a" => 5 } assert_valid schema_fixture_path('good_schema_extends2.json'), { "a" => 5, "b" => { "a" => 5 } } end end json-schema-2.6.0/test/test_fragment_resolution.rb000066400000000000000000000014311264371451000223610ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) class FragmentResolution < Minitest::Test def test_fragment_resolution schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "required" => ["a"], "properties" => { "a" => { "type" => "object", "properties" => { "b" => {"type" => "integer" } } } } } data = {"b" => 5} refute_valid schema, data assert_valid schema, data, :fragment => "#/properties/a" assert_raises JSON::Schema::SchemaError do JSON::Validator.validate!(schema,data,:fragment => "/properties/a") end assert_raises JSON::Schema::SchemaError do JSON::Validator.validate!(schema,data,:fragment => "#/properties/b") end end end json-schema-2.6.0/test/test_fragment_validation_with_ref.rb000066400000000000000000000014631264371451000242040ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) class FragmentValidationWithRef < Minitest::Test 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"}] assert_valid whole_schema, data, :fragment => "#/definitions/posts" end end json-schema-2.6.0/test/test_full_validation.rb000066400000000000000000000130731264371451000214540ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) class JSONFullValidation < Minitest::Test def test_full_validation data = {"b" => {"a" => 5}} schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "type" => "object", "properties" => { "b" => { "required" => true } } } errors = JSON::Validator.fully_validate(schema,data) assert(errors.empty?) data = {"c" => 5} schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "type" => "object", "properties" => { "b" => { "required" => true }, "c" => { "type" => "string" } } } errors = JSON::Validator.fully_validate(schema,data) assert(errors.length == 2) end def test_full_validation_with_union_types data = {"b" => 5} schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "type" => "object", "properties" => { "b" => { "type" => ["null","integer"] } } } errors = JSON::Validator.fully_validate(schema,data) assert(errors.empty?) schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "type" => "object", "properties" => { "b" => { "type" => ["integer","null"] } } } errors = JSON::Validator.fully_validate(schema,data) assert(errors.empty?) data = {"b" => "a string"} errors = JSON::Validator.fully_validate(schema,data) assert(errors.length == 1) schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "type" => "object", "properties" => { "b" => { "type" => [ { "type" => "object", "properties" => { "c" => {"type" => "string"} } }, { "type" => "object", "properties" => { "d" => {"type" => "integer"} } } ] } } } data = {"b" => {"c" => "taco"}} errors = JSON::Validator.fully_validate(schema,data) assert(errors.empty?) data = {"b" => {"d" => 6}} errors = JSON::Validator.fully_validate(schema,data) assert(errors.empty?) data = {"b" => {"c" => 6, "d" => "OH GOD"}} errors = JSON::Validator.fully_validate(schema,data) assert(errors.length == 1) end def test_full_validation_with_object_errors data = {"b" => {"a" => 5}} schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "type" => "object", "properties" => { "b" => { "required" => true } } } errors = JSON::Validator.fully_validate(schema,data,:errors_as_objects => true) assert(errors.empty?) data = {"c" => 5} schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "type" => "object", "properties" => { "b" => { "required" => true }, "c" => { "type" => "string" } } } errors = JSON::Validator.fully_validate(schema,data,:errors_as_objects => true) assert(errors.length == 2) assert(errors[0][:failed_attribute] == "Properties") assert(errors[0][:fragment] == "#/") assert(errors[1][:failed_attribute] == "Type") assert(errors[1][:fragment] == "#/c") end def test_full_validation_with_nested_required_properties schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "type" => "object", "properties" => { "x" => { "required" => true, "type" => "object", "properties" => { "a" => {"type"=>"integer","required"=>true}, "b" => {"type"=>"integer","required"=>true}, "c" => {"type"=>"integer","required"=>false}, "d" => {"type"=>"integer","required"=>false}, "e" => {"type"=>"integer","required"=>false}, } } } } data = {"x" => {"a"=>5, "d"=>5, "e"=>"what?"}} errors = JSON::Validator.fully_validate(schema,data,:errors_as_objects => true) assert_equal 2, errors.length assert_equal '#/x', errors[0][:fragment] assert_equal 'Properties', errors[0][:failed_attribute] assert_equal '#/x/e', errors[1][:fragment] assert_equal 'Type', errors[1][:failed_attribute] end def test_full_validation_with_nested_required_propertiesin_array schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "type" => "object", "properties" => { "x" => { "required" => true, "type" => "array", "items" => { "type" => "object", "properties" => { "a" => {"type"=>"integer","required"=>true}, "b" => {"type"=>"integer","required"=>true}, "c" => {"type"=>"integer","required"=>false}, "d" => {"type"=>"integer","required"=>false}, "e" => {"type"=>"integer","required"=>false}, } } } } } missing_b= {"a"=>5} e_is_wrong_type= {"a"=>5,"b"=>5,"e"=>"what?"} data = {"x" => [missing_b, e_is_wrong_type]} errors = JSON::Validator.fully_validate(schema,data,:errors_as_objects => true) assert_equal 2, errors.length assert_equal '#/x/0', errors[0][:fragment] assert_equal 'Properties', errors[0][:failed_attribute] assert_equal '#/x/1/e', errors[1][:fragment] assert_equal 'Type', errors[1][:failed_attribute] end end json-schema-2.6.0/test/test_helper.rb000066400000000000000000000022131264371451000175510ustar00rootroot00000000000000require 'minitest/autorun' require 'webmock/minitest' $:.unshift(File.expand_path('../../lib', __FILE__)) require 'json-schema' Dir[File.join(File.expand_path('../support', __FILE__), '*.rb')].each do |support_file| require support_file end class Minitest::Test def schema_fixture_path(filename) File.join(File.dirname(__FILE__), 'schemas', filename) end def data_fixture_path(filename) File.join(File.dirname(__FILE__), 'data', filename) end def assert_valid(schema, data, options = {}) if !options.key?(:version) && respond_to?(:schema_version) options = options.merge(:version => schema_version) end errors = JSON::Validator.fully_validate(schema, data, options) assert_equal([], errors, "#{data.inspect} should be valid for schema:\n#{schema.inspect}") end def refute_valid(schema, data, options = {}) if !options.key?(:version) && respond_to?(:schema_version) options = options.merge(:version => schema_version) end errors = JSON::Validator.fully_validate(schema, data, options) refute_equal([], errors, "#{data.inspect} should be invalid for schema:\n#{schema.inspect}") end end json-schema-2.6.0/test/test_initialize_data.rb000066400000000000000000000073601264371451000214340ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) class InitializeDataTest < Minitest::Test def test_parse_character_string schema = {'type' => 'string'} data = 'hello world' assert(JSON::Validator.validate(schema, data)) assert(JSON::Validator.validate(schema, data, :parse_data => false)) assert_raises(JSON::Schema::JsonParseError) do JSON::Validator.validate(schema, data, :json => true) end assert_raises(JSON::Schema::JsonLoadError) { JSON::Validator.validate(schema, data, :uri => true) } end def test_parse_integer_string schema = {'type' => 'integer'} data = '42' assert(JSON::Validator.validate(schema, data)) refute(JSON::Validator.validate(schema, data, :parse_data => false)) assert(JSON::Validator.validate(schema, data, :json => true)) assert_raises(JSON::Schema::JsonLoadError) { JSON::Validator.validate(schema, data, :uri => true) } end def test_parse_hash_string schema = { 'type' => 'object', 'properties' => { 'a' => { 'type' => 'string' } } } data = '{"a": "b"}' assert(JSON::Validator.validate(schema, data)) refute(JSON::Validator.validate(schema, data, :parse_data => false)) assert(JSON::Validator.validate(schema, data, :json => true)) assert_raises(JSON::Schema::JsonLoadError) { JSON::Validator.validate(schema, data, :uri => true) } end def test_parse_json_string schema = {'type' => 'string'} data = '"hello world"' assert(JSON::Validator.validate(schema, data)) assert(JSON::Validator.validate(schema, data, :parse_data => false)) assert(JSON::Validator.validate(schema, data, :json => true)) assert_raises(JSON::Schema::JsonLoadError) { JSON::Validator.validate(schema, data, :uri => true) } end def test_parse_valid_uri_string schema = {'type' => 'string'} data = 'http://foo.bar/' stub_request(:get, "foo.bar").to_return(:body => '"hello world"', :status => 200) assert(JSON::Validator.validate(schema, data)) assert(JSON::Validator.validate(schema, data, :parse_data => false)) assert_raises(JSON::Schema::JsonParseError) do JSON::Validator.validate(schema, data, :json => true) end assert(JSON::Validator.validate(schema, data, :uri => true)) end def test_parse_invalid_uri_string schema = {'type' => 'string'} data = 'http://foo.bar/' stub_request(:get, "foo.bar").to_timeout assert(JSON::Validator.validate(schema, data)) assert(JSON::Validator.validate(schema, data, :parse_data => false)) stub_request(:get, "foo.bar").to_return(:status => [500, "Internal Server Error"]) assert(JSON::Validator.validate(schema, data)) assert(JSON::Validator.validate(schema, data, :parse_data => false)) assert_raises(JSON::Schema::JsonParseError) do JSON::Validator.validate(schema, data, :json => true) end assert_raises(JSON::Schema::JsonLoadError) { JSON::Validator.validate(schema, data, :uri => true) } end def test_parse_integer schema = {'type' => 'integer'} data = 42 assert(JSON::Validator.validate(schema, data)) assert(JSON::Validator.validate(schema, data, :parse_data => false)) assert_raises(TypeError) { JSON::Validator.validate(schema, data, :json => true) } assert_raises(TypeError) { JSON::Validator.validate(schema, data, :uri => true) } end def test_parse_hash schema = { 'type' => 'object', 'properties' => { 'a' => { 'type' => 'string' } } } data = { 'a' => 'b' } assert(JSON::Validator.validate(schema, data)) assert(JSON::Validator.validate(schema, data, :parse_data => false)) assert_raises(TypeError) { JSON::Validator.validate(schema, data, :json => true) } assert_raises(TypeError) { JSON::Validator.validate(schema, data, :uri => true) } end end json-schema-2.6.0/test/test_jsonschema_draft1.rb000066400000000000000000000054671264371451000217030ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) class JSONSchemaDraft1Test < Minitest::Test def schema_version :draft1 end def exclusive_minimum { 'minimumCanEqual' => false } end def exclusive_maximum { 'maximumCanEqual' => false } end include ArrayValidation::ItemsTests include EnumValidation::General include EnumValidation::V1_V2 include NumberValidation::MinMaxTests include ObjectValidation::AdditionalPropertiesTests include StrictValidation include StringValidation::ValueTests include StringValidation::FormatTests include StringValidation::DateAndTimeFormatTests include TypeValidation::SimpleTypeTests include TypeValidation::AnyTypeTests include TypeValidation::SchemaUnionTypeTests def test_optional # Set up the default datatype schema = { "properties" => { "a" => {"type" => "string"} } } data = {} refute_valid schema, data data['a'] = "Hello" assert_valid schema, data schema = { "properties" => { "a" => {"type" => "integer", "optional" => "true"} } } data = {} assert_valid schema, data end def test_max_decimal # Set up the default datatype schema = { "properties" => { "a" => {"maxDecimal" => 2} } } data = { "a" => nil } data["a"] = 3.35 assert_valid schema, data data["a"] = 3.455 refute_valid schema, data schema["properties"]["a"]["maxDecimal"] = 0 data["a"] = 4.0 refute_valid schema, data data["a"] = 'boo' assert_valid schema, data data["a"] = 5 assert_valid schema, data end def test_disallow # Set up the default datatype schema = { "properties" => { "a" => {"disallow" => "integer"} } } data = { "a" => nil } data["a"] = 'string' assert_valid schema, data data["a"] = 5 refute_valid schema, data schema["properties"]["a"]["disallow"] = ["integer","string"] data["a"] = 'string' refute_valid schema, data data["a"] = 5 refute_valid schema, data data["a"] = false assert_valid schema, data end def test_format_datetime schema = { "type" => "object", "properties" => { "a" => {"type" => "string", "format" => "date-time"}} } assert_valid schema, {"a" => "2010-01-01T12:00:00Z"} refute_valid schema, {"a" => "2010-01-32T12:00:00Z"} refute_valid schema, {"a" => "2010-13-01T12:00:00Z"} refute_valid schema, {"a" => "2010-01-01T24:00:00Z"} refute_valid schema, {"a" => "2010-01-01T12:60:00Z"} refute_valid schema, {"a" => "2010-01-01T12:00:60Z"} refute_valid schema, {"a" => "2010-01-01T12:00:00z"} refute_valid schema, {"a" => "2010-01-0112:00:00Z"} refute_valid schema, {"a" => "2010-01-01T12:00:00Z\nabc"} end end json-schema-2.6.0/test/test_jsonschema_draft2.rb000066400000000000000000000047061264371451000216770ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) class JSONSchemaDraft2Test < Minitest::Test def schema_version :draft2 end def exclusive_minimum { 'minimumCanEqual' => false } end def exclusive_maximum { 'maximumCanEqual' => false } end def multiple_of 'divisibleBy' end include ArrayValidation::ItemsTests include ArrayValidation::UniqueItemsTests include EnumValidation::General include EnumValidation::V1_V2 include NumberValidation::MinMaxTests include NumberValidation::MultipleOfTests include ObjectValidation::AdditionalPropertiesTests include StrictValidation include StringValidation::ValueTests include StringValidation::FormatTests include StringValidation::DateAndTimeFormatTests include TypeValidation::SimpleTypeTests include TypeValidation::AnyTypeTests include TypeValidation::SchemaUnionTypeTests def test_optional # Set up the default datatype schema = { "properties" => { "a" => {"type" => "string"} } } data = {} refute_valid schema, data data['a'] = "Hello" assert_valid schema, data schema = { "properties" => { "a" => {"type" => "integer", "optional" => "true"} } } data = {} assert_valid schema, data end def test_disallow # Set up the default datatype schema = { "properties" => { "a" => {"disallow" => "integer"} } } data = { "a" => nil } data["a"] = 'string' assert_valid schema, data data["a"] = 5 refute_valid schema, data schema["properties"]["a"]["disallow"] = ["integer","string"] data["a"] = 'string' refute_valid schema, data data["a"] = 5 refute_valid schema, data data["a"] = false assert_valid schema, data end def test_format_datetime schema = { "type" => "object", "properties" => { "a" => {"type" => "string", "format" => "date-time"}} } assert_valid schema, {"a" => "2010-01-01T12:00:00Z"} refute_valid schema, {"a" => "2010-01-32T12:00:00Z"} refute_valid schema, {"a" => "2010-13-01T12:00:00Z"} refute_valid schema, {"a" => "2010-01-01T24:00:00Z"} refute_valid schema, {"a" => "2010-01-01T12:60:00Z"} refute_valid schema, {"a" => "2010-01-01T12:00:60Z"} refute_valid schema, {"a" => "2010-01-01T12:00:00z"} refute_valid schema, {"a" => "2010-01-0112:00:00Z"} refute_valid schema, {"a" => "2010-01-01T12:00:00Z\nabc"} end end json-schema-2.6.0/test/test_jsonschema_draft3.rb000066400000000000000000000301111264371451000216650ustar00rootroot00000000000000# encoding: utf-8 require File.expand_path('../test_helper', __FILE__) class JSONSchemaDraft3Test < Minitest::Test def schema_version :draft3 end def exclusive_minimum { 'exclusiveMinimum' => true } end def exclusive_maximum { 'exclusiveMaximum' => true } end def multiple_of 'divisibleBy' end include ArrayValidation::ItemsTests include ArrayValidation::AdditionalItemsTests include ArrayValidation::UniqueItemsTests include EnumValidation::General include EnumValidation::V3_V4 include NumberValidation::MinMaxTests include NumberValidation::MultipleOfTests include ObjectValidation::AdditionalPropertiesTests include ObjectValidation::PatternPropertiesTests include StrictValidation include StringValidation::ValueTests include StringValidation::FormatTests include StringValidation::DateAndTimeFormatTests include TypeValidation::SimpleTypeTests include TypeValidation::AnyTypeTests include TypeValidation::SchemaUnionTypeTests def test_types # Set up the default datatype schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "properties" => { "a" => {} } } data = { "a" => nil } # Test an array of unioned-type objects that prevent additionalProperties schema["properties"]["a"] = { 'type' => 'array', 'items' => { 'type' => [ { 'type' => 'object', 'properties' => { "b" => { "type" => "integer" } } }, { 'type' => 'object', 'properties' => { "c" => { "type" => "string" } } } ], 'additionalProperties' => false } } data["a"] = [{"b" => 5}, {"c" => "foo"}] errors = JSON::Validator.fully_validate(schema, data) assert(errors.empty?, errors.join("\n")) # This should actually pass, because this matches the first schema in the union data["a"] << {"c" => false} assert_valid schema, data end def test_required # Set up the default datatype schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "properties" => { "a" => {"required" => true} } } data = {} refute_valid schema, data data['a'] = "Hello" assert_valid schema, data schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "properties" => { "a" => {"type" => "integer"} } } data = {} assert_valid schema, data end def test_strict_properties_required_props schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "properties" => { "a" => {"type" => "string", "required" => true}, "b" => {"type" => "string", "required" => false} } } data = {"a" => "a"} assert(JSON::Validator.validate(schema,data,:strict => true)) data = {"b" => "b"} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b"} assert(JSON::Validator.validate(schema,data,:strict => true)) end def test_strict_properties_additional_props schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "properties" => { "a" => {"type" => "string"}, "b" => {"type" => "string"} }, "additionalProperties" => {"type" => "integer"} } data = {"a" => "a"} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"b" => "b"} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b"} assert(JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b", "c" => "c"} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b", "c" => 3} assert(JSON::Validator.validate(schema,data,:strict => true)) end def test_strict_properties_pattern_props schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "properties" => { "a" => {"type" => "string"}, "b" => {"type" => "string"} }, "patternProperties" => {"\\d+ taco" => {"type" => "integer"}} } data = {"a" => "a"} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"b" => "b"} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b"} assert(JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b", "c" => "c"} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b", "c" => 3} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b", "23 taco" => 3} assert(JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b", "23 taco" => "cheese"} assert(!JSON::Validator.validate(schema,data,:strict => true)) end def test_disallow # Set up the default datatype schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "properties" => { "a" => {"disallow" => "integer"} } } data = { "a" => nil } data["a"] = 'string' assert_valid schema, data data["a"] = 5 refute_valid schema, data schema["properties"]["a"]["disallow"] = ["integer","string"] data["a"] = 'string' refute_valid schema, data data["a"] = 5 refute_valid schema, data data["a"] = false assert_valid schema, data end def test_extends schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "properties" => { "a" => { "type" => "integer"} } } schema2 = { "$schema" => "http://json-schema.org/draft-03/schema#", "properties" => { "a" => { "maximum" => 5 } } } data = { "a" => 10 } assert_valid schema, data assert(!JSON::Validator.validate(schema2,data)) schema["extends"] = schema2 refute_valid schema, data end def test_list_option schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "type" => "object", "properties" => { "a" => {"type" => "integer", "required" => true} } } data = [{"a" => 1},{"a" => 2},{"a" => 3}] assert(JSON::Validator.validate(schema,data,:list => true)) refute_valid schema, data data = {"a" => 1} assert(!JSON::Validator.validate(schema,data,:list => true)) data = [{"a" => 1},{"b" => 2},{"a" => 3}] assert(!JSON::Validator.validate(schema,data,:list => true)) end def test_self_reference schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "type" => "object", "properties" => { "a" => {"type" => "integer"}, "b" => {"$ref" => "#"}} } assert_valid schema, {"a" => 5, "b" => {"b" => {"a" => 1}}} refute_valid schema, {"a" => 5, "b" => {"b" => {"a" => 'taco'}}} end def test_format_datetime schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "type" => "object", "properties" => { "a" => {"type" => "string", "format" => "date-time"}} } assert_valid schema, {"a" => "2010-01-01T12:00:00Z"} assert_valid schema, {"a" => "2010-01-01T12:00:00.1Z"} assert_valid schema, {"a" => "2010-01-01T12:00:00,1Z"} refute_valid schema, {"a" => "2010-01-32T12:00:00Z"} refute_valid schema, {"a" => "2010-13-01T12:00:00Z"} refute_valid schema, {"a" => "2010-01-01T24:00:00Z"} refute_valid schema, {"a" => "2010-01-01T12:60:00Z"} refute_valid schema, {"a" => "2010-01-01T12:00:60Z"} refute_valid schema, {"a" => "2010-01-01T12:00:00z"} refute_valid schema, {"a" => "2010-01-0112:00:00Z"} refute_valid schema, {"a" => "2010-01-01T12:00:00.1Z\nabc"} # test with a specific timezone assert_valid schema, {"a" => "2010-01-01T12:00:00+01"} assert_valid schema, {"a" => "2010-01-01T12:00:00+01:00"} assert_valid schema, {"a" => "2010-01-01T12:00:00+01:30"} assert_valid schema, {"a" => "2010-01-01T12:00:00+0234"} refute_valid schema, {"a" => "2010-01-01T12:00:00+01:"} refute_valid schema, {"a" => "2010-01-01T12:00:00+0"} # do not allow mixing Z and specific timezone refute_valid schema, {"a" => "2010-01-01T12:00:00Z+01"} refute_valid schema, {"a" => "2010-01-01T12:00:00+01Z"} refute_valid schema, {"a" => "2010-01-01T12:00:00+01:30Z"} refute_valid schema, {"a" => "2010-01-01T12:00:00+0Z"} # test without any timezone assert_valid schema, {"a" => "2010-01-01T12:00:00"} assert_valid schema, {"a" => "2010-01-01T12:00:00.12345"} assert_valid schema, {"a" => "2010-01-01T12:00:00,12345"} assert_valid schema, {"a" => "2010-01-01T12:00:00.12345"} end def test_format_uri data1 = {"a" => "http://gitbuh.com"} data2 = {"a" => "::boo"} data3 = {"a" => "http://ja.wikipedia.org/wiki/メインページ"} schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "type" => "object", "properties" => { "a" => {"type" => "string", "format" => "uri"}} } assert(JSON::Validator.validate(schema,data1)) assert(!JSON::Validator.validate(schema,data2)) assert(JSON::Validator.validate(schema,data3)) end def test_schema schema = { "$schema" => "http://json-schema.org/THIS-IS-NOT-A-SCHEMA", "type" => "object" } data = {"a" => "taco"} assert(!JSON::Validator.validate(schema, data)) schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "type" => "object" } assert_valid schema, data end def test_dependency schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "type" => "object", "properties" => { "a" => {"type" => "integer"}, "b" => {"type" => "integer"} }, "dependencies" => { "a" => "b" } } data = {"a" => 1, "b" => 2} assert_valid schema, data data = {"a" => 1} refute_valid schema, data schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "type" => "object", "properties" => { "a" => {"type" => "integer"}, "b" => {"type" => "integer"}, "c" => {"type" => "integer"} }, "dependencies" => { "a" => ["b","c"] } } data = {"a" => 1, "c" => 2} refute_valid schema, data data = {"a" => 1, "b" => 2, "c" => 3} assert_valid schema, data end def test_default schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "type" => "object", "properties" => { "a" => {"type" => "integer", "default" => 42}, "b" => {"type" => "integer"} } } data = {:b => 2} assert_valid schema, data assert_nil(data["a"]) assert(JSON::Validator.validate(schema,data, :insert_defaults => true)) assert_equal(42, data["a"]) assert_equal(2, data[:b]) schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "type" => "object", "properties" => { "a" => {"type" => "integer", "default" => 42, "required" => true}, "b" => {"type" => "integer"} } } data = {:b => 2} refute_valid schema, data assert_nil(data["a"]) assert(JSON::Validator.validate(schema,data, :insert_defaults => true)) assert_equal(42, data["a"]) assert_equal(2, data[:b]) schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "type" => "object", "properties" => { "a" => {"type" => "integer", "default" => 42, "required" => true, "readonly" => true}, "b" => {"type" => "integer"} } } data = {:b => 2} refute_valid schema, data assert_nil(data["a"]) assert(!JSON::Validator.validate(schema,data, :insert_defaults => true)) assert_nil(data["a"]) assert_equal(2, data[:b]) schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "type" => "object", "properties" => { "a" => {"type" => "integer", "default" => "42"}, "b" => {"type" => "integer"} } } data = {:b => 2} assert_valid schema, data assert_nil(data["a"]) assert(!JSON::Validator.validate(schema,data, :insert_defaults => true)) assert_equal("42",data["a"]) assert_equal(2, data[:b]) end end json-schema-2.6.0/test/test_jsonschema_draft4.rb000066400000000000000000000410611264371451000216740ustar00rootroot00000000000000# encoding: utf-8 require File.expand_path('../test_helper', __FILE__) class JSONSchemaDraft4Test < Minitest::Test def schema_version :draft4 end def exclusive_minimum { 'exclusiveMinimum' => true } end def exclusive_maximum { 'exclusiveMaximum' => true } end def ipv4_format 'ipv4' end include ArrayValidation::ItemsTests include ArrayValidation::AdditionalItemsTests include ArrayValidation::UniqueItemsTests include EnumValidation::General include EnumValidation::V3_V4 include NumberValidation::MinMaxTests include NumberValidation::MultipleOfTests include ObjectValidation::AdditionalPropertiesTests include ObjectValidation::PatternPropertiesTests include StrictValidation include StringValidation::ValueTests include StringValidation::FormatTests include TypeValidation::SimpleTypeTests def test_required # Set up the default datatype schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "required" => ["a"], "properties" => { "a" => {} } } data = {} refute_valid schema, data data['a'] = "Hello" assert_valid schema, data schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "properties" => { "a" => {"type" => "integer"} } } data = {} assert_valid schema, data end def test_min_properties schema = { 'minProperties' => 2 } assert_valid schema, {'a' => 1, 'b' => 2} assert_valid schema, {'a' => 1, 'b' => 2, 'c' => 3} refute_valid schema, {'a' => 1} refute_valid schema, {} end def test_max_properties schema = { 'maxProperties' => 2 } assert_valid schema, {'a' => 1, 'b' => 2} assert_valid schema, {'a' => 1} assert_valid schema, {} refute_valid schema, {'a' => 1, 'b' => 2, 'c' => 3} end def test_strict_properties schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "properties" => { "a" => {"type" => "string"}, "b" => {"type" => "string"} } } data = {"a" => "a"} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"b" => "b"} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b"} assert(JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b", "c" => "c"} assert(!JSON::Validator.validate(schema,data,:strict => true)) end def test_strict_properties_additional_props schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "properties" => { "a" => {"type" => "string"}, "b" => {"type" => "string"} }, "additionalProperties" => {"type" => "integer"} } data = {"a" => "a"} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"b" => "b"} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b"} assert(JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b", "c" => "c"} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b", "c" => 3} assert(JSON::Validator.validate(schema,data,:strict => true)) end def test_strict_properties_pattern_props schema = { "$schema" => "http://json-schema.org/draft-03/schema#", "properties" => { "a" => {"type" => "string"}, "b" => {"type" => "string"} }, "patternProperties" => {"\\d+ taco" => {"type" => "integer"}} } data = {"a" => "a"} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"b" => "b"} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b"} assert(JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b", "c" => "c"} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b", "c" => 3} assert(!JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b", "23 taco" => 3} assert(JSON::Validator.validate(schema,data,:strict => true)) data = {"a" => "a", "b" => "b", "23 taco" => "cheese"} assert(!JSON::Validator.validate(schema,data,:strict => true)) end def test_list_option schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "type" => "object", "required" => ["a"], "properties" => { "a" => {"type" => "integer"} } } data = [{"a" => 1},{"a" => 2},{"a" => 3}] assert(JSON::Validator.validate(schema,data,:list => true)) refute_valid schema, data data = {"a" => 1} assert(!JSON::Validator.validate(schema,data,:list => true)) data = [{"a" => 1},{"b" => 2},{"a" => 3}] assert(!JSON::Validator.validate(schema,data,:list => true)) end def test_default_with_strict_and_anyof schema = { "anyOf" => [ { "type" => "object", "properties" => { "foo" => { "enum" => ["view", "search"], "default" => "view" } } }, { "type" => "object", "properties" => { "bar" => { "type" => "string" } } } ] } data = { "bar" => "baz" } assert(JSON::Validator.validate(schema, data, :insert_defaults => true, :strict => true)) end def test_default_with_anyof schema = { "anyOf" => [ { "type" => "object", "properties" => { "foo" => { "enum" => ["view", "search"], "default" => "view" } } }, { "type" => "object", "properties" => { "bar" => { "type" => "string" } } } ] } data = {} assert(JSON::Validator.validate(schema, data, :insert_defaults => true, :strict => true)) assert(data['foo'] == 'view') end def test_default_with_strict_and_oneof schema = { "oneOf" => [ { "type" => "object", "properties" => { "bar" => { "type" => "string" } } }, { "type" => "object", "properties" => { "foo" => { "enum" => ["view", "search"], "default" => "view" } } } ] } data = { "bar" => "baz" } assert(JSON::Validator.validate(schema, data, :insert_defaults => true, :strict => true)) assert(!data.key?('foo')) end def test_self_reference schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "type" => "object", "properties" => { "a" => {"type" => "integer"}, "b" => {"$ref" => "#"}} } assert_valid schema, {"a" => 5, "b" => {"b" => {"a" => 1}}} refute_valid schema, {"a" => 5, "b" => {"b" => {"a" => 'taco'}}} end def test_format_datetime schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "type" => "object", "properties" => { "a" => {"type" => "string", "format" => "date-time"}} } assert_valid schema, {"a" => "2010-01-01T12:00:00Z"} assert_valid schema, {"a" => "2010-01-01T12:00:00.1Z"} refute_valid schema, {"a" => "2010-01-01T12:00:00,1Z"} refute_valid schema, {"a" => "2010-01-01T12:00:00+0000"} assert_valid schema, {"a" => "2010-01-01T12:00:00+00:00"} refute_valid schema, {"a" => "2010-01-32T12:00:00Z"} refute_valid schema, {"a" => "2010-13-01T12:00:00Z"} assert_valid schema, {"a" => "2010-01-01T24:00:00Z"} refute_valid schema, {"a" => "2010-01-01T12:60:00Z"} assert_valid schema, {"a" => "2010-01-01T12:00:60Z"} assert_valid schema, {"a" => "2010-01-01T12:00:00z"} refute_valid schema, {"a" => "2010-01-0112:00:00Z"} end def test_format_uri data1 = {"a" => "http://gitbuh.com"} data2 = {"a" => "::boo"} data3 = {"a" => "http://ja.wikipedia.org/wiki/メインページ"} schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "type" => "object", "properties" => { "a" => {"type" => "string", "format" => "uri"}} } assert(JSON::Validator.validate(schema,data1)) assert(!JSON::Validator.validate(schema,data2)) assert(JSON::Validator.validate(schema,data3)) end def test_schema schema = { "$schema" => "http://json-schema.org/THIS-IS-NOT-A-SCHEMA", "type" => "object" } data = {"a" => "taco"} assert(!JSON::Validator.validate(schema,data)) schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "type" => "object" } assert_valid schema, data end def test_dependency schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "type" => "object", "properties" => { "a" => {"type" => "integer"}, "b" => {"type" => "integer"} }, "dependencies" => { "a" => ["b"] } } data = {"a" => 1, "b" => 2} assert_valid schema, data data = {"a" => 1} refute_valid schema, data schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "type" => "object", "properties" => { "a" => {"type" => "integer"}, "b" => {"type" => "integer"}, "c" => {"type" => "integer"} }, "dependencies" => { "a" => ["b","c"] } } data = {"a" => 1, "c" => 2} refute_valid schema, data data = {"a" => 1, "b" => 2, "c" => 3} assert_valid schema, data end def test_schema_dependency schema = { "type"=> "object", "properties"=> { "name"=> { "type"=> "string" }, "credit_card"=> { "type"=> "number" } }, "required"=> ["name"], "dependencies"=> { "credit_card"=> { "properties"=> { "billing_address"=> { "type"=> "string" } }, "required"=> ["billing_address"] } } } data = { "name" => "John Doe", "credit_card" => 5555555555555555 } assert(!JSON::Validator.validate(schema,data), 'test schema dependency with invalid data') data['billing_address'] = "Somewhere over the rainbow" assert(JSON::Validator.validate(schema,data), 'test schema dependency with valid data') end def test_default schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "type" => "object", "properties" => { "a" => {"type" => "integer", "default" => 42}, "b" => {"type" => "integer"} } } data = {:b => 2} assert_valid schema, data assert_nil(data["a"]) assert(JSON::Validator.validate(schema,data, :insert_defaults => true)) assert_equal(42, data["a"]) assert_equal(2, data[:b]) schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "type" => "object", "required" => ["a"], "properties" => { "a" => {"type" => "integer", "default" => 42}, "b" => {"type" => "integer"} } } data = {:b => 2} refute_valid schema, data assert_nil(data["a"]) assert(JSON::Validator.validate(schema,data, :insert_defaults => true)) assert_equal(42, data["a"]) assert_equal(2, data[:b]) schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "type" => "object", "required" => ["a"], "properties" => { "a" => {"type" => "integer", "default" => 42, "readonly" => true}, "b" => {"type" => "integer"} } } data = {:b => 2} refute_valid schema, data assert_nil(data["a"]) assert(!JSON::Validator.validate(schema,data, :insert_defaults => true)) assert_nil(data["a"]) assert_equal(2, data[:b]) schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "type" => "object", "properties" => { "a" => {"type" => "integer", "default" => "42"}, "b" => {"type" => "integer"} } } data = {:b => 2} assert_valid schema, data assert_nil(data["a"]) assert(!JSON::Validator.validate(schema,data, :insert_defaults => true)) assert_equal("42",data["a"]) assert_equal(2, data[:b]) end def test_boolean_false_default schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "type" => "object", "required" => ["a"], "properties" => { "a" => {"type" => "boolean", "default" => false}, "b" => {"type" => "integer"} } } data = {:b => 2} refute_valid schema, data assert_nil(data["a"]) assert(JSON::Validator.validate(schema, data, :insert_defaults => true)) assert_equal(false, data["a"]) assert_equal(2, data[:b]) end def test_all_of schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "allOf" => [ { "properties" => {"a" => {"type" => "string"}}, "required" => ["a"] }, { "properties" => {"b" => {"type" => "integer"}} } ] } data = {"a" => "hello", "b" => 5} assert_valid schema, data data = {"a" => "hello"} assert_valid schema, data data = {"a" => "hello", "b" => "taco"} refute_valid schema, data data = {"b" => 5} refute_valid schema, data end def test_any_of schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "anyOf" => [ { "properties" => {"a" => {"type" => "string"}}, "required" => ["a"] }, { "properties" => {"b" => {"type" => "integer"}} } ] } data = {"a" => "hello", "b" => 5} assert_valid schema, data data = {"a" => "hello"} assert_valid schema, data data = {"a" => "hello", "b" => "taco"} assert_valid schema, data data = {"b" => 5} assert_valid schema, data data = {"a" => 5, "b" => "taco"} refute_valid schema, data end def test_one_of schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "oneOf" => [ { "properties" => {"a" => {"type" => "string"}}, "required" => ["a"] }, { "properties" => {"b" => {"type" => "integer"}} } ] } data = {"a" => "hello", "b" => 5} refute_valid schema, data # This passes because b is not required, thus matches both schemas data = {"a" => "hello"} refute_valid schema, data data = {"a" => "hello", "b" => "taco"} assert_valid schema, data data = {"b" => 5} assert_valid schema, data data = {"a" => 5, "b" => "taco"} refute_valid schema, data end def test_not # Start with a simple not schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "properties" => { "a" => {"not" => { "type" => ["string", "boolean"]}} } } data = {"a" => 1} assert_valid schema, data data = {"a" => "hi!"} refute_valid schema, data data = {"a" => true} refute_valid schema, data # Sub-schema not schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "properties" => { "a" => {"not" => {"anyOf" => [ { "type" => ["string","boolean"] }, { "type" => "object", "properties" => { "b" => {"type" => "boolean"} } } ]} } } } data = {"a" => 1} assert_valid schema, data data = {"a" => "hi!"} refute_valid schema, data data = {"a" => true} refute_valid schema, data data = {"a" => {"b" => true}} refute_valid schema, data data = {"a" => {"b" => 5}} assert_valid schema, data end def test_not_fully_validate # Start with a simple not schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "properties" => { "a" => {"not" => { "type" => ["string", "boolean"]}} } } data = {"a" => 1} errors = JSON::Validator.fully_validate(schema,data) assert_equal(0, errors.length) data = {"a" => "taco"} errors = JSON::Validator.fully_validate(schema,data) assert_equal(1, errors.length) end def test_definitions schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "type" => "array", "items" => { "$ref" => "#/definitions/positiveInteger"}, "definitions" => { "positiveInteger" => { "type" => "integer", "minimum" => 0, "exclusiveMinimum" => true } } } data = [1,2,3] assert_valid schema, data data = [-1,2,3] refute_valid schema, data end end json-schema-2.6.0/test/test_list_option.rb000066400000000000000000000011131264371451000206330ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) class ListOptionTest < Minitest::Test def test_list_option_reusing_schemas schema_hash = { "$schema" => "http://json-schema.org/draft-04/schema#", "type" => "object", "properties" => { "a" => { "type" => "integer" } } } uri = Addressable::URI.parse('http://example.com/item') schema = JSON::Schema.new(schema_hash, uri) JSON::Validator.add_schema(schema) data = {"a" => 1} assert_valid uri.to_s, data data = [{"a" => 1}] assert_valid uri.to_s, data, :list => true end end json-schema-2.6.0/test/test_load_ref_schema.rb000066400000000000000000000017601264371451000213730ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) class LoadRefSchemaTests < Minitest::Test def load_other_schema JSON::Validator.add_schema(JSON::Schema.new( { '$schema' => 'http://json-schema.org/draft-04/schema#', 'type' => 'object', 'properties' => { "title" => { "type" => "string" } } }, Addressable::URI.parse("http://example.com/schema#") )) end def test_cached_schema schema_url = "http://example.com/schema#" schema = { "$ref" => schema_url } data = {} load_other_schema _validator = JSON::Validator.new(schema, data) assert JSON::Validator.schema_loaded?(schema_url) end def test_cached_schema_with_fragment schema_url = "http://example.com/schema#" schema = { "$ref" => "#{schema_url}/properties/title" } data = {} load_other_schema _validator = JSON::Validator.new(schema, data) assert JSON::Validator.schema_loaded?(schema_url) end end json-schema-2.6.0/test/test_merge_missing_values.rb000066400000000000000000000033311264371451000225030ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) class MergeMissingValuesTest < Minitest::Test def test_merge_missing_values_for_string original = 'foo' updated = 'foo' JSON::Validator.merge_missing_values(updated, original) assert_equal('foo', original) end def test_merge_missing_values_for_empty_array original = [] updated = [] JSON::Validator.merge_missing_values(updated, original) assert_equal([], original) end def test_merge_missing_values_for_empty_hash original = {} updated = {} JSON::Validator.merge_missing_values(updated, original) assert_equal({}, original) end def test_merge_missing_values_for_new_values original = {:hello => 'world'} updated = {'hello' => 'world', 'foo' => 'bar'} JSON::Validator.merge_missing_values(updated, original) assert_equal({:hello => 'world', 'foo' => 'bar'}, original) end def test_merge_missing_values_for_nested_array original = [:hello, 'world', 1, 2, 3, {:foo => :bar, 'baz' => 'qux'}] updated = ['hello', 'world', 1, 2, 3, {'foo' => 'bar', 'baz' => 'qux', 'this_is' => 'new'}] JSON::Validator.merge_missing_values(updated, original) assert_equal([:hello, 'world', 1, 2, 3, {:foo => :bar, 'baz' => 'qux', 'this_is' => 'new'}], original) end def test_merge_missing_values_for_nested_hash original = {:hello => 'world', :foo => ['bar', :baz, {:uno => {:due => 3}}]} updated = {'hello' => 'world', 'foo' => ['bar', 'baz', {'uno' => {'due' => 3, 'this_is' => 'new'}}], 'ack' => 'sed'} JSON::Validator.merge_missing_values(updated, original) assert_equal({:hello => 'world', :foo => ['bar', :baz, {:uno => {:due => 3, 'this_is' => 'new'}}], 'ack' => 'sed'}, original) end end json-schema-2.6.0/test/test_minitems.rb000066400000000000000000000006201264371451000201170ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) class MinItemsTest < Minitest::Test def test_minitems_nils schema = { "type" => "array", "minItems" => 1, "items" => { "type" => "object" } } errors = JSON::Validator.fully_validate(schema, [nil]) assert_equal(errors.length, 1) assert(errors[0] !~ /minimum/) assert(errors[0] =~ /NilClass/) end end json-schema-2.6.0/test/test_one_of.rb000066400000000000000000000054061264371451000175460ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) class OneOfTest < Minitest::Test def test_one_of_links_schema schema = schema_fixture_path('one_of_ref_links_schema.json') data = data_fixture_path('one_of_ref_links_data.json') assert_valid schema, data end def test_one_of_with_string_patterns schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "oneOf" => [ { "properties" => {"a" => {"type" => "string", "pattern" => "foo"}}, }, { "properties" => {"a" => {"type" => "string", "pattern" => "bar"}}, }, { "properties" => {"a" => {"type" => "string", "pattern" => "baz"}}, } ] } assert_valid schema, { "a" => "foo" } refute_valid schema, { "a" => "foobar" } assert_valid schema, { "a" => "baz" } refute_valid schema, { "a" => 5 } end def test_one_of_sub_errors schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "oneOf" => [ { "properties" => {"a" => {"type" => "string", "pattern" => "foo"}}, }, { "properties" => {"a" => {"type" => "string", "pattern" => "bar"}}, }, { "properties" => {"a" => {"type" => "number", "minimum" => 10}}, } ] } errors = JSON::Validator.fully_validate(schema, { "a" => 5 }, :errors_as_objects => true) nested_errors = errors[0][:errors] assert_equal([:oneof_0,:oneof_1,:oneof_2], nested_errors.keys, 'should have nested errors for each allOf subschema') assert_match(/the property '#\/a' of type Fixnum did not match the following type: string/i, nested_errors[:oneof_0][0][:message]) assert_match(/the property '#\/a' did not have a minimum value of 10, inclusively/i, nested_errors[:oneof_2][0][:message]) end def test_one_of_sub_errors_message schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "oneOf" => [ { "properties" => {"a" => {"type" => "string", "pattern" => "foo"}}, }, { "properties" => {"a" => {"type" => "string", "pattern" => "bar"}}, }, { "properties" => {"a" => {"type" => "number", "minimum" => 10}}, } ] } errors = JSON::Validator.fully_validate(schema, { "a" => 5 }) expected_message = """The property '#/' of type Hash did not match any of the required schemas. The schema specific errors were: - oneOf #0: - The property '#/a' of type Fixnum did not match the following type: string - oneOf #1: - The property '#/a' of type Fixnum did not match the following type: string - oneOf #2: - The property '#/a' did not have a minimum value of 10, inclusively""" assert_equal(expected_message, errors[0]) end end json-schema-2.6.0/test/test_ruby_schema.rb000066400000000000000000000021471264371451000206010ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) class RubySchemaTest < Minitest::Test def test_string_keys schema = { "type" => 'object', "required" => ["a"], "properties" => { "a" => {"type" => "integer", "default" => 42}, "b" => {"type" => "integer"} } } assert_valid schema, { "a" => 5 } end def test_symbol_keys schema = { :type => 'object', :required => ["a"], :properties => { :a => {:type => "integer", :default => 42}, :b => {:type => "integer"} } } assert_valid schema, { :a => 5 } end def test_symbol_keys_in_hash_within_array schema = { :type => 'object', :properties => { :a => { :type => "array", :items => [ { :properties => { :b => { :type => "integer" } } } ] } } } data = { :a => [ { :b => 1 } ] } assert_valid schema, data, :validate_schema => true end end json-schema-2.6.0/test/test_schema_loader.rb000066400000000000000000000043531264371451000210670ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) class TestSchemaReader < Minitest::Test ADDRESS_SCHEMA_URI = 'http://json-schema.org/address' ADDRESS_SCHEMA_PATH = File.expand_path('../schemas/address_microformat.json', __FILE__) def stub_address_request(body = File.read(ADDRESS_SCHEMA_PATH)) stub_request(:get, ADDRESS_SCHEMA_URI). to_return(:body => body, :status => 200) end def test_accept_all_uris stub_address_request reader = JSON::Schema::Reader.new schema = reader.read(ADDRESS_SCHEMA_URI) assert_equal schema.uri, Addressable::URI.parse("#{ADDRESS_SCHEMA_URI}#") end def test_accept_all_files reader = JSON::Schema::Reader.new schema = reader.read(ADDRESS_SCHEMA_PATH) assert_equal schema.uri, Addressable::URI.convert_path(ADDRESS_SCHEMA_PATH + '#') end def test_refuse_all_uris reader = JSON::Schema::Reader.new(:accept_uri => false) refute reader.accept_uri?(Addressable::URI.parse('http://foo.com')) end def test_refuse_all_files reader = JSON::Schema::Reader.new(:accept_file => false) refute reader.accept_file?(Pathname.new('/foo/bar/baz')) end def test_accept_uri_proc reader = JSON::Schema::Reader.new( :accept_uri => proc { |uri| uri.host == 'json-schema.org' } ) assert reader.accept_uri?(Addressable::URI.parse('http://json-schema.org/address')) refute reader.accept_uri?(Addressable::URI.parse('http://sub.json-schema.org/address')) end def test_accept_file_proc test_root = Pathname.new(__FILE__).expand_path.dirname reader = JSON::Schema::Reader.new( :accept_file => proc { |path| path.to_s.start_with?(test_root.to_s) } ) assert reader.accept_file?(test_root.join('anything.json')) refute reader.accept_file?(test_root.join('..', 'anything.json')) end def test_file_scheme reader = JSON::Schema::Reader.new(:accept_uri => true, :accept_file => false) assert_raises(JSON::Schema::ReadRefused) do reader.read('file://' + ADDRESS_SCHEMA_PATH) end end def test_parse_error stub_address_request('this is totally not valid JSON!') reader = JSON::Schema::Reader.new assert_raises(JSON::Schema::JsonParseError) do reader.read(ADDRESS_SCHEMA_URI) end end end json-schema-2.6.0/test/test_schema_type_attribute.rb000066400000000000000000000011571264371451000226640ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) class TestSchemaTypeAttribute < Minitest::Test def test_type_of_data assert_equal(type_of_data(String.new), 'string') assert_equal(type_of_data(Numeric.new), 'number') assert_equal(type_of_data(1), 'integer') assert_equal(type_of_data(true), 'boolean') assert_equal(type_of_data(false), 'boolean') assert_equal(type_of_data(Hash.new), 'object') assert_equal(type_of_data(nil), 'null') assert_equal(type_of_data(Object.new), 'any') end private def type_of_data(data) JSON::Schema::TypeAttribute.type_of_data(data) end end json-schema-2.6.0/test/test_schema_validation.rb000066400000000000000000000110031264371451000217410ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) require 'tmpdir' class JSONSchemaValidation < Minitest::Test def valid_schema_v3 { "$schema" => "http://json-schema.org/draft-03/schema#", "type" => "object", "properties" => { "b" => { "required" => true } } } end def invalid_schema_v3 { "$schema" => "http://json-schema.org/draft-03/schema#", "type" => "object", "properties" => { "b" => { "required" => "true" } } } end def valid_schema_v4 { "$schema" => "http://json-schema.org/draft-04/schema#", "type" => "object", "required" => ["b"], "properties" => { } } end def invalid_schema_v4 { "$schema" => "http://json-schema.org/draft-04/schema#", "type" => "object", "required" => "b", "properties" => { } } end def symbolized_schema { :type => :object, :required => [ :id, :name, :real_name, :role, :website, :biography, :created_at, :demographic ], :properties => { :id => { :type => [ :integer ] }, :name => { :type => [ :string ] }, :real_name => { :type => [ :string ] }, :role => { :type => [ :string ] }, :website => { :type => [ :string, :null ] }, :created_at => { :type => [ :string ] }, :biography => { :type => [ :string, :null ] } }, :relationships => { :demographic => { :type => :object, :required => [ :id, :gender ], :properties => { :id => { :type => [ :integer ] }, :gender => { :type => [ :string ] } } } } } end def test_draft03_validation data = {"b" => {"a" => 5}} assert(JSON::Validator.validate(valid_schema_v3,data,:validate_schema => true, :version => :draft3)) assert(!JSON::Validator.validate(invalid_schema_v3,data,:validate_schema => true, :version => :draft3)) end def test_validate_just_schema_draft03 errors = JSON::Validator.fully_validate_schema(valid_schema_v3, :version => :draft3) assert_equal [], errors errors = JSON::Validator.fully_validate_schema(invalid_schema_v3, :version => :draft3) assert_equal 1, errors.size assert_match(/the property .*required.*did not match/i, errors.first) end def test_draft04_validation data = {"b" => {"a" => 5}} assert(JSON::Validator.validate(valid_schema_v4,data,:validate_schema => true, :version => :draft4)) assert(!JSON::Validator.validate(invalid_schema_v4,data,:validate_schema => true, :version => :draft4)) end def test_validate_just_schema_draft04 errors = JSON::Validator.fully_validate_schema(valid_schema_v4, :version => :draft4) assert_equal [], errors errors = JSON::Validator.fully_validate_schema(invalid_schema_v4, :version => :draft4) assert_equal 1, errors.size assert_match(/the property .*required.*did not match/i, errors.first) end def test_validate_schema_3_without_version_option data = {"b" => {"a" => 5}} assert(JSON::Validator.validate(valid_schema_v3,data,:validate_schema => true)) assert(!JSON::Validator.validate(invalid_schema_v3,data,:validate_schema => true)) end def test_schema_validation_from_different_directory Dir.mktmpdir do |tmpdir| Dir.chdir(tmpdir) do data = {"b" => {"a" => 5}} assert(JSON::Validator.validate(valid_schema_v4,data,:validate_schema => true, :version => :draft4)) assert(!JSON::Validator.validate(invalid_schema_v4,data,:validate_schema => true, :version => :draft4)) end end end def test_validate_schema_with_symbol_keys data = { "created_at" => "2014-01-25T00:58:33-08:00", "id" => 8517194300913402149003, "name" => "chelsey", "real_name" => "Mekhi Hegmann", "website" => nil, "role" => "user", "biography" => nil, "demographic" => nil } assert(JSON::Validator.validate!(symbolized_schema, data, :validate_schema => true)) end end json-schema-2.6.0/test/test_stringify.rb000066400000000000000000000023771264371451000203230ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) class StringifyTest < Minitest::Test def test_stringify_on_hash hash = { :a => 'foo', 'b' => :bar } assert_equal({'a' => 'foo', 'b' => 'bar'}, JSON::Schema.stringify(hash), 'symbol keys should be converted to strings') end def test_stringify_on_array array = [ :a, 'b' ] assert_equal(['a', 'b'], JSON::Schema.stringify(array), 'symbols in an array should be converted to strings') end def test_stringify_on_hash_of_arrays hash = { :a => [:foo], 'b' => :bar } assert_equal({'a' => ['foo'], 'b' => 'bar'}, JSON::Schema.stringify(hash), 'symbols in a nested array should be converted to strings') end def test_stringify_on_array_of_hashes array = [ :a, { :b => :bar } ] assert_equal(['a', {'b' => 'bar'}], JSON::Schema.stringify(array), 'symbols keys in a nested hash should be converted to strings') end def test_stringify_on_hash_of_hashes hash = { :a => { :b => { :foo => :bar } } } assert_equal({'a' => {'b' => {'foo' => 'bar'} } }, JSON::Schema.stringify(hash), 'symbols in a nested hash of hashes should be converted to strings') end end json-schema-2.6.0/test/test_uri_related.rb000066400000000000000000000032311264371451000205720ustar00rootroot00000000000000# coding: utf-8 require File.expand_path('../test_helper', __FILE__) class UriRelatedTest < Minitest::Test def test_asian_characters schema = { "$schema"=> "http://json-schema.org/draft-04/schema#", "id"=> "http://俺:鍵@例え.テスト/p?条件#ここ#", "type" => "object", "required" => ["a"], "properties" => { "a" => { "id" => "a", "type" => "integer" } } } data = { "a" => 5 } assert_valid schema, data end def test_schema_ref_with_empty_fragment schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "type" => "object", "required" => ["names"], "properties"=> { "names"=> { "type"=> "array", "items"=> { "anyOf"=> [ { "$ref" => "test/schemas/ref john with spaces schema.json#" }, ] } } } } data = {"names" => [{"first" => "john"}]} assert_valid schema, data end def test_schema_ref_from_file_with_spaces schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "type" => "object", "required" => ["names"], "properties"=> { "names"=> { "type"=> "array", "items"=> { "anyOf"=> [ { "$ref" => "test/schemas/ref john with spaces schema.json" } ] } } } } data = {"names" => [{"first" => "john"}]} assert_valid schema, data end def test_schema_from_file_with_spaces data = {"first" => "john"} schema = "test/schemas/ref john with spaces schema.json" assert_valid schema, data end end json-schema-2.6.0/test/test_validator.rb000066400000000000000000000026561264371451000202720ustar00rootroot00000000000000require File.expand_path('../test_helper', __FILE__) class TestValidator < Minitest::Test class MockReader def read(location) schema = { '$schema' => 'http://json-schema.org/draft-04/schema#', 'type' => 'string', 'minLength' => 2 } JSON::Schema.new(schema, Addressable::URI.parse(location.to_s)) end end def setup @original_reader = JSON::Validator.schema_reader end def teardown JSON::Validator.schema_reader = @original_reader end def test_default_schema_reader reader = JSON::Validator.schema_reader assert reader.accept_uri?(Addressable::URI.parse('http://example.com')) assert reader.accept_file?(Pathname.new('/etc/passwd')) end def test_set_default_schema_reader JSON::Validator.schema_reader = MockReader.new schema = { '$ref' => 'http://any.url/at/all' } assert_valid schema, 'abc' refute_valid schema, 'a' end def test_validate_with_reader reader = MockReader.new schema = { '$ref' => 'http://any.url/at/all' } assert_valid schema, 'abc', :schema_reader => reader refute_valid schema, 'a', :schema_reader => reader end def test_validate_list_with_reader reader = MockReader.new schema = { '$ref' => 'http://what.ever/schema' } assert_valid schema, ['abc', 'def'], :schema_reader => reader, :list => true refute_valid schema, ['abc', 'a'], :schema_reader => reader, :list => true end end