git.iko.soy/typeable/hjsonschema
on master help sign in
91 files changed+4630−647
since splitsnapshots
unifiedsplit
.travis.yml+67−56 JSON-Schema-Test-Suite/.travis.yml+7−2 JSON-Schema-Test-Suite/README.md+26−5 JSON-Schema-Test-Suite/bin/jsonschema_suite+2−27 JSON-Schema-Test-Suite/index.js+32 JSON-Schema-Test-Suite/package.json+28 JSON-Schema-Test-Suite/remotes/name.json+11 JSON-Schema-Test-Suite/test-schema.json+28 JSON-Schema-Test-Suite/tests/draft3/optional/format.json+2−2 JSON-Schema-Test-Suite/tests/draft3/ref.json+33 JSON-Schema-Test-Suite/tests/draft3/type.json+15 JSON-Schema-Test-Suite/tests/draft4/additionalItems.json+6−1 JSON-Schema-Test-Suite/tests/draft4/items.json+32 JSON-Schema-Test-Suite/tests/draft4/maximum.json+5 JSON-Schema-Test-Suite/tests/draft4/minimum.json+5 JSON-Schema-Test-Suite/tests/draft4/optional/ecmascript-regex.json+13 JSON-Schema-Test-Suite/tests/draft4/optional/format.json+2−2 JSON-Schema-Test-Suite/tests/draft4/ref.json+139 JSON-Schema-Test-Suite/tests/draft4/refRemote.json+100−3 JSON-Schema-Test-Suite/tests/draft4/required.json+5 JSON-Schema-Test-Suite/tests/draft4/type.json+15 JSON-Schema-Test-Suite/tests/draft6/additionalItems.json+87 JSON-Schema-Test-Suite/tests/draft6/additionalProperties.json+88 JSON-Schema-Test-Suite/tests/draft6/allOf.json+145 JSON-Schema-Test-Suite/tests/draft6/anyOf.json+101 JSON-Schema-Test-Suite/tests/draft6/boolean_schema.json+104 JSON-Schema-Test-Suite/tests/draft6/const.json+65 JSON-Schema-Test-Suite/tests/draft6/contains.json+95 JSON-Schema-Test-Suite/tests/draft6/default.json+49 JSON-Schema-Test-Suite/tests/draft6/definitions.json+32 JSON-Schema-Test-Suite/tests/draft6/dependencies.json+162 JSON-Schema-Test-Suite/tests/draft6/enum.json+72 JSON-Schema-Test-Suite/tests/draft6/exclusiveMaximum.json+30 JSON-Schema-Test-Suite/tests/draft6/exclusiveMinimum.json+30 JSON-Schema-Test-Suite/tests/draft6/items.json+133 JSON-Schema-Test-Suite/tests/draft6/maxItems.json+28 JSON-Schema-Test-Suite/tests/draft6/maxLength.json+33 JSON-Schema-Test-Suite/tests/draft6/maxProperties.json+28 JSON-Schema-Test-Suite/tests/draft6/maximum.json+28 JSON-Schema-Test-Suite/tests/draft6/minItems.json+28 JSON-Schema-Test-Suite/tests/draft6/minLength.json+33 JSON-Schema-Test-Suite/tests/draft6/minProperties.json+28 JSON-Schema-Test-Suite/tests/draft6/minimum.json+28 JSON-Schema-Test-Suite/tests/draft6/multipleOf.json+60 JSON-Schema-Test-Suite/tests/draft6/not.json+117 JSON-Schema-Test-Suite/tests/draft6/oneOf.json+112 JSON-Schema-Test-Suite/tests/draft6/optional/bignum.json+105 JSON-Schema-Test-Suite/tests/draft6/optional/ecmascript-regex.json+13 JSON-Schema-Test-Suite/tests/draft6/optional/format.json+148 JSON-Schema-Test-Suite/tests/draft6/optional/zeroTerminatedFloats.json+15 JSON-Schema-Test-Suite/tests/draft6/pattern.json+34 JSON-Schema-Test-Suite/tests/draft6/patternProperties.json+141 JSON-Schema-Test-Suite/tests/draft6/properties.json+123 JSON-Schema-Test-Suite/tests/draft6/propertyNames.json+68 JSON-Schema-Test-Suite/tests/draft6/ref.json+332 JSON-Schema-Test-Suite/tests/draft6/refRemote.json+171 JSON-Schema-Test-Suite/tests/draft6/required.json+60 JSON-Schema-Test-Suite/tests/draft6/type.json+345 JSON-Schema-Test-Suite/tests/draft6/uniqueItems.json+79 README.md+10−50 changelog.md+57 examples/AlternateSchema.hs+87−60 examples/Simple.hs+7−8 examples/TwoStep.hs+3−4 hjsonschema.cabal+25−29 logo.jpg shell.nix+5−3 src/Import.hs+15−8 src/JSONSchema/Draft4.hs+21−30 src/JSONSchema/Draft4/Failure.hs+1−2 src/JSONSchema/Draft4/Schema.hs+6−7 src/JSONSchema/Draft4/Spec.hs+61−39 src/JSONSchema/Fetch.hs+46−65 src/JSONSchema/Types.hs−1 src/JSONSchema/Validator/Draft4.hs+19−19 src/JSONSchema/Validator/Draft4/Any.hs+217−59 src/JSONSchema/Validator/Draft4/Array.hs+8−7 src/JSONSchema/Validator/Draft4/Number.hs+1−2 src/JSONSchema/Validator/Draft4/Object.hs+6−10 src/JSONSchema/Validator/Draft4/Object/Properties.hs+6−6 src/JSONSchema/Validator/Draft4/String.hs+2−3 src/JSONSchema/Validator/Reference.hs+28−36 src/JSONSchema/Validator/Types.hs−1 src/JSONSchema/Validator/Utils.hs+11−27 stack.yaml+2 test/Local.hs+10−14 test/Local/Failure.hs+6−7 test/Local/Reference.hs+12−13 test/Local/Validation.hs+5−6 test/Remote.hs+9−11 test/Shared.hs+21−22
.travis.yml+67−56
@@ -1,84 +1,95 @@
1−# Generated by: https://github.com/hvr/multi-ghc-travis
1+# This Travis job script has been generated by a script via
2+#
3+# make_travis_yml_2.hs 'hjsonschema.cabal'
4+#
5+# For more information, see https://github.com/hvr/multi-ghc-travis
26#
3−# Removed `cabal check` because I don't want a description field.
4−
57language: c
68sudo: false
79
10+git:
11+ submodules: false # whether to recursively clone submodules
12+
813cache:
914 directories:
10− - $HOME/.cabsnap
1115 - $HOME/.cabal/packages
16+ - $HOME/.cabal/store
1217
1318before_cache:
1419 - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log
15− - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.tar
20+ # remove files that are regenerated by 'cabal update'
21+ - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.*
22+ - rm -fv $HOME/.cabal/packages/hackage.haskell.org/*.json
23+ - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.cache
24+ - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar
25+ - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar.idx
1626
1727matrix:
1828 include:
19− - env: CABALVER=1.18 GHCVER=7.8.4
20− compiler: ": #GHC 7.8.4"
21− addons: {apt: {packages: [cabal-install-1.18,ghc-7.8.4], sources: [hvr-ghc]}}
22− - env: CABALVER=1.22 GHCVER=7.10.2
23− compiler: ": #GHC 7.10.2"
24− addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.2], sources: [hvr-ghc]}}
25− - env: CABALVER=1.24 GHCVER=8.0.1
26− compiler: ": #GHC 8.0.1"
27− addons: {apt: {packages: [cabal-install-1.24,ghc-8.0.1], sources: [hvr-ghc]}}
29+ - compiler: "ghc-8.0.2"
30+ # env: TEST=--disable-tests BENCH=--disable-benchmarks
31+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.0.2], sources: [hvr-ghc]}}
32+ - compiler: "ghc-8.2.2"
33+ # env: TEST=--disable-tests BENCH=--disable-benchmarks
34+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.2.2], sources: [hvr-ghc]}}
35+ - compiler: "ghc-8.4.1"
36+ # env: TEST=--disable-tests BENCH=--disable-benchmarks
37+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.4.1], sources: [hvr-ghc]}}
2838
2939before_install:
40+ - HC=${CC}
41+ - HCPKG=${HC/ghc/ghc-pkg}
3042 - unset CC
31− - export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH
43+ - PATH=/opt/ghc/bin:/opt/ghc-ppa-tools/bin:$PATH
44+ - PKGNAME='hjsonschema'
3245
3346install:
3447 - cabal --version
35− - echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]"
36− - if [ -f $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz ];
37− then
38− zcat $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz >
39− $HOME/.cabal/packages/hackage.haskell.org/00-index.tar;
40− fi
48+ - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
49+ - BENCH=${BENCH---enable-benchmarks}
50+ - TEST=${TEST---enable-tests}
51+ - HADDOCK=${HADDOCK-true}
52+ - INSTALLED=${INSTALLED-true}
4153 - travis_retry cabal update -v
42− - sed -i 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config
43− - cabal install --only-dependencies --enable-tests --enable-benchmarks --dry -v > installplan.txt
44− - sed -i -e '1,/^Resolving /d' installplan.txt; cat installplan.txt
45−
46−# check whether current requested install-plan matches cached package-db snapshot
47− - if diff -u installplan.txt $HOME/.cabsnap/installplan.txt;
48− then
49− echo "cabal build-cache HIT";
50− rm -rfv .ghc;
51− cp -a $HOME/.cabsnap/ghc $HOME/.ghc;
52− cp -a $HOME/.cabsnap/lib $HOME/.cabsnap/share $HOME/.cabsnap/bin $HOME/.cabal/;
53− else
54− echo "cabal build-cache MISS";
55− rm -rf $HOME/.cabsnap;
56− mkdir -p $HOME/.ghc $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin;
57− cabal install --only-dependencies --enable-tests --enable-benchmarks;
58− fi
59−
60−# snapshot package-db on cache miss
61− - if [ ! -d $HOME/.cabsnap ];
62− then
63− echo "snapshotting package-db to build-cache";
64− mkdir $HOME/.cabsnap;
65− cp -a $HOME/.ghc $HOME/.cabsnap/ghc;
66− cp -a $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin installplan.txt $HOME/.cabsnap/;
67− fi
54+ - sed -i.bak 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config
55+ - rm -fv cabal.project.local
56+ - "echo 'packages: .' > cabal.project"
57+ - rm -f cabal.project.freeze
58+ - cabal new-build -w ${HC} ${TEST} ${BENCH} --dep -j2 all
59+ - cabal new-build -w ${HC} --disable-tests --disable-benchmarks --dep -j2 all
6860
6961# Here starts the actual work to be performed for the package under test;
7062# any command which exits with a non-zero exit code causes the build to fail.
7163script:
7264 - if [ -f configure.ac ]; then autoreconf -i; fi
73− - cabal configure --enable-tests --enable-benchmarks -v2 # -v2 provides useful information for debugging
74− - cabal build # this builds all libraries and executables (including tests/benchmarks)
75− - cabal test
76− - cabal sdist # tests that a source-distribution can be generated
65+ - rm -rf .ghc.environment.* dist/
66+ - cabal sdist # test that a source-distribution can be generated
67+ - cd dist/
68+ - SRCTAR=(${PKGNAME}-*.tar.gz)
69+ - SRC_BASENAME="${SRCTAR/%.tar.gz}"
70+ - tar -xvf "./$SRC_BASENAME.tar.gz"
71+ - cd "$SRC_BASENAME/"
72+## from here on, CWD is inside the extracted source-tarball
73+ - rm -fv cabal.project.local
74+ - "echo 'packages: .' > cabal.project"
75+ # this builds all libraries and executables (without tests/benchmarks)
76+ - rm -f cabal.project.freeze
77+ - cabal new-build -w ${HC} --disable-tests --disable-benchmarks all
78+ # this builds all libraries and executables (including tests/benchmarks)
79+ # - rm -rf ./dist-newstyle
80+
81+ # Build with installed constraints for packages in global-db
82+ - if $INSTALLED; then
83+ echo cabal new-build -w ${HC} --disable-tests --disable-benchmarks $(${HCPKG} list --global --simple-output --names-only | sed 's/\([a-zA-Z0-9-]\{1,\}\) */--constraint="\1 installed" /g') all | sh;
84+ else echo "Not building with installed constraints"; fi
85+
86+ # build & run tests, build benchmarks
87+ - cabal new-build -w ${HC} ${TEST} ${BENCH} all
88+ - if [ "x$TEST" = "x--enable-tests" ]; then cabal new-test -w ${HC} ${TEST} all; fi
7789
78−# Check that the resulting source distribution can be built & installed.
79−# If there are no other `.tar.gz` files in `dist`, this can be even simpler:
80−# `cabal install --force-reinstalls dist/*-*.tar.gz`
81− - SRC_TGZ=$(cabal info . | awk '{print $2;exit}').tar.gz &&
82− (cd dist && cabal install --force-reinstalls "$SRC_TGZ")
90+ # haddock
91+ - rm -rf ./dist-newstyle
92+ - if $HADDOCK; then cabal new-haddock -w ${HC} --disable-tests --disable-benchmarks all; else echo "Skipping haddock generation";fi
8393
94+# REGENDATA ["hjsonschema.cabal"]
8495# EOF
JSON-Schema-Test-Suite/.travis.yml+7−2
@@ -1,4 +1,9 @@
11language: python
22python: "2.7"
3−install: pip install tox
4−script: tox
3+node_js: "6"
4+install:
5+ - pip install tox
6+ - npm install
7+script:
8+ - tox
9+ - npm test
JSON-Schema-Test-Suite/README.md+26−5
@@ -1,4 +1,4 @@
1−JSON Schema Test Suite [![Build Status](https://travis-ci.org/json-schema/JSON-Schema-Test-Suite.png?branch=develop)](https://travis-ci.org/json-schema/JSON-Schema-Test-Suite)
1+JSON Schema Test Suite [![Build Status](https://travis-ci.org/json-schema-org/JSON-Schema-Test-Suite.svg?branch=master)](https://travis-ci.org/json-schema-org/JSON-Schema-Test-Suite)
22======================
33
44This repository contains a set of JSON objects that implementors of JSON Schema
@@ -64,10 +64,18 @@ This suite is being used by:
6464
6565* [jsck](https://github.com/pandastrike/jsck)
6666
67+### C++ ###
68+
69+* [Modern C++ JSON schema validator](https://github.com/pboettch/json-schema-validator)
70+
6771### Dart ###
6872
6973* [json_schema](https://github.com/patefacio/json_schema)
7074
75+### Elixir ###
76+
77+* [ex_json_schema](https://github.com/jonasschmidt/ex_json_schema)
78+
7179### Erlang ###
7280
7381* [jesse](https://github.com/klarna/jesse)
@@ -84,7 +92,9 @@ This suite is being used by:
8492
8593### Java ###
8694
87−* [json-schema-validator](https://github.com/fge/json-schema-validator)
95+* [json-schema-validator](https://github.com/daveclayton/json-schema-validator)
96+* [everit-org/json-schema](https://github.com/everit-org/json-schema)
97+* [networknt/json-schema-validator](https://github.com/networknt/json-schema-validator)
8898
8999### JavaScript ###
90100
@@ -102,22 +112,25 @@ This suite is being used by:
102112* [z-schema](https://github.com/zaggino/z-schema)
103113* [jsen](https://github.com/bugventure/jsen)
104114* [ajv](https://github.com/epoberezkin/ajv)
115+* [djv](https://github.com/korzio/djv)
105116
106117### Node.js ###
107118
108119The JSON Schema Test Suite is also available as an
109120[npm](https://www.npmjs.com/package/json-schema-test-suite) package.
110−Node-specific support is maintained on the [node branch](https://github.com/json-schema/JSON-Schema-Test-Suite/tree/node).
111−See [NODE-README.md](https://github.com/json-schema/JSON-Schema-Test-Suite/blob/node/NODE-README.md)
121+Node-specific support is maintained on the [node branch](https://github.com/json-schema-org/JSON-Schema-Test-Suite/tree/node).
122+See [NODE-README.md](https://github.com/json-schema-org/JSON-Schema-Test-Suite/blob/node/NODE-README.md)
112123for more information.
113124
114125### .NET ###
115126
116127* [Newtonsoft.Json.Schema](https://github.com/JamesNK/Newtonsoft.Json.Schema)
128+* [Manatee.Json](https://github.com/gregsdennis/Manatee.Json)
117129
118130### PHP ###
119131
120132* [json-schema](https://github.com/justinrainbow/json-schema)
133+* [json-guard](https://github.com/thephpleague/json-guard)
121134
122135### Python ###
123136
@@ -135,6 +148,14 @@ for more information.
135148
136149* [JSONSchema](https://github.com/kylef/JSONSchema.swift)
137150
151+### Clojure ###
152+
153+* [json-schema](https://github.com/tatut/json-schema)
154+
155+### PostgreSQL ###
156+
157+* [postgres-json-schema](https://github.com/gavinwahl/postgres-json-schema)
158+
138159If you use it as well, please fork and send a pull request adding yourself to
139160the list :).
140161
@@ -144,5 +165,5 @@ Contributing
144165If you see something missing or incorrect, a pull request is most welcome!
145166
146167There are some sanity checks in place for testing the test suite. You can run
147−them with `bin/jsonschema_suite check` or `tox`. They will be run automatically by
168+them with `bin/jsonschema_suite check && npm test` or `tox && npm test`. They will be run automatically by
148169[Travis CI](https://travis-ci.org/) as well.
JSON-Schema-Test-Suite/bin/jsonschema_suite+2−27
@@ -52,33 +52,8 @@ REMOTES = {
5252}
5353REMOTES_DIR = os.path.join(ROOT_DIR, "remotes")
5454
55−TESTSUITE_SCHEMA = {
56− "$schema": "http://json-schema.org/draft-03/schema#",
57− "type": "array",
58− "items": {
59− "type": "object",
60− "properties": {
61− "description": {"type": "string", "required": True},
62− "schema": {"required": True},
63− "tests": {
64− "type": "array",
65− "items": {
66− "type": "object",
67− "properties": {
68− "description": {"type": "string", "required": True},
69− "data": {"required": True},
70− "valid": {"type": "boolean", "required": True}
71− },
72− "additionalProperties": False
73− },
74− "minItems": 1
75− }
76− },
77− "additionalProperties": False,
78− "minItems": 1
79− }
80−}
81−
55+with open(os.path.join(ROOT_DIR, "test-schema.json")) as schema:
56+ TESTSUITE_SCHEMA = json.load(schema)
8257
8358def files(paths):
8459 for path in paths:
JSON-Schema-Test-Suite/index.jsnew file+32
@@ -0,0 +1,32 @@
1+'use strict';
2+
3+var Ajv = require('ajv');
4+var jsonSchemaTest = require('json-schema-test');
5+var assert = require('assert');
6+
7+var refs = {
8+ 'http://localhost:1234/integer.json': require('./remotes/integer.json'),
9+ 'http://localhost:1234/subSchemas.json': require('./remotes/subSchemas.json'),
10+ 'http://localhost:1234/folder/folderInteger.json': require('./remotes/folder/folderInteger.json'),
11+ 'http://localhost:1234/name.json': require('./remotes/name.json')
12+};
13+
14+runTest(4);
15+runTest(6);
16+
17+function runTest(draft) {
18+ var opts = {};
19+ if (draft == 4) opts.meta = false;
20+ var ajv = new Ajv(opts);
21+ ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-04.json'));
22+ if (draft == 4) ajv._opts.defaultMeta = 'http://json-schema.org/draft-04/schema#';
23+ for (var uri in refs) ajv.addSchema(refs[uri], uri);
24+
25+ jsonSchemaTest(ajv, {
26+ description: 'Test suite draft-0' + draft,
27+ suites: {tests: './tests/draft' + draft + '/{**/,}*.json'},
28+ skip: draft == 4 ? ['optional/zeroTerminatedFloats'] : [],
29+ cwd: __dirname,
30+ hideFolder: 'tests/'
31+ });
32+}
JSON-Schema-Test-Suite/package.jsonnew file+28
@@ -0,0 +1,28 @@
1+{
2+ "name": "json-schema-test-suite",
3+ "version": "0.1.0",
4+ "description": "A language agnostic test suite for the JSON Schema specifications",
5+ "main": "index.js",
6+ "scripts": {
7+ "test": "mocha index.js -R spec"
8+ },
9+ "repository": {
10+ "type": "git",
11+ "url": "git+https://github.com/json-schema-org/JSON-Schema-Test-Suite.git"
12+ },
13+ "keywords": [
14+ "json-schema",
15+ "tests"
16+ ],
17+ "author": "http://json-schema.org",
18+ "license": "MIT",
19+ "bugs": {
20+ "url": "https://github.com/json-schema-org/JSON-Schema-Test-Suite/issues"
21+ },
22+ "homepage": "https://github.com/json-schema-org/JSON-Schema-Test-Suite#readme",
23+ "devDependencies": {
24+ "ajv": "^5.0.4-beta.0",
25+ "json-schema-test": "^1.3.0",
26+ "mocha": "^3.2.0"
27+ }
28+}
JSON-Schema-Test-Suite/remotes/name.jsonnew file+11
@@ -0,0 +1,11 @@
1+{
2+ "definitions": {
3+ "orNull": {
4+ "anyOf": [
5+ {"type": "null"},
6+ {"$ref": "#"}
7+ ]
8+ }
9+ },
10+ "type": "string"
11+}
JSON-Schema-Test-Suite/test-schema.jsonnew file+28
@@ -0,0 +1,28 @@
1+{
2+ "$schema": "http://json-schema.org/draft-04/schema#",
3+ "type": "array",
4+ "items": {
5+ "type": "object",
6+ "required": ["description", "schema", "tests"],
7+ "properties": {
8+ "description": {"type": "string"},
9+ "schema": {},
10+ "tests": {
11+ "type": "array",
12+ "items": {
13+ "type": "object",
14+ "required": ["description", "data", "valid"],
15+ "properties": {
16+ "description": {"type": "string"},
17+ "data": {},
18+ "valid": {"type": "boolean"}
19+ },
20+ "additionalProperties": false
21+ },
22+ "minItems": 1
23+ }
24+ },
25+ "additionalProperties": false,
26+ "minItems": 1
27+ }
28+}
JSON-Schema-Test-Suite/tests/draft3/optional/format.json+2−2
@@ -78,9 +78,9 @@
7878 "valid": true
7979 },
8080 {
81− "description": "a valid protocol-relative URI",
81+ "description": "an invalid protocol-relative URI Reference",
8282 "data": "//foo.bar/?baz=qux#quux",
83− "valid": true
83+ "valid": false
8484 },
8585 {
8686 "description": "an invalid URI",
JSON-Schema-Test-Suite/tests/draft3/ref.json+33
@@ -140,6 +140,39 @@
140140 }
141141 ]
142142 },
143+ {
144+ "description": "ref overrides any sibling keywords",
145+ "schema": {
146+ "definitions": {
147+ "reffed": {
148+ "type": "array"
149+ }
150+ },
151+ "properties": {
152+ "foo": {
153+ "$ref": "#/definitions/reffed",
154+ "maxItems": 2
155+ }
156+ }
157+ },
158+ "tests": [
159+ {
160+ "description": "remote ref valid",
161+ "data": { "foo": [] },
162+ "valid": true
163+ },
164+ {
165+ "description": "remote ref valid, maxItems ignored",
166+ "data": { "foo": [ 1, 2, 3] },
167+ "valid": true
168+ },
169+ {
170+ "description": "ref invalid",
171+ "data": { "foo": "string" },
172+ "valid": false
173+ }
174+ ]
175+ },
143176 {
144177 "description": "remote ref, containing refs itself",
145178 "schema": {"$ref": "http://json-schema.org/draft-03/schema#"},
JSON-Schema-Test-Suite/tests/draft3/type.json+15
@@ -18,6 +18,11 @@
1818 "data": "foo",
1919 "valid": false
2020 },
21+ {
22+ "description": "a string is still not an integer, even if it looks like one",
23+ "data": "1",
24+ "valid": false
25+ },
2126 {
2227 "description": "an object is not an integer",
2328 "data": {},
@@ -59,6 +64,11 @@
5964 "data": "foo",
6065 "valid": false
6166 },
67+ {
68+ "description": "a string is still not a number, even if it looks like one",
69+ "data": "1",
70+ "valid": false
71+ },
6272 {
6373 "description": "an object is not a number",
6474 "data": {},
@@ -100,6 +110,11 @@
100110 "data": "foo",
101111 "valid": true
102112 },
113+ {
114+ "description": "a string is still a string, even if it looks like a number",
115+ "data": "1",
116+ "valid": true
117+ },
103118 {
104119 "description": "an object is not a string",
105120 "data": {},
JSON-Schema-Test-Suite/tests/draft4/additionalItems.json+6−1
@@ -40,7 +40,12 @@
4040 },
4141 "tests": [
4242 {
43− "description": "no additional items present",
43+ "description": "fewer number of items present",
44+ "data": [ 1, 2 ],
45+ "valid": true
46+ },
47+ {
48+ "description": "equal number of items present",
4449 "data": [ 1, 2, 3 ],
4550 "valid": true
4651 },
JSON-Schema-Test-Suite/tests/draft4/items.json+32
@@ -19,6 +19,14 @@
1919 "description": "ignores non-arrays",
2020 "data": {"foo" : "bar"},
2121 "valid": true
22+ },
23+ {
24+ "description": "JavaScript pseudo-array is valid",
25+ "data": {
26+ "0": "invalid",
27+ "length": 1
28+ },
29+ "valid": true
2230 }
2331 ]
2432 },
@@ -40,6 +48,30 @@
4048 "description": "wrong types",
4149 "data": [ "foo", 1 ],
4250 "valid": false
51+ },
52+ {
53+ "description": "incomplete array of items",
54+ "data": [ 1 ],
55+ "valid": true
56+ },
57+ {
58+ "description": "array with additional items",
59+ "data": [ 1, "foo", true ],
60+ "valid": true
61+ },
62+ {
63+ "description": "empty array",
64+ "data": [ ],
65+ "valid": true
66+ },
67+ {
68+ "description": "JavaScript pseudo-array is valid",
69+ "data": {
70+ "0": "invalid",
71+ "1": "valid",
72+ "length": 2
73+ },
74+ "valid": true
4375 }
4476 ]
4577 }
JSON-Schema-Test-Suite/tests/draft4/maximum.json+5
@@ -8,6 +8,11 @@
88 "data": 2.6,
99 "valid": true
1010 },
11+ {
12+ "description": "boundary point is valid",
13+ "data": 3.0,
14+ "valid": true
15+ },
1116 {
1217 "description": "above the maximum is invalid",
1318 "data": 3.5,
JSON-Schema-Test-Suite/tests/draft4/minimum.json+5
@@ -8,6 +8,11 @@
88 "data": 2.6,
99 "valid": true
1010 },
11+ {
12+ "description": "boundary point is valid",
13+ "data": 1.1,
14+ "valid": true
15+ },
1116 {
1217 "description": "below the minimum is invalid",
1318 "data": 0.6,
JSON-Schema-Test-Suite/tests/draft4/optional/ecmascript-regex.jsonnew file+13
@@ -0,0 +1,13 @@
1+[
2+ {
3+ "description": "ECMA 262 regex non-compliance",
4+ "schema": { "format": "regex" },
5+ "tests": [
6+ {
7+ "description": "ECMA 262 has no support for \\Z anchor from .NET",
8+ "data": "^\\S(|(.|\\n)*\\S)\\Z",
9+ "valid": false
10+ }
11+ ]
12+ }
13+]
JSON-Schema-Test-Suite/tests/draft4/optional/format.json+2−2
@@ -30,9 +30,9 @@
3030 "valid": true
3131 },
3232 {
33− "description": "a valid protocol-relative URI",
33+ "description": "an invalid protocol-relative URI Reference",
3434 "data": "//foo.bar/?baz=qux#quux",
35− "valid": true
35+ "valid": false
3636 },
3737 {
3838 "description": "an invalid URI",
JSON-Schema-Test-Suite/tests/draft4/ref.json+139
@@ -140,6 +140,39 @@
140140 }
141141 ]
142142 },
143+ {
144+ "description": "ref overrides any sibling keywords",
145+ "schema": {
146+ "definitions": {
147+ "reffed": {
148+ "type": "array"
149+ }
150+ },
151+ "properties": {
152+ "foo": {
153+ "$ref": "#/definitions/reffed",
154+ "maxItems": 2
155+ }
156+ }
157+ },
158+ "tests": [
159+ {
160+ "description": "ref valid",
161+ "data": { "foo": [] },
162+ "valid": true
163+ },
164+ {
165+ "description": "ref valid, maxItems ignored",
166+ "data": { "foo": [ 1, 2, 3] },
167+ "valid": true
168+ },
169+ {
170+ "description": "ref invalid",
171+ "data": { "foo": "string" },
172+ "valid": false
173+ }
174+ ]
175+ },
143176 {
144177 "description": "remote ref, containing refs itself",
145178 "schema": {"$ref": "http://json-schema.org/draft-04/schema#"},
@@ -155,5 +188,111 @@
155188 "valid": false
156189 }
157190 ]
191+ },
192+ {
193+ "description": "property named $ref that is not a reference",
194+ "schema": {
195+ "properties": {
196+ "$ref": {"type": "string"}
197+ }
198+ },
199+ "tests": [
200+ {
201+ "description": "property named $ref valid",
202+ "data": {"$ref": "a"},
203+ "valid": true
204+ },
205+ {
206+ "description": "property named $ref invalid",
207+ "data": {"$ref": 2},
208+ "valid": false
209+ }
210+ ]
211+ },
212+ {
213+ "description": "Recursive references between schemas",
214+ "schema": {
215+ "description": "tree of nodes",
216+ "type": "object",
217+ "properties": {
218+ "meta": {"type": "string"},
219+ "nodes": {
220+ "type": "array",
221+ "items": {"$ref": "#/definitions/node"}
222+ }
223+ },
224+ "required": ["meta", "nodes"],
225+ "definitions": {
226+ "node": {
227+ "description": "node",
228+ "type": "object",
229+ "properties": {
230+ "value": {"type": "number"},
231+ "subtree": {"$ref": "#"}
232+ },
233+ "required": ["value"]
234+ }
235+ }
236+ },
237+ "tests": [
238+ {
239+ "description": "valid tree",
240+ "data": {
241+ "meta": "root",
242+ "nodes": [
243+ {
244+ "value": 1,
245+ "subtree": {
246+ "meta": "child",
247+ "nodes": [
248+ {"value": 1.1},
249+ {"value": 1.2}
250+ ]
251+ }
252+ },
253+ {
254+ "value": 2,
255+ "subtree": {
256+ "meta": "child",
257+ "nodes": [
258+ {"value": 2.1},
259+ {"value": 2.2}
260+ ]
261+ }
262+ }
263+ ]
264+ },
265+ "valid": true
266+ },
267+ {
268+ "description": "invalid tree",
269+ "data": {
270+ "meta": "root",
271+ "nodes": [
272+ {
273+ "value": 1,
274+ "subtree": {
275+ "meta": "child",
276+ "nodes": [
277+ {"value": "string is invalid"},
278+ {"value": 1.2}
279+ ]
280+ }
281+ },
282+ {
283+ "value": 2,
284+ "subtree": {
285+ "meta": "child",
286+ "nodes": [
287+ {"value": 2.1},
288+ {"value": 2.2}
289+ ]
290+ }
291+ }
292+ ]
293+ },
294+ "valid": false
295+ }
296+ ]
158297 }
159298]
JSON-Schema-Test-Suite/tests/draft4/refRemote.json+100−3
@@ -50,7 +50,7 @@
5050 ]
5151 },
5252 {
53− "description": "change resolution scope",
53+ "description": "base URI change",
5454 "schema": {
5555 "id": "http://localhost:1234/",
5656 "items": {
@@ -60,15 +60,112 @@
6060 },
6161 "tests": [
6262 {
63− "description": "changed scope ref valid",
63+ "description": "base URI change ref valid",
6464 "data": [[1]],
6565 "valid": true
6666 },
6767 {
68− "description": "changed scope ref invalid",
68+ "description": "base URI change ref invalid",
6969 "data": [["a"]],
7070 "valid": false
7171 }
7272 ]
73+ },
74+ {
75+ "description": "base URI change - change folder",
76+ "schema": {
77+ "id": "http://localhost:1234/scope_change_defs1.json",
78+ "type" : "object",
79+ "properties": {
80+ "list": {"$ref": "#/definitions/baz"}
81+ },
82+ "definitions": {
83+ "baz": {
84+ "id": "folder/",
85+ "type": "array",
86+ "items": {"$ref": "folderInteger.json"}
87+ }
88+ }
89+ },
90+ "tests": [
91+ {
92+ "description": "number is valid",
93+ "data": {"list": [1]},
94+ "valid": true
95+ },
96+ {
97+ "description": "string is invalid",
98+ "data": {"list": ["a"]},
99+ "valid": false
100+ }
101+ ]
102+ },
103+ {
104+ "description": "base URI change - change folder in subschema",
105+ "schema": {
106+ "id": "http://localhost:1234/scope_change_defs2.json",
107+ "type" : "object",
108+ "properties": {
109+ "list": {"$ref": "#/definitions/baz/definitions/bar"}
110+ },
111+ "definitions": {
112+ "baz": {
113+ "id": "folder/",
114+ "definitions": {
115+ "bar": {
116+ "type": "array",
117+ "items": {"$ref": "folderInteger.json"}
118+ }
119+ }
120+ }
121+ }
122+ },
123+ "tests": [
124+ {
125+ "description": "number is valid",
126+ "data": {"list": [1]},
127+ "valid": true
128+ },
129+ {
130+ "description": "string is invalid",
131+ "data": {"list": ["a"]},
132+ "valid": false
133+ }
134+ ]
135+ },
136+ {
137+ "description": "root ref in remote ref",
138+ "schema": {
139+ "id": "http://localhost:1234/object",
140+ "type": "object",
141+ "properties": {
142+ "name": {"$ref": "name.json#/definitions/orNull"}
143+ }
144+ },
145+ "tests": [
146+ {
147+ "description": "string is valid",
148+ "data": {
149+ "name": "foo"
150+ },
151+ "valid": true
152+ },
153+ {
154+ "description": "null is valid",
155+ "data": {
156+ "name": null
157+ },
158+ "valid": true
159+ },
160+ {
161+ "description": "object is invalid",
162+ "data": {
163+ "name": {
164+ "name": null
165+ }
166+ },
167+ "valid": false
168+ }
169+ ]
73170 }
74171]
JSON-Schema-Test-Suite/tests/draft4/required.json+5
@@ -18,6 +18,11 @@
1818 "description": "non-present required property is invalid",
1919 "data": {"bar": 1},
2020 "valid": false
21+ },
22+ {
23+ "description": "ignores non-objects",
24+ "data": 12,
25+ "valid": true
2126 }
2227 ]
2328 },
JSON-Schema-Test-Suite/tests/draft4/type.json+15
@@ -18,6 +18,11 @@
1818 "data": "foo",
1919 "valid": false
2020 },
21+ {
22+ "description": "a string is still not an integer, even if it looks like one",
23+ "data": "1",
24+ "valid": false
25+ },
2126 {
2227 "description": "an object is not an integer",
2328 "data": {},
@@ -59,6 +64,11 @@
5964 "data": "foo",
6065 "valid": false
6166 },
67+ {
68+ "description": "a string is still not a number, even if it looks like one",
69+ "data": "1",
70+ "valid": false
71+ },
6272 {
6373 "description": "an object is not a number",
6474 "data": {},
@@ -100,6 +110,11 @@
100110 "data": "foo",
101111 "valid": true
102112 },
113+ {
114+ "description": "a string is still a string, even if it looks like a number",
115+ "data": "1",
116+ "valid": true
117+ },
103118 {
104119 "description": "an object is not a string",
105120 "data": {},
JSON-Schema-Test-Suite/tests/draft6/additionalItems.jsonnew file+87
@@ -0,0 +1,87 @@
1+[
2+ {
3+ "description": "additionalItems as schema",
4+ "schema": {
5+ "items": [{}],
6+ "additionalItems": {"type": "integer"}
7+ },
8+ "tests": [
9+ {
10+ "description": "additional items match schema",
11+ "data": [ null, 2, 3, 4 ],
12+ "valid": true
13+ },
14+ {
15+ "description": "additional items do not match schema",
16+ "data": [ null, 2, 3, "foo" ],
17+ "valid": false
18+ }
19+ ]
20+ },
21+ {
22+ "description": "items is schema, no additionalItems",
23+ "schema": {
24+ "items": {},
25+ "additionalItems": false
26+ },
27+ "tests": [
28+ {
29+ "description": "all items match schema",
30+ "data": [ 1, 2, 3, 4, 5 ],
31+ "valid": true
32+ }
33+ ]
34+ },
35+ {
36+ "description": "array of items with no additionalItems",
37+ "schema": {
38+ "items": [{}, {}, {}],
39+ "additionalItems": false
40+ },
41+ "tests": [
42+ {
43+ "description": "fewer number of items present",
44+ "data": [ 1, 2 ],
45+ "valid": true
46+ },
47+ {
48+ "description": "equal number of items present",
49+ "data": [ 1, 2, 3 ],
50+ "valid": true
51+ },
52+ {
53+ "description": "additional items are not permitted",
54+ "data": [ 1, 2, 3, 4 ],
55+ "valid": false
56+ }
57+ ]
58+ },
59+ {
60+ "description": "additionalItems as false without items",
61+ "schema": {"additionalItems": false},
62+ "tests": [
63+ {
64+ "description":
65+ "items defaults to empty schema so everything is valid",
66+ "data": [ 1, 2, 3, 4, 5 ],
67+ "valid": true
68+ },
69+ {
70+ "description": "ignores non-arrays",
71+ "data": {"foo" : "bar"},
72+ "valid": true
73+ }
74+ ]
75+ },
76+ {
77+ "description": "additionalItems are allowed by default",
78+ "schema": {"items": [{"type": "integer"}]},
79+ "tests": [
80+ {
81+ "description": "only the first item is validated",
82+ "data": [1, "foo", false],
83+ "valid": true
84+ }
85+ ]
86+ }
87+]
JSON-Schema-Test-Suite/tests/draft6/additionalProperties.jsonnew file+88
@@ -0,0 +1,88 @@
1+[
2+ {
3+ "description":
4+ "additionalProperties being false does not allow other properties",
5+ "schema": {
6+ "properties": {"foo": {}, "bar": {}},
7+ "patternProperties": { "^v": {} },
8+ "additionalProperties": false
9+ },
10+ "tests": [
11+ {
12+ "description": "no additional properties is valid",
13+ "data": {"foo": 1},
14+ "valid": true
15+ },
16+ {
17+ "description": "an additional property is invalid",
18+ "data": {"foo" : 1, "bar" : 2, "quux" : "boom"},
19+ "valid": false
20+ },
21+ {
22+ "description": "ignores non-objects",
23+ "data": [1, 2, 3],
24+ "valid": true
25+ },
26+ {
27+ "description": "patternProperties are not additional properties",
28+ "data": {"foo":1, "vroom": 2},
29+ "valid": true
30+ }
31+ ]
32+ },
33+ {
34+ "description":
35+ "additionalProperties allows a schema which should validate",
36+ "schema": {
37+ "properties": {"foo": {}, "bar": {}},
38+ "additionalProperties": {"type": "boolean"}
39+ },
40+ "tests": [
41+ {
42+ "description": "no additional properties is valid",
43+ "data": {"foo": 1},
44+ "valid": true
45+ },
46+ {
47+ "description": "an additional valid property is valid",
48+ "data": {"foo" : 1, "bar" : 2, "quux" : true},
49+ "valid": true
50+ },
51+ {
52+ "description": "an additional invalid property is invalid",
53+ "data": {"foo" : 1, "bar" : 2, "quux" : 12},
54+ "valid": false
55+ }
56+ ]
57+ },
58+ {
59+ "description":
60+ "additionalProperties can exist by itself",
61+ "schema": {
62+ "additionalProperties": {"type": "boolean"}
63+ },
64+ "tests": [
65+ {
66+ "description": "an additional valid property is valid",
67+ "data": {"foo" : true},
68+ "valid": true
69+ },
70+ {
71+ "description": "an additional invalid property is invalid",
72+ "data": {"foo" : 1},
73+ "valid": false
74+ }
75+ ]
76+ },
77+ {
78+ "description": "additionalProperties are allowed by default",
79+ "schema": {"properties": {"foo": {}, "bar": {}}},
80+ "tests": [
81+ {
82+ "description": "additional properties are allowed",
83+ "data": {"foo": 1, "bar": 2, "quux": true},
84+ "valid": true
85+ }
86+ ]
87+ }
88+]
JSON-Schema-Test-Suite/tests/draft6/allOf.jsonnew file+145
@@ -0,0 +1,145 @@
1+[
2+ {
3+ "description": "allOf",
4+ "schema": {
5+ "allOf": [
6+ {
7+ "properties": {
8+ "bar": {"type": "integer"}
9+ },
10+ "required": ["bar"]
11+ },
12+ {
13+ "properties": {
14+ "foo": {"type": "string"}
15+ },
16+ "required": ["foo"]
17+ }
18+ ]
19+ },
20+ "tests": [
21+ {
22+ "description": "allOf",
23+ "data": {"foo": "baz", "bar": 2},
24+ "valid": true
25+ },
26+ {
27+ "description": "mismatch second",
28+ "data": {"foo": "baz"},
29+ "valid": false
30+ },
31+ {
32+ "description": "mismatch first",
33+ "data": {"bar": 2},
34+ "valid": false
35+ },
36+ {
37+ "description": "wrong type",
38+ "data": {"foo": "baz", "bar": "quux"},
39+ "valid": false
40+ }
41+ ]
42+ },
43+ {
44+ "description": "allOf with base schema",
45+ "schema": {
46+ "properties": {"bar": {"type": "integer"}},
47+ "required": ["bar"],
48+ "allOf" : [
49+ {
50+ "properties": {
51+ "foo": {"type": "string"}
52+ },
53+ "required": ["foo"]
54+ },
55+ {
56+ "properties": {
57+ "baz": {"type": "null"}
58+ },
59+ "required": ["baz"]
60+ }
61+ ]
62+ },
63+ "tests": [
64+ {
65+ "description": "valid",
66+ "data": {"foo": "quux", "bar": 2, "baz": null},
67+ "valid": true
68+ },
69+ {
70+ "description": "mismatch base schema",
71+ "data": {"foo": "quux", "baz": null},
72+ "valid": false
73+ },
74+ {
75+ "description": "mismatch first allOf",
76+ "data": {"bar": 2, "baz": null},
77+ "valid": false
78+ },
79+ {
80+ "description": "mismatch second allOf",
81+ "data": {"foo": "quux", "bar": 2},
82+ "valid": false
83+ },
84+ {
85+ "description": "mismatch both",
86+ "data": {"bar": 2},
87+ "valid": false
88+ }
89+ ]
90+ },
91+ {
92+ "description": "allOf simple types",
93+ "schema": {
94+ "allOf": [
95+ {"maximum": 30},
96+ {"minimum": 20}
97+ ]
98+ },
99+ "tests": [
100+ {
101+ "description": "valid",
102+ "data": 25,
103+ "valid": true
104+ },
105+ {
106+ "description": "mismatch one",
107+ "data": 35,
108+ "valid": false
109+ }
110+ ]
111+ },
112+ {
113+ "description": "allOf with boolean schemas, all true",
114+ "schema": {"allOf": [true, true]},
115+ "tests": [
116+ {
117+ "description": "any value is valid",
118+ "data": "foo",
119+ "valid": true
120+ }
121+ ]
122+ },
123+ {
124+ "description": "allOf with boolean schemas, some false",
125+ "schema": {"allOf": [true, false]},
126+ "tests": [
127+ {
128+ "description": "any value is invalid",
129+ "data": "foo",
130+ "valid": false
131+ }
132+ ]
133+ },
134+ {
135+ "description": "allOf with boolean schemas, all false",
136+ "schema": {"allOf": [false, false]},
137+ "tests": [
138+ {
139+ "description": "any value is invalid",
140+ "data": "foo",
141+ "valid": false
142+ }
143+ ]
144+ }
145+]
JSON-Schema-Test-Suite/tests/draft6/anyOf.jsonnew file+101
@@ -0,0 +1,101 @@
1+[
2+ {
3+ "description": "anyOf",
4+ "schema": {
5+ "anyOf": [
6+ {
7+ "type": "integer"
8+ },
9+ {
10+ "minimum": 2
11+ }
12+ ]
13+ },
14+ "tests": [
15+ {
16+ "description": "first anyOf valid",
17+ "data": 1,
18+ "valid": true
19+ },
20+ {
21+ "description": "second anyOf valid",
22+ "data": 2.5,
23+ "valid": true
24+ },
25+ {
26+ "description": "both anyOf valid",
27+ "data": 3,
28+ "valid": true
29+ },
30+ {
31+ "description": "neither anyOf valid",
32+ "data": 1.5,
33+ "valid": false
34+ }
35+ ]
36+ },
37+ {
38+ "description": "anyOf with base schema",
39+ "schema": {
40+ "type": "string",
41+ "anyOf" : [
42+ {
43+ "maxLength": 2
44+ },
45+ {
46+ "minLength": 4
47+ }
48+ ]
49+ },
50+ "tests": [
51+ {
52+ "description": "mismatch base schema",
53+ "data": 3,
54+ "valid": false
55+ },
56+ {
57+ "description": "one anyOf valid",
58+ "data": "foobar",
59+ "valid": true
60+ },
61+ {
62+ "description": "both anyOf invalid",
63+ "data": "foo",
64+ "valid": false
65+ }
66+ ]
67+ },
68+ {
69+ "description": "anyOf with boolean schemas, all true",
70+ "schema": {"anyOf": [true, true]},
71+ "tests": [
72+ {
73+ "description": "any value is valid",
74+ "data": "foo",
75+ "valid": true
76+ }
77+ ]
78+ },
79+ {
80+ "description": "anyOf with boolean schemas, some true",
81+ "schema": {"anyOf": [true, false]},
82+ "tests": [
83+ {
84+ "description": "any value is valid",
85+ "data": "foo",
86+ "valid": true
87+ }
88+ ]
89+ },
90+ {
91+ "description": "anyOf with boolean schemas, all false",
92+ "schema": {"anyOf": [false, false]},
93+ "tests": [
94+ {
95+ "description": "any value is invalid",
96+ "data": "foo",
97+ "valid": false
98+ }
99+ ]
100+ }
101+]
JSON-Schema-Test-Suite/tests/draft6/boolean_schema.jsonnew file+104
@@ -0,0 +1,104 @@
1+[
2+ {
3+ "description": "boolean schema 'true'",
4+ "schema": true,
5+ "tests": [
6+ {
7+ "description": "number is valid",
8+ "data": 1,
9+ "valid": true
10+ },
11+ {
12+ "description": "string is valid",
13+ "data": "foo",
14+ "valid": true
15+ },
16+ {
17+ "description": "boolean true is valid",
18+ "data": true,
19+ "valid": true
20+ },
21+ {
22+ "description": "boolean false is valid",
23+ "data": false,
24+ "valid": true
25+ },
26+ {
27+ "description": "null is valid",
28+ "data": null,
29+ "valid": true
30+ },
31+ {
32+ "description": "object is valid",
33+ "data": {"foo": "bar"},
34+ "valid": true
35+ },
36+ {
37+ "description": "empty object is valid",
38+ "data": {},
39+ "valid": true
40+ },
41+ {
42+ "description": "array is valid",
43+ "data": ["foo"],
44+ "valid": true
45+ },
46+ {
47+ "description": "empty array is valid",
48+ "data": [],
49+ "valid": true
50+ }
51+ ]
52+ },
53+ {
54+ "description": "boolean schema 'false'",
55+ "schema": false,
56+ "tests": [
57+ {
58+ "description": "number is invalid",
59+ "data": 1,
60+ "valid": false
61+ },
62+ {
63+ "description": "string is invalid",
64+ "data": "foo",
65+ "valid": false
66+ },
67+ {
68+ "description": "boolean true is invalid",
69+ "data": true,
70+ "valid": false
71+ },
72+ {
73+ "description": "boolean false is invalid",
74+ "data": false,
75+ "valid": false
76+ },
77+ {
78+ "description": "null is invalid",
79+ "data": null,
80+ "valid": false
81+ },
82+ {
83+ "description": "object is invalid",
84+ "data": {"foo": "bar"},
85+ "valid": false
86+ },
87+ {
88+ "description": "empty object is invalid",
89+ "data": {},
90+ "valid": false
91+ },
92+ {
93+ "description": "array is invalid",
94+ "data": ["foo"],
95+ "valid": false
96+ },
97+ {
98+ "description": "empty array is invalid",
99+ "data": [],
100+ "valid": false
101+ }
102+ ]
103+ }
104+]
JSON-Schema-Test-Suite/tests/draft6/const.jsonnew file+65
@@ -0,0 +1,65 @@
1+[
2+ {
3+ "description": "const validation",
4+ "schema": {"const": 2},
5+ "tests": [
6+ {
7+ "description": "same value is valid",
8+ "data": 2,
9+ "valid": true
10+ },
11+ {
12+ "description": "another value is invalid",
13+ "data": 5,
14+ "valid": false
15+ },
16+ {
17+ "description": "another type is invalid",
18+ "data": "a",
19+ "valid": false
20+ }
21+ ]
22+ },
23+ {
24+ "description": "const with object",
25+ "schema": {"const": {"foo": "bar", "baz": "bax"}},
26+ "tests": [
27+ {
28+ "description": "same object is valid",
29+ "data": {"foo": "bar", "baz": "bax"},
30+ "valid": true
31+ },
32+ {
33+ "description": "same object with different property order is valid",
34+ "data": {"baz": "bax", "foo": "bar"},
35+ "valid": true
36+ },
37+ {
38+ "description": "another object is invalid",
39+ "data": {"foo": "bar"},
40+ "valid": false
41+ },
42+ {
43+ "description": "another type is invalid",
44+ "data": [1, 2],
45+ "valid": false
46+ }
47+ ]
48+ },
49+ {
50+ "description": "const with null",
51+ "schema": {"const": null},
52+ "tests": [
53+ {
54+ "description": "null is valid",
55+ "data": null,
56+ "valid": true
57+ },
58+ {
59+ "description": "not null is invalid",
60+ "data": 0,
61+ "valid": false
62+ }
63+ ]
64+ }
65+]
JSON-Schema-Test-Suite/tests/draft6/contains.jsonnew file+95
@@ -0,0 +1,95 @@
1+[
2+ {
3+ "description": "contains keyword validation",
4+ "schema": {
5+ "contains": {"minimum": 5}
6+ },
7+ "tests": [
8+ {
9+ "description": "array with item matching schema (5) is valid",
10+ "data": [3, 4, 5],
11+ "valid": true
12+ },
13+ {
14+ "description": "array with item matching schema (6) is valid",
15+ "data": [3, 4, 6],
16+ "valid": true
17+ },
18+ {
19+ "description": "array with two items matching schema (5, 6) is valid",
20+ "data": [3, 4, 5, 6],
21+ "valid": true
22+ },
23+ {
24+ "description": "array without items matching schema is invalid",
25+ "data": [2, 3, 4],
26+ "valid": false
27+ },
28+ {
29+ "description": "empty array is invalid",
30+ "data": [],
31+ "valid": false
32+ },
33+ {
34+ "description": "not array is valid",
35+ "data": {},
36+ "valid": true
37+ }
38+ ]
39+ },
40+ {
41+ "description": "contains keyword with const keyword",
42+ "schema": {
43+ "contains": { "const": 5 }
44+ },
45+ "tests": [
46+ {
47+ "description": "array with item 5 is valid",
48+ "data": [3, 4, 5],
49+ "valid": true
50+ },
51+ {
52+ "description": "array with two items 5 is valid",
53+ "data": [3, 4, 5, 5],
54+ "valid": true
55+ },
56+ {
57+ "description": "array without item 5 is invalid",
58+ "data": [1, 2, 3, 4],
59+ "valid": false
60+ }
61+ ]
62+ },
63+ {
64+ "description": "contains keyword with boolean schema true",
65+ "schema": {"contains": true},
66+ "tests": [
67+ {
68+ "description": "any non-empty array is valid",
69+ "data": ["foo"],
70+ "valid": true
71+ },
72+ {
73+ "description": "empty array is invalid",
74+ "data": [],
75+ "valid": false
76+ }
77+ ]
78+ },
79+ {
80+ "description": "contains keyword with boolean schema false",
81+ "schema": {"contains": false},
82+ "tests": [
83+ {
84+ "description": "any non-empty array is invalid",
85+ "data": ["foo"],
86+ "valid": false
87+ },
88+ {
89+ "description": "empty array is invalid",
90+ "data": [],
91+ "valid": false
92+ }
93+ ]
94+ }
95+]
JSON-Schema-Test-Suite/tests/draft6/default.jsonnew file+49
@@ -0,0 +1,49 @@
1+[
2+ {
3+ "description": "invalid type for default",
4+ "schema": {
5+ "properties": {
6+ "foo": {
7+ "type": "integer",
8+ "default": []
9+ }
10+ }
11+ },
12+ "tests": [
13+ {
14+ "description": "valid when property is specified",
15+ "data": {"foo": 13},
16+ "valid": true
17+ },
18+ {
19+ "description": "still valid when the invalid default is used",
20+ "data": {},
21+ "valid": true
22+ }
23+ ]
24+ },
25+ {
26+ "description": "invalid string value for default",
27+ "schema": {
28+ "properties": {
29+ "bar": {
30+ "type": "string",
31+ "minLength": 4,
32+ "default": "bad"
33+ }
34+ }
35+ },
36+ "tests": [
37+ {
38+ "description": "valid when property is specified",
39+ "data": {"bar": "good"},
40+ "valid": true
41+ },
42+ {
43+ "description": "still valid when the invalid default is used",
44+ "data": {},
45+ "valid": true
46+ }
47+ ]
48+ }
49+]
JSON-Schema-Test-Suite/tests/draft6/definitions.jsonnew file+32
@@ -0,0 +1,32 @@
1+[
2+ {
3+ "description": "valid definition",
4+ "schema": {"$ref": "http://json-schema.org/draft-04/schema#"},
5+ "tests": [
6+ {
7+ "description": "valid definition schema",
8+ "data": {
9+ "definitions": {
10+ "foo": {"type": "integer"}
11+ }
12+ },
13+ "valid": true
14+ }
15+ ]
16+ },
17+ {
18+ "description": "invalid definition",
19+ "schema": {"$ref": "http://json-schema.org/draft-04/schema#"},
20+ "tests": [
21+ {
22+ "description": "invalid definition schema",
23+ "data": {
24+ "definitions": {
25+ "foo": {"type": 1}
26+ }
27+ },
28+ "valid": false
29+ }
30+ ]
31+ }
32+]
JSON-Schema-Test-Suite/tests/draft6/dependencies.jsonnew file+162
@@ -0,0 +1,162 @@
1+[
2+ {
3+ "description": "dependencies",
4+ "schema": {
5+ "dependencies": {"bar": ["foo"]}
6+ },
7+ "tests": [
8+ {
9+ "description": "neither",
10+ "data": {},
11+ "valid": true
12+ },
13+ {
14+ "description": "nondependant",
15+ "data": {"foo": 1},
16+ "valid": true
17+ },
18+ {
19+ "description": "with dependency",
20+ "data": {"foo": 1, "bar": 2},
21+ "valid": true
22+ },
23+ {
24+ "description": "missing dependency",
25+ "data": {"bar": 2},
26+ "valid": false
27+ },
28+ {
29+ "description": "ignores non-objects",
30+ "data": "foo",
31+ "valid": true
32+ }
33+ ]
34+ },
35+ {
36+ "description": "dependencies with empty array",
37+ "schema": {
38+ "dependencies": {"bar": []}
39+ },
40+ "tests": [
41+ {
42+ "description": "empty object",
43+ "data": {},
44+ "valid": true
45+ },
46+ {
47+ "description": "object with one property",
48+ "data": {"bar": 2},
49+ "valid": true
50+ }
51+ ]
52+ },
53+ {
54+ "description": "multiple dependencies",
55+ "schema": {
56+ "dependencies": {"quux": ["foo", "bar"]}
57+ },
58+ "tests": [
59+ {
60+ "description": "neither",
61+ "data": {},
62+ "valid": true
63+ },
64+ {
65+ "description": "nondependants",
66+ "data": {"foo": 1, "bar": 2},
67+ "valid": true
68+ },
69+ {
70+ "description": "with dependencies",
71+ "data": {"foo": 1, "bar": 2, "quux": 3},
72+ "valid": true
73+ },
74+ {
75+ "description": "missing dependency",
76+ "data": {"foo": 1, "quux": 2},
77+ "valid": false
78+ },
79+ {
80+ "description": "missing other dependency",
81+ "data": {"bar": 1, "quux": 2},
82+ "valid": false
83+ },
84+ {
85+ "description": "missing both dependencies",
86+ "data": {"quux": 1},
87+ "valid": false
88+ }
89+ ]
90+ },
91+ {
92+ "description": "multiple dependencies subschema",
93+ "schema": {
94+ "dependencies": {
95+ "bar": {
96+ "properties": {
97+ "foo": {"type": "integer"},
98+ "bar": {"type": "integer"}
99+ }
100+ }
101+ }
102+ },
103+ "tests": [
104+ {
105+ "description": "valid",
106+ "data": {"foo": 1, "bar": 2},
107+ "valid": true
108+ },
109+ {
110+ "description": "no dependency",
111+ "data": {"foo": "quux"},
112+ "valid": true
113+ },
114+ {
115+ "description": "wrong type",
116+ "data": {"foo": "quux", "bar": 2},
117+ "valid": false
118+ },
119+ {
120+ "description": "wrong type other",
121+ "data": {"foo": 2, "bar": "quux"},
122+ "valid": false
123+ },
124+ {
125+ "description": "wrong type both",
126+ "data": {"foo": "quux", "bar": "quux"},
127+ "valid": false
128+ }
129+ ]
130+ },
131+ {
132+ "description": "dependencies with boolean subschemas",
133+ "schema": {
134+ "dependencies": {
135+ "foo": true,
136+ "bar": false
137+ }
138+ },
139+ "tests": [
140+ {
141+ "description": "object with property having schema true is valid",
142+ "data": {"foo": 1},
143+ "valid": true
144+ },
145+ {
146+ "description": "object with property having schema false is invalid",
147+ "data": {"bar": 2},
148+ "valid": false
149+ },
150+ {
151+ "description": "object with both properties is invalid",
152+ "data": {"foo": 1, "bar": 2},
153+ "valid": false
154+ },
155+ {
156+ "description": "empty object is valid",
157+ "data": {},
158+ "valid": true
159+ }
160+ ]
161+ }
162+]
JSON-Schema-Test-Suite/tests/draft6/enum.jsonnew file+72
@@ -0,0 +1,72 @@
1+[
2+ {
3+ "description": "simple enum validation",
4+ "schema": {"enum": [1, 2, 3]},
5+ "tests": [
6+ {
7+ "description": "one of the enum is valid",
8+ "data": 1,
9+ "valid": true
10+ },
11+ {
12+ "description": "something else is invalid",
13+ "data": 4,
14+ "valid": false
15+ }
16+ ]
17+ },
18+ {
19+ "description": "heterogeneous enum validation",
20+ "schema": {"enum": [6, "foo", [], true, {"foo": 12}]},
21+ "tests": [
22+ {
23+ "description": "one of the enum is valid",
24+ "data": [],
25+ "valid": true
26+ },
27+ {
28+ "description": "something else is invalid",
29+ "data": null,
30+ "valid": false
31+ },
32+ {
33+ "description": "objects are deep compared",
34+ "data": {"foo": false},
35+ "valid": false
36+ }
37+ ]
38+ },
39+ {
40+ "description": "enums in properties",
41+ "schema": {
42+ "type":"object",
43+ "properties": {
44+ "foo": {"enum":["foo"]},
45+ "bar": {"enum":["bar"]}
46+ },
47+ "required": ["bar"]
48+ },
49+ "tests": [
50+ {
51+ "description": "both properties are valid",
52+ "data": {"foo":"foo", "bar":"bar"},
53+ "valid": true
54+ },
55+ {
56+ "description": "missing optional property is valid",
57+ "data": {"bar":"bar"},
58+ "valid": true
59+ },
60+ {
61+ "description": "missing required property is invalid",
62+ "data": {"foo":"foo"},
63+ "valid": false
64+ },
65+ {
66+ "description": "missing all properties is invalid",
67+ "data": {},
68+ "valid": false
69+ }
70+ ]
71+ }
72+]
JSON-Schema-Test-Suite/tests/draft6/exclusiveMaximum.jsonnew file+30
@@ -0,0 +1,30 @@
1+[
2+ {
3+ "description": "exclusiveMaximum validation",
4+ "schema": {
5+ "exclusiveMaximum": 3.0
6+ },
7+ "tests": [
8+ {
9+ "description": "below the exclusiveMaximum is valid",
10+ "data": 2.2,
11+ "valid": true
12+ },
13+ {
14+ "description": "boundary point is invalid",
15+ "data": 3.0,
16+ "valid": false
17+ },
18+ {
19+ "description": "above the exclusiveMaximum is invalid",
20+ "data": 3.5,
21+ "valid": false
22+ },
23+ {
24+ "description": "ignores non-numbers",
25+ "data": "x",
26+ "valid": true
27+ }
28+ ]
29+ }
30+]
JSON-Schema-Test-Suite/tests/draft6/exclusiveMinimum.jsonnew file+30
@@ -0,0 +1,30 @@
1+[
2+ {
3+ "description": "exclusiveMinimum validation",
4+ "schema": {
5+ "exclusiveMinimum": 1.1
6+ },
7+ "tests": [
8+ {
9+ "description": "above the exclusiveMinimum is valid",
10+ "data": 1.2,
11+ "valid": true
12+ },
13+ {
14+ "description": "boundary point is invalid",
15+ "data": 1.1,
16+ "valid": false
17+ },
18+ {
19+ "description": "below the exclusiveMinimum is invalid",
20+ "data": 0.6,
21+ "valid": false
22+ },
23+ {
24+ "description": "ignores non-numbers",
25+ "data": "x",
26+ "valid": true
27+ }
28+ ]
29+ }
30+]
JSON-Schema-Test-Suite/tests/draft6/items.jsonnew file+133
@@ -0,0 +1,133 @@
1+[
2+ {
3+ "description": "a schema given for items",
4+ "schema": {
5+ "items": {"type": "integer"}
6+ },
7+ "tests": [
8+ {
9+ "description": "valid items",
10+ "data": [ 1, 2, 3 ],
11+ "valid": true
12+ },
13+ {
14+ "description": "wrong type of items",
15+ "data": [1, "x"],
16+ "valid": false
17+ },
18+ {
19+ "description": "ignores non-arrays",
20+ "data": {"foo" : "bar"},
21+ "valid": true
22+ },
23+ {
24+ "description": "JavaScript pseudo-array is valid",
25+ "data": {
26+ "0": "invalid",
27+ "length": 1
28+ },
29+ "valid": true
30+ }
31+ ]
32+ },
33+ {
34+ "description": "an array of schemas for items",
35+ "schema": {
36+ "items": [
37+ {"type": "integer"},
38+ {"type": "string"}
39+ ]
40+ },
41+ "tests": [
42+ {
43+ "description": "correct types",
44+ "data": [ 1, "foo" ],
45+ "valid": true
46+ },
47+ {
48+ "description": "wrong types",
49+ "data": [ "foo", 1 ],
50+ "valid": false
51+ },
52+ {
53+ "description": "incomplete array of items",
54+ "data": [ 1 ],
55+ "valid": true
56+ },
57+ {
58+ "description": "array with additional items",
59+ "data": [ 1, "foo", true ],
60+ "valid": true
61+ },
62+ {
63+ "description": "empty array",
64+ "data": [ ],
65+ "valid": true
66+ },
67+ {
68+ "description": "JavaScript pseudo-array is valid",
69+ "data": {
70+ "0": "invalid",
71+ "1": "valid",
72+ "length": 2
73+ },
74+ "valid": true
75+ }
76+ ]
77+ },
78+ {
79+ "description": "items with boolean schema (true)",
80+ "schema": {"items": true},
81+ "tests": [
82+ {
83+ "description": "any array is valid",
84+ "data": [ 1, "foo", true ],
85+ "valid": true
86+ },
87+ {
88+ "description": "empty array is valid",
89+ "data": [],
90+ "valid": true
91+ }
92+ ]
93+ },
94+ {
95+ "description": "items with boolean schema (false)",
96+ "schema": {"items": false},
97+ "tests": [
98+ {
99+ "description": "any non-empty array is invalid",
100+ "data": [ 1, "foo", true ],
101+ "valid": false
102+ },
103+ {
104+ "description": "empty array is valid",
105+ "data": [],
106+ "valid": true
107+ }
108+ ]
109+ },
110+ {
111+ "description": "items with boolean schemas",
112+ "schema": {
113+ "items": [true, false]
114+ },
115+ "tests": [
116+ {
117+ "description": "array with one item is valid",
118+ "data": [ 1 ],
119+ "valid": true
120+ },
121+ {
122+ "description": "array with two items is invalid",
123+ "data": [ 1, "foo" ],
124+ "valid": false
125+ },
126+ {
127+ "description": "empty array is valid",
128+ "data": [],
129+ "valid": true
130+ }
131+ ]
132+ }
133+]
JSON-Schema-Test-Suite/tests/draft6/maxItems.jsonnew file+28
@@ -0,0 +1,28 @@
1+[
2+ {
3+ "description": "maxItems validation",
4+ "schema": {"maxItems": 2},
5+ "tests": [
6+ {
7+ "description": "shorter is valid",
8+ "data": [1],
9+ "valid": true
10+ },
11+ {
12+ "description": "exact length is valid",
13+ "data": [1, 2],
14+ "valid": true
15+ },
16+ {
17+ "description": "too long is invalid",
18+ "data": [1, 2, 3],
19+ "valid": false
20+ },
21+ {
22+ "description": "ignores non-arrays",
23+ "data": "foobar",
24+ "valid": true
25+ }
26+ ]
27+ }
28+]
JSON-Schema-Test-Suite/tests/draft6/maxLength.jsonnew file+33
@@ -0,0 +1,33 @@
1+[
2+ {
3+ "description": "maxLength validation",
4+ "schema": {"maxLength": 2},
5+ "tests": [
6+ {
7+ "description": "shorter is valid",
8+ "data": "f",
9+ "valid": true
10+ },
11+ {
12+ "description": "exact length is valid",
13+ "data": "fo",
14+ "valid": true
15+ },
16+ {
17+ "description": "too long is invalid",
18+ "data": "foo",
19+ "valid": false
20+ },
21+ {
22+ "description": "ignores non-strings",
23+ "data": 100,
24+ "valid": true
25+ },
26+ {
27+ "description": "two supplementary Unicode code points is long enough",
28+ "data": "\uD83D\uDCA9\uD83D\uDCA9",
29+ "valid": true
30+ }
31+ ]
32+ }
33+]
JSON-Schema-Test-Suite/tests/draft6/maxProperties.jsonnew file+28
@@ -0,0 +1,28 @@
1+[
2+ {
3+ "description": "maxProperties validation",
4+ "schema": {"maxProperties": 2},
5+ "tests": [
6+ {
7+ "description": "shorter is valid",
8+ "data": {"foo": 1},
9+ "valid": true
10+ },
11+ {
12+ "description": "exact length is valid",
13+ "data": {"foo": 1, "bar": 2},
14+ "valid": true
15+ },
16+ {
17+ "description": "too long is invalid",
18+ "data": {"foo": 1, "bar": 2, "baz": 3},
19+ "valid": false
20+ },
21+ {
22+ "description": "ignores non-objects",
23+ "data": "foobar",
24+ "valid": true
25+ }
26+ ]
27+ }
28+]
JSON-Schema-Test-Suite/tests/draft6/maximum.jsonnew file+28
@@ -0,0 +1,28 @@
1+[
2+ {
3+ "description": "maximum validation",
4+ "schema": {"maximum": 3.0},
5+ "tests": [
6+ {
7+ "description": "below the maximum is valid",
8+ "data": 2.6,
9+ "valid": true
10+ },
11+ {
12+ "description": "boundary point is valid",
13+ "data": 3.0,
14+ "valid": true
15+ },
16+ {
17+ "description": "above the maximum is invalid",
18+ "data": 3.5,
19+ "valid": false
20+ },
21+ {
22+ "description": "ignores non-numbers",
23+ "data": "x",
24+ "valid": true
25+ }
26+ ]
27+ }
28+]
JSON-Schema-Test-Suite/tests/draft6/minItems.jsonnew file+28
@@ -0,0 +1,28 @@
1+[
2+ {
3+ "description": "minItems validation",
4+ "schema": {"minItems": 1},
5+ "tests": [
6+ {
7+ "description": "longer is valid",
8+ "data": [1, 2],
9+ "valid": true
10+ },
11+ {
12+ "description": "exact length is valid",
13+ "data": [1],
14+ "valid": true
15+ },
16+ {
17+ "description": "too short is invalid",
18+ "data": [],
19+ "valid": false
20+ },
21+ {
22+ "description": "ignores non-arrays",
23+ "data": "",
24+ "valid": true
25+ }
26+ ]
27+ }
28+]
JSON-Schema-Test-Suite/tests/draft6/minLength.jsonnew file+33
@@ -0,0 +1,33 @@
1+[
2+ {
3+ "description": "minLength validation",
4+ "schema": {"minLength": 2},
5+ "tests": [
6+ {
7+ "description": "longer is valid",
8+ "data": "foo",
9+ "valid": true
10+ },
11+ {
12+ "description": "exact length is valid",
13+ "data": "fo",
14+ "valid": true
15+ },
16+ {
17+ "description": "too short is invalid",
18+ "data": "f",
19+ "valid": false
20+ },
21+ {
22+ "description": "ignores non-strings",
23+ "data": 1,
24+ "valid": true
25+ },
26+ {
27+ "description": "one supplementary Unicode code point is not long enough",
28+ "data": "\uD83D\uDCA9",
29+ "valid": false
30+ }
31+ ]
32+ }
33+]
JSON-Schema-Test-Suite/tests/draft6/minProperties.jsonnew file+28
@@ -0,0 +1,28 @@
1+[
2+ {
3+ "description": "minProperties validation",
4+ "schema": {"minProperties": 1},
5+ "tests": [
6+ {
7+ "description": "longer is valid",
8+ "data": {"foo": 1, "bar": 2},
9+ "valid": true
10+ },
11+ {
12+ "description": "exact length is valid",
13+ "data": {"foo": 1},
14+ "valid": true
15+ },
16+ {
17+ "description": "too short is invalid",
18+ "data": {},
19+ "valid": false
20+ },
21+ {
22+ "description": "ignores non-objects",
23+ "data": "",
24+ "valid": true
25+ }
26+ ]
27+ }
28+]
JSON-Schema-Test-Suite/tests/draft6/minimum.jsonnew file+28
@@ -0,0 +1,28 @@
1+[
2+ {
3+ "description": "minimum validation",
4+ "schema": {"minimum": 1.1},
5+ "tests": [
6+ {
7+ "description": "above the minimum is valid",
8+ "data": 2.6,
9+ "valid": true
10+ },
11+ {
12+ "description": "boundary point is valid",
13+ "data": 1.1,
14+ "valid": true
15+ },
16+ {
17+ "description": "below the minimum is invalid",
18+ "data": 0.6,
19+ "valid": false
20+ },
21+ {
22+ "description": "ignores non-numbers",
23+ "data": "x",
24+ "valid": true
25+ }
26+ ]
27+ }
28+]
JSON-Schema-Test-Suite/tests/draft6/multipleOf.jsonnew file+60
@@ -0,0 +1,60 @@
1+[
2+ {
3+ "description": "by int",
4+ "schema": {"multipleOf": 2},
5+ "tests": [
6+ {
7+ "description": "int by int",
8+ "data": 10,
9+ "valid": true
10+ },
11+ {
12+ "description": "int by int fail",
13+ "data": 7,
14+ "valid": false
15+ },
16+ {
17+ "description": "ignores non-numbers",
18+ "data": "foo",
19+ "valid": true
20+ }
21+ ]
22+ },
23+ {
24+ "description": "by number",
25+ "schema": {"multipleOf": 1.5},
26+ "tests": [
27+ {
28+ "description": "zero is multiple of anything",
29+ "data": 0,
30+ "valid": true
31+ },
32+ {
33+ "description": "4.5 is multiple of 1.5",
34+ "data": 4.5,
35+ "valid": true
36+ },
37+ {
38+ "description": "35 is not multiple of 1.5",
39+ "data": 35,
40+ "valid": false
41+ }
42+ ]
43+ },
44+ {
45+ "description": "by small number",
46+ "schema": {"multipleOf": 0.0001},
47+ "tests": [
48+ {
49+ "description": "0.0075 is multiple of 0.0001",
50+ "data": 0.0075,
51+ "valid": true
52+ },
53+ {
54+ "description": "0.00751 is not multiple of 0.0001",
55+ "data": 0.00751,
56+ "valid": false
57+ }
58+ ]
59+ }
60+]
JSON-Schema-Test-Suite/tests/draft6/not.jsonnew file+117
@@ -0,0 +1,117 @@
1+[
2+ {
3+ "description": "not",
4+ "schema": {
5+ "not": {"type": "integer"}
6+ },
7+ "tests": [
8+ {
9+ "description": "allowed",
10+ "data": "foo",
11+ "valid": true
12+ },
13+ {
14+ "description": "disallowed",
15+ "data": 1,
16+ "valid": false
17+ }
18+ ]
19+ },
20+ {
21+ "description": "not multiple types",
22+ "schema": {
23+ "not": {"type": ["integer", "boolean"]}
24+ },
25+ "tests": [
26+ {
27+ "description": "valid",
28+ "data": "foo",
29+ "valid": true
30+ },
31+ {
32+ "description": "mismatch",
33+ "data": 1,
34+ "valid": false
35+ },
36+ {
37+ "description": "other mismatch",
38+ "data": true,
39+ "valid": false
40+ }
41+ ]
42+ },
43+ {
44+ "description": "not more complex schema",
45+ "schema": {
46+ "not": {
47+ "type": "object",
48+ "properties": {
49+ "foo": {
50+ "type": "string"
51+ }
52+ }
53+ }
54+ },
55+ "tests": [
56+ {
57+ "description": "match",
58+ "data": 1,
59+ "valid": true
60+ },
61+ {
62+ "description": "other match",
63+ "data": {"foo": 1},
64+ "valid": true
65+ },
66+ {
67+ "description": "mismatch",
68+ "data": {"foo": "bar"},
69+ "valid": false
70+ }
71+ ]
72+ },
73+ {
74+ "description": "forbidden property",
75+ "schema": {
76+ "properties": {
77+ "foo": {
78+ "not": {}
79+ }
80+ }
81+ },
82+ "tests": [
83+ {
84+ "description": "property present",
85+ "data": {"foo": 1, "bar": 2},
86+ "valid": false
87+ },
88+ {
89+ "description": "property absent",
90+ "data": {"bar": 1, "baz": 2},
91+ "valid": true
92+ }
93+ ]
94+ },
95+ {
96+ "description": "not with boolean schema true",
97+ "schema": {"not": true},
98+ "tests": [
99+ {
100+ "description": "any value is invalid",
101+ "data": "foo",
102+ "valid": false
103+ }
104+ ]
105+ },
106+ {
107+ "description": "not with boolean schema false",
108+ "schema": {"not": false},
109+ "tests": [
110+ {
111+ "description": "any value is valid",
112+ "data": "foo",
113+ "valid": true
114+ }
115+ ]
116+ }
117+]
JSON-Schema-Test-Suite/tests/draft6/oneOf.jsonnew file+112
@@ -0,0 +1,112 @@
1+[
2+ {
3+ "description": "oneOf",
4+ "schema": {
5+ "oneOf": [
6+ {
7+ "type": "integer"
8+ },
9+ {
10+ "minimum": 2
11+ }
12+ ]
13+ },
14+ "tests": [
15+ {
16+ "description": "first oneOf valid",
17+ "data": 1,
18+ "valid": true
19+ },
20+ {
21+ "description": "second oneOf valid",
22+ "data": 2.5,
23+ "valid": true
24+ },
25+ {
26+ "description": "both oneOf valid",
27+ "data": 3,
28+ "valid": false
29+ },
30+ {
31+ "description": "neither oneOf valid",
32+ "data": 1.5,
33+ "valid": false
34+ }
35+ ]
36+ },
37+ {
38+ "description": "oneOf with base schema",
39+ "schema": {
40+ "type": "string",
41+ "oneOf" : [
42+ {
43+ "minLength": 2
44+ },
45+ {
46+ "maxLength": 4
47+ }
48+ ]
49+ },
50+ "tests": [
51+ {
52+ "description": "mismatch base schema",
53+ "data": 3,
54+ "valid": false
55+ },
56+ {
57+ "description": "one oneOf valid",
58+ "data": "foobar",
59+ "valid": true
60+ },
61+ {
62+ "description": "both oneOf valid",
63+ "data": "foo",
64+ "valid": false
65+ }
66+ ]
67+ },
68+ {
69+ "description": "oneOf with boolean schemas, all true",
70+ "schema": {"oneOf": [true, true, true]},
71+ "tests": [
72+ {
73+ "description": "any value is invalid",
74+ "data": "foo",
75+ "valid": false
76+ }
77+ ]
78+ },
79+ {
80+ "description": "oneOf with boolean schemas, one true",
81+ "schema": {"oneOf": [true, false, false]},
82+ "tests": [
83+ {
84+ "description": "any value is valid",
85+ "data": "foo",
86+ "valid": true
87+ }
88+ ]
89+ },
90+ {
91+ "description": "oneOf with boolean schemas, more than one true",
92+ "schema": {"oneOf": [true, true, false]},
93+ "tests": [
94+ {
95+ "description": "any value is invalid",
96+ "data": "foo",
97+ "valid": false
98+ }
99+ ]
100+ },
101+ {
102+ "description": "oneOf with boolean schemas, all false",
103+ "schema": {"oneOf": [false, false, false]},
104+ "tests": [
105+ {
106+ "description": "any value is invalid",
107+ "data": "foo",
108+ "valid": false
109+ }
110+ ]
111+ }
112+]
JSON-Schema-Test-Suite/tests/draft6/optional/bignum.jsonnew file+105
@@ -0,0 +1,105 @@
1+[
2+ {
3+ "description": "integer",
4+ "schema": {"type": "integer"},
5+ "tests": [
6+ {
7+ "description": "a bignum is an integer",
8+ "data": 12345678910111213141516171819202122232425262728293031,
9+ "valid": true
10+ }
11+ ]
12+ },
13+ {
14+ "description": "number",
15+ "schema": {"type": "number"},
16+ "tests": [
17+ {
18+ "description": "a bignum is a number",
19+ "data": 98249283749234923498293171823948729348710298301928331,
20+ "valid": true
21+ }
22+ ]
23+ },
24+ {
25+ "description": "integer",
26+ "schema": {"type": "integer"},
27+ "tests": [
28+ {
29+ "description": "a negative bignum is an integer",
30+ "data": -12345678910111213141516171819202122232425262728293031,
31+ "valid": true
32+ }
33+ ]
34+ },
35+ {
36+ "description": "number",
37+ "schema": {"type": "number"},
38+ "tests": [
39+ {
40+ "description": "a negative bignum is a number",
41+ "data": -98249283749234923498293171823948729348710298301928331,
42+ "valid": true
43+ }
44+ ]
45+ },
46+ {
47+ "description": "string",
48+ "schema": {"type": "string"},
49+ "tests": [
50+ {
51+ "description": "a bignum is not a string",
52+ "data": 98249283749234923498293171823948729348710298301928331,
53+ "valid": false
54+ }
55+ ]
56+ },
57+ {
58+ "description": "integer comparison",
59+ "schema": {"maximum": 18446744073709551615},
60+ "tests": [
61+ {
62+ "description": "comparison works for high numbers",
63+ "data": 18446744073709551600,
64+ "valid": true
65+ }
66+ ]
67+ },
68+ {
69+ "description": "float comparison with high precision",
70+ "schema": {
71+ "exclusiveMaximum": 972783798187987123879878123.18878137
72+ },
73+ "tests": [
74+ {
75+ "description": "comparison works for high numbers",
76+ "data": 972783798187987123879878123.188781371,
77+ "valid": false
78+ }
79+ ]
80+ },
81+ {
82+ "description": "integer comparison",
83+ "schema": {"minimum": -18446744073709551615},
84+ "tests": [
85+ {
86+ "description": "comparison works for very negative numbers",
87+ "data": -18446744073709551600,
88+ "valid": true
89+ }
90+ ]
91+ },
92+ {
93+ "description": "float comparison with high precision on negative numbers",
94+ "schema": {
95+ "exclusiveMinimum": -972783798187987123879878123.18878137
96+ },
97+ "tests": [
98+ {
99+ "description": "comparison works for very negative numbers",
100+ "data": -972783798187987123879878123.188781371,
101+ "valid": false
102+ }
103+ ]
104+ }
105+]
JSON-Schema-Test-Suite/tests/draft6/optional/ecmascript-regex.jsonnew file+13
@@ -0,0 +1,13 @@
1+[
2+ {
3+ "description": "ECMA 262 regex non-compliance",
4+ "schema": { "format": "regex" },
5+ "tests": [
6+ {
7+ "description": "ECMA 262 has no support for \\Z anchor from .NET",
8+ "data": "^\\S(|(.|\\n)*\\S)\\Z",
9+ "valid": false
10+ }
11+ ]
12+ }
13+]
JSON-Schema-Test-Suite/tests/draft6/optional/format.jsonnew file+148
@@ -0,0 +1,148 @@
1+[
2+ {
3+ "description": "validation of date-time strings",
4+ "schema": {"format": "date-time"},
5+ "tests": [
6+ {
7+ "description": "a valid date-time string",
8+ "data": "1963-06-19T08:30:06.283185Z",
9+ "valid": true
10+ },
11+ {
12+ "description": "an invalid date-time string",
13+ "data": "06/19/1963 08:30:06 PST",
14+ "valid": false
15+ },
16+ {
17+ "description": "only RFC3339 not all of ISO 8601 are valid",
18+ "data": "2013-350T01:01:01",
19+ "valid": false
20+ }
21+ ]
22+ },
23+ {
24+ "description": "validation of URIs",
25+ "schema": {"format": "uri"},
26+ "tests": [
27+ {
28+ "description": "a valid URI",
29+ "data": "http://foo.bar/?baz=qux#quux",
30+ "valid": true
31+ },
32+ {
33+ "description": "an invalid protocol-relative URI Reference",
34+ "data": "//foo.bar/?baz=qux#quux",
35+ "valid": false
36+ },
37+ {
38+ "description": "an invalid URI",
39+ "data": "\\\\WINDOWS\\fileshare",
40+ "valid": false
41+ },
42+ {
43+ "description": "an invalid URI though valid URI reference",
44+ "data": "abc",
45+ "valid": false
46+ }
47+ ]
48+ },
49+ {
50+ "description": "validation of e-mail addresses",
51+ "schema": {"format": "email"},
52+ "tests": [
53+ {
54+ "description": "a valid e-mail address",
55+ "data": "joe.bloggs@example.com",
56+ "valid": true
57+ },
58+ {
59+ "description": "an invalid e-mail address",
60+ "data": "2962",
61+ "valid": false
62+ }
63+ ]
64+ },
65+ {
66+ "description": "validation of IP addresses",
67+ "schema": {"format": "ipv4"},
68+ "tests": [
69+ {
70+ "description": "a valid IP address",
71+ "data": "192.168.0.1",
72+ "valid": true
73+ },
74+ {
75+ "description": "an IP address with too many components",
76+ "data": "127.0.0.0.1",
77+ "valid": false
78+ },
79+ {
80+ "description": "an IP address with out-of-range values",
81+ "data": "256.256.256.256",
82+ "valid": false
83+ },
84+ {
85+ "description": "an IP address without 4 components",
86+ "data": "127.0",
87+ "valid": false
88+ },
89+ {
90+ "description": "an IP address as an integer",
91+ "data": "0x7f000001",
92+ "valid": false
93+ }
94+ ]
95+ },
96+ {
97+ "description": "validation of IPv6 addresses",
98+ "schema": {"format": "ipv6"},
99+ "tests": [
100+ {
101+ "description": "a valid IPv6 address",
102+ "data": "::1",
103+ "valid": true
104+ },
105+ {
106+ "description": "an IPv6 address with out-of-range values",
107+ "data": "12345::",
108+ "valid": false
109+ },
110+ {
111+ "description": "an IPv6 address with too many components",
112+ "data": "1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1",
113+ "valid": false
114+ },
115+ {
116+ "description": "an IPv6 address containing illegal characters",
117+ "data": "::laptop",
118+ "valid": false
119+ }
120+ ]
121+ },
122+ {
123+ "description": "validation of host names",
124+ "schema": {"format": "hostname"},
125+ "tests": [
126+ {
127+ "description": "a valid host name",
128+ "data": "www.example.com",
129+ "valid": true
130+ },
131+ {
132+ "description": "a host name starting with an illegal character",
133+ "data": "-a-host-name-that-starts-with--",
134+ "valid": false
135+ },
136+ {
137+ "description": "a host name containing illegal characters",
138+ "data": "not_a_valid_host_name",
139+ "valid": false
140+ },
141+ {
142+ "description": "a host name with a component too long",
143+ "data": "a-vvvvvvvvvvvvvvvveeeeeeeeeeeeeeeerrrrrrrrrrrrrrrryyyyyyyyyyyyyyyy-long-host-name-component",
144+ "valid": false
145+ }
146+ ]
147+ }
148+]
JSON-Schema-Test-Suite/tests/draft6/optional/zeroTerminatedFloats.jsonnew file+15
@@ -0,0 +1,15 @@
1+[
2+ {
3+ "description": "some languages do not distinguish between different types of numeric value",
4+ "schema": {
5+ "type": "integer"
6+ },
7+ "tests": [
8+ {
9+ "description": "a float is not an integer even without fractional part",
10+ "data": 1.0,
11+ "valid": true
12+ }
13+ ]
14+ }
15+]
JSON-Schema-Test-Suite/tests/draft6/pattern.jsonnew file+34
@@ -0,0 +1,34 @@
1+[
2+ {
3+ "description": "pattern validation",
4+ "schema": {"pattern": "^a*$"},
5+ "tests": [
6+ {
7+ "description": "a matching pattern is valid",
8+ "data": "aaa",
9+ "valid": true
10+ },
11+ {
12+ "description": "a non-matching pattern is invalid",
13+ "data": "abc",
14+ "valid": false
15+ },
16+ {
17+ "description": "ignores non-strings",
18+ "data": true,
19+ "valid": true
20+ }
21+ ]
22+ },
23+ {
24+ "description": "pattern is not anchored",
25+ "schema": {"pattern": "a+"},
26+ "tests": [
27+ {
28+ "description": "matches a substring",
29+ "data": "xxaayy",
30+ "valid": true
31+ }
32+ ]
33+ }
34+]
JSON-Schema-Test-Suite/tests/draft6/patternProperties.jsonnew file+141
@@ -0,0 +1,141 @@
1+[
2+ {
3+ "description":
4+ "patternProperties validates properties matching a regex",
5+ "schema": {
6+ "patternProperties": {
7+ "f.*o": {"type": "integer"}
8+ }
9+ },
10+ "tests": [
11+ {
12+ "description": "a single valid match is valid",
13+ "data": {"foo": 1},
14+ "valid": true
15+ },
16+ {
17+ "description": "multiple valid matches is valid",
18+ "data": {"foo": 1, "foooooo" : 2},
19+ "valid": true
20+ },
21+ {
22+ "description": "a single invalid match is invalid",
23+ "data": {"foo": "bar", "fooooo": 2},
24+ "valid": false
25+ },
26+ {
27+ "description": "multiple invalid matches is invalid",
28+ "data": {"foo": "bar", "foooooo" : "baz"},
29+ "valid": false
30+ },
31+ {
32+ "description": "ignores non-objects",
33+ "data": 12,
34+ "valid": true
35+ }
36+ ]
37+ },
38+ {
39+ "description": "multiple simultaneous patternProperties are validated",
40+ "schema": {
41+ "patternProperties": {
42+ "a*": {"type": "integer"},
43+ "aaa*": {"maximum": 20}
44+ }
45+ },
46+ "tests": [
47+ {
48+ "description": "a single valid match is valid",
49+ "data": {"a": 21},
50+ "valid": true
51+ },
52+ {
53+ "description": "a simultaneous match is valid",
54+ "data": {"aaaa": 18},
55+ "valid": true
56+ },
57+ {
58+ "description": "multiple matches is valid",
59+ "data": {"a": 21, "aaaa": 18},
60+ "valid": true
61+ },
62+ {
63+ "description": "an invalid due to one is invalid",
64+ "data": {"a": "bar"},
65+ "valid": false
66+ },
67+ {
68+ "description": "an invalid due to the other is invalid",
69+ "data": {"aaaa": 31},
70+ "valid": false
71+ },
72+ {
73+ "description": "an invalid due to both is invalid",
74+ "data": {"aaa": "foo", "aaaa": 31},
75+ "valid": false
76+ }
77+ ]
78+ },
79+ {
80+ "description": "regexes are not anchored by default and are case sensitive",
81+ "schema": {
82+ "patternProperties": {
83+ "[0-9]{2,}": { "type": "boolean" },
84+ "X_": { "type": "string" }
85+ }
86+ },
87+ "tests": [
88+ {
89+ "description": "non recognized members are ignored",
90+ "data": { "answer 1": "42" },
91+ "valid": true
92+ },
93+ {
94+ "description": "recognized members are accounted for",
95+ "data": { "a31b": null },
96+ "valid": false
97+ },
98+ {
99+ "description": "regexes are case sensitive",
100+ "data": { "a_x_3": 3 },
101+ "valid": true
102+ },
103+ {
104+ "description": "regexes are case sensitive, 2",
105+ "data": { "a_X_3": 3 },
106+ "valid": false
107+ }
108+ ]
109+ },
110+ {
111+ "description": "patternProperties with boolean schemas",
112+ "schema": {
113+ "patternProperties": {
114+ "f.*": true,
115+ "b.*": false
116+ }
117+ },
118+ "tests": [
119+ {
120+ "description": "object with property matching schema true is valid",
121+ "data": {"foo": 1},
122+ "valid": true
123+ },
124+ {
125+ "description": "object with property matching schema false is invalid",
126+ "data": {"bar": 2},
127+ "valid": false
128+ },
129+ {
130+ "description": "object with both properties is invalid",
131+ "data": {"foo": 1, "bar": 2},
132+ "valid": false
133+ },
134+ {
135+ "description": "empty object is valid",
136+ "data": {},
137+ "valid": true
138+ }
139+ ]
140+ }
141+]
JSON-Schema-Test-Suite/tests/draft6/properties.jsonnew file+123
@@ -0,0 +1,123 @@
1+[
2+ {
3+ "description": "object properties validation",
4+ "schema": {
5+ "properties": {
6+ "foo": {"type": "integer"},
7+ "bar": {"type": "string"}
8+ }
9+ },
10+ "tests": [
11+ {
12+ "description": "both properties present and valid is valid",
13+ "data": {"foo": 1, "bar": "baz"},
14+ "valid": true
15+ },
16+ {
17+ "description": "one property invalid is invalid",
18+ "data": {"foo": 1, "bar": {}},
19+ "valid": false
20+ },
21+ {
22+ "description": "both properties invalid is invalid",
23+ "data": {"foo": [], "bar": {}},
24+ "valid": false
25+ },
26+ {
27+ "description": "doesn't invalidate other properties",
28+ "data": {"quux": []},
29+ "valid": true
30+ },
31+ {
32+ "description": "ignores non-objects",
33+ "data": [],
34+ "valid": true
35+ }
36+ ]
37+ },
38+ {
39+ "description":
40+ "properties, patternProperties, additionalProperties interaction",
41+ "schema": {
42+ "properties": {
43+ "foo": {"type": "array", "maxItems": 3},
44+ "bar": {"type": "array"}
45+ },
46+ "patternProperties": {"f.o": {"minItems": 2}},
47+ "additionalProperties": {"type": "integer"}
48+ },
49+ "tests": [
50+ {
51+ "description": "property validates property",
52+ "data": {"foo": [1, 2]},
53+ "valid": true
54+ },
55+ {
56+ "description": "property invalidates property",
57+ "data": {"foo": [1, 2, 3, 4]},
58+ "valid": false
59+ },
60+ {
61+ "description": "patternProperty invalidates property",
62+ "data": {"foo": []},
63+ "valid": false
64+ },
65+ {
66+ "description": "patternProperty validates nonproperty",
67+ "data": {"fxo": [1, 2]},
68+ "valid": true
69+ },
70+ {
71+ "description": "patternProperty invalidates nonproperty",
72+ "data": {"fxo": []},
73+ "valid": false
74+ },
75+ {
76+ "description": "additionalProperty ignores property",
77+ "data": {"bar": []},
78+ "valid": true
79+ },
80+ {
81+ "description": "additionalProperty validates others",
82+ "data": {"quux": 3},
83+ "valid": true
84+ },
85+ {
86+ "description": "additionalProperty invalidates others",
87+ "data": {"quux": "foo"},
88+ "valid": false
89+ }
90+ ]
91+ },
92+ {
93+ "description": "properties with boolean schema",
94+ "schema": {
95+ "properties": {
96+ "foo": true,
97+ "bar": false
98+ }
99+ },
100+ "tests": [
101+ {
102+ "description": "no property present is valid",
103+ "data": {},
104+ "valid": true
105+ },
106+ {
107+ "description": "only 'true' property present is valid",
108+ "data": {"foo": 1},
109+ "valid": true
110+ },
111+ {
112+ "description": "only 'false' property present is invalid",
113+ "data": {"bar": 2},
114+ "valid": false
115+ },
116+ {
117+ "description": "both properties present is invalid",
118+ "data": {"foo": 1, "bar": 2},
119+ "valid": false
120+ }
121+ ]
122+ }
123+]
JSON-Schema-Test-Suite/tests/draft6/propertyNames.jsonnew file+68
@@ -0,0 +1,68 @@
1+[
2+ {
3+ "description": "propertyNames validation",
4+ "schema": {
5+ "propertyNames": {"maxLength": 3}
6+ },
7+ "tests": [
8+ {
9+ "description": "all property names valid",
10+ "data": {
11+ "f": {},
12+ "foo": {}
13+ },
14+ "valid": true
15+ },
16+ {
17+ "description": "some property names invalid",
18+ "data": {
19+ "foo": {},
20+ "foobar": {}
21+ },
22+ "valid": false
23+ },
24+ {
25+ "description": "object without properties is valid",
26+ "data": {},
27+ "valid": true
28+ },
29+ {
30+ "description": "non-object is valid",
31+ "data": [],
32+ "valid": true
33+ }
34+ ]
35+ },
36+ {
37+ "description": "propertyNames with boolean schema true",
38+ "schema": {"propertyNames": true},
39+ "tests": [
40+ {
41+ "description": "object with any properties is valid",
42+ "data": {"foo": 1},
43+ "valid": true
44+ },
45+ {
46+ "description": "empty object is valid",
47+ "data": {},
48+ "valid": true
49+ }
50+ ]
51+ },
52+ {
53+ "description": "propertyNames with boolean schema false",
54+ "schema": {"propertyNames": false},
55+ "tests": [
56+ {
57+ "description": "object with any properties is invalid",
58+ "data": {"foo": 1},
59+ "valid": false
60+ },
61+ {
62+ "description": "empty object is valid",
63+ "data": {},
64+ "valid": true
65+ }
66+ ]
67+ }
68+]
JSON-Schema-Test-Suite/tests/draft6/ref.jsonnew file+332
@@ -0,0 +1,332 @@
1+[
2+ {
3+ "description": "root pointer ref",
4+ "schema": {
5+ "properties": {
6+ "foo": {"$ref": "#"}
7+ },
8+ "additionalProperties": false
9+ },
10+ "tests": [
11+ {
12+ "description": "match",
13+ "data": {"foo": false},
14+ "valid": true
15+ },
16+ {
17+ "description": "recursive match",
18+ "data": {"foo": {"foo": false}},
19+ "valid": true
20+ },
21+ {
22+ "description": "mismatch",
23+ "data": {"bar": false},
24+ "valid": false
25+ },
26+ {
27+ "description": "recursive mismatch",
28+ "data": {"foo": {"bar": false}},
29+ "valid": false
30+ }
31+ ]
32+ },
33+ {
34+ "description": "relative pointer ref to object",
35+ "schema": {
36+ "properties": {
37+ "foo": {"type": "integer"},
38+ "bar": {"$ref": "#/properties/foo"}
39+ }
40+ },
41+ "tests": [
42+ {
43+ "description": "match",
44+ "data": {"bar": 3},
45+ "valid": true
46+ },
47+ {
48+ "description": "mismatch",
49+ "data": {"bar": true},
50+ "valid": false
51+ }
52+ ]
53+ },
54+ {
55+ "description": "relative pointer ref to array",
56+ "schema": {
57+ "items": [
58+ {"type": "integer"},
59+ {"$ref": "#/items/0"}
60+ ]
61+ },
62+ "tests": [
63+ {
64+ "description": "match array",
65+ "data": [1, 2],
66+ "valid": true
67+ },
68+ {
69+ "description": "mismatch array",
70+ "data": [1, "foo"],
71+ "valid": false
72+ }
73+ ]
74+ },
75+ {
76+ "description": "escaped pointer ref",
77+ "schema": {
78+ "tilda~field": {"type": "integer"},
79+ "slash/field": {"type": "integer"},
80+ "percent%field": {"type": "integer"},
81+ "properties": {
82+ "tilda": {"$ref": "#/tilda~0field"},
83+ "slash": {"$ref": "#/slash~1field"},
84+ "percent": {"$ref": "#/percent%25field"}
85+ }
86+ },
87+ "tests": [
88+ {
89+ "description": "slash invalid",
90+ "data": {"slash": "aoeu"},
91+ "valid": false
92+ },
93+ {
94+ "description": "tilda invalid",
95+ "data": {"tilda": "aoeu"},
96+ "valid": false
97+ },
98+ {
99+ "description": "percent invalid",
100+ "data": {"percent": "aoeu"},
101+ "valid": false
102+ },
103+ {
104+ "description": "slash valid",
105+ "data": {"slash": 123},
106+ "valid": true
107+ },
108+ {
109+ "description": "tilda valid",
110+ "data": {"tilda": 123},
111+ "valid": true
112+ },
113+ {
114+ "description": "percent valid",
115+ "data": {"percent": 123},
116+ "valid": true
117+ }
118+ ]
119+ },
120+ {
121+ "description": "nested refs",
122+ "schema": {
123+ "definitions": {
124+ "a": {"type": "integer"},
125+ "b": {"$ref": "#/definitions/a"},
126+ "c": {"$ref": "#/definitions/b"}
127+ },
128+ "$ref": "#/definitions/c"
129+ },
130+ "tests": [
131+ {
132+ "description": "nested ref valid",
133+ "data": 5,
134+ "valid": true
135+ },
136+ {
137+ "description": "nested ref invalid",
138+ "data": "a",
139+ "valid": false
140+ }
141+ ]
142+ },
143+ {
144+ "description": "ref overrides any sibling keywords",
145+ "schema": {
146+ "definitions": {
147+ "reffed": {
148+ "type": "array"
149+ }
150+ },
151+ "properties": {
152+ "foo": {
153+ "$ref": "#/definitions/reffed",
154+ "maxItems": 2
155+ }
156+ }
157+ },
158+ "tests": [
159+ {
160+ "description": "ref valid",
161+ "data": { "foo": [] },
162+ "valid": true
163+ },
164+ {
165+ "description": "ref valid, maxItems ignored",
166+ "data": { "foo": [ 1, 2, 3] },
167+ "valid": true
168+ },
169+ {
170+ "description": "ref invalid",
171+ "data": { "foo": "string" },
172+ "valid": false
173+ }
174+ ]
175+ },
176+ {
177+ "description": "remote ref, containing refs itself",
178+ "schema": {"$ref": "http://json-schema.org/draft-04/schema#"},
179+ "tests": [
180+ {
181+ "description": "remote ref valid",
182+ "data": {"minLength": 1},
183+ "valid": true
184+ },
185+ {
186+ "description": "remote ref invalid",
187+ "data": {"minLength": -1},
188+ "valid": false
189+ }
190+ ]
191+ },
192+ {
193+ "description": "property named $ref that is not a reference",
194+ "schema": {
195+ "properties": {
196+ "$ref": {"type": "string"}
197+ }
198+ },
199+ "tests": [
200+ {
201+ "description": "property named $ref valid",
202+ "data": {"$ref": "a"},
203+ "valid": true
204+ },
205+ {
206+ "description": "property named $ref invalid",
207+ "data": {"$ref": 2},
208+ "valid": false
209+ }
210+ ]
211+ },
212+ {
213+ "description": "$ref to boolean schema true",
214+ "schema": {
215+ "$ref": "#/definitions/bool",
216+ "definitions": {
217+ "bool": true
218+ }
219+ },
220+ "tests": [
221+ {
222+ "description": "any value is valid",
223+ "data": "foo",
224+ "valid": true
225+ }
226+ ]
227+ },
228+ {
229+ "description": "$ref to boolean schema false",
230+ "schema": {
231+ "$ref": "#/definitions/bool",
232+ "definitions": {
233+ "bool": false
234+ }
235+ },
236+ "tests": [
237+ {
238+ "description": "any value is invalid",
239+ "data": "foo",
240+ "valid": false
241+ }
242+ ]
243+ },
244+ {
245+ "description": "Recursive references between schemas",
246+ "schema": {
247+ "$id": "http://localhost:1234/tree",
248+ "description": "tree of nodes",
249+ "type": "object",
250+ "properties": {
251+ "meta": {"type": "string"},
252+ "nodes": {
253+ "type": "array",
254+ "items": {"$ref": "node"}
255+ }
256+ },
257+ "required": ["meta", "nodes"],
258+ "definitions": {
259+ "node": {
260+ "$id": "http://localhost:1234/node",
261+ "description": "node",
262+ "type": "object",
263+ "properties": {
264+ "value": {"type": "number"},
265+ "subtree": {"$ref": "tree"}
266+ },
267+ "required": ["value"]
268+ }
269+ }
270+ },
271+ "tests": [
272+ {
273+ "description": "valid tree",
274+ "data": {
275+ "meta": "root",
276+ "nodes": [
277+ {
278+ "value": 1,
279+ "subtree": {
280+ "meta": "child",
281+ "nodes": [
282+ {"value": 1.1},
283+ {"value": 1.2}
284+ ]
285+ }
286+ },
287+ {
288+ "value": 2,
289+ "subtree": {
290+ "meta": "child",
291+ "nodes": [
292+ {"value": 2.1},
293+ {"value": 2.2}
294+ ]
295+ }
296+ }
297+ ]
298+ },
299+ "valid": true
300+ },
301+ {
302+ "description": "invalid tree",
303+ "data": {
304+ "meta": "root",
305+ "nodes": [
306+ {
307+ "value": 1,
308+ "subtree": {
309+ "meta": "child",
310+ "nodes": [
311+ {"value": "string is invalid"},
312+ {"value": 1.2}
313+ ]
314+ }
315+ },
316+ {
317+ "value": 2,
318+ "subtree": {
319+ "meta": "child",
320+ "nodes": [
321+ {"value": 2.1},
322+ {"value": 2.2}
323+ ]
324+ }
325+ }
326+ ]
327+ },
328+ "valid": false
329+ }
330+ ]
331+ }
332+]
JSON-Schema-Test-Suite/tests/draft6/refRemote.jsonnew file+171
@@ -0,0 +1,171 @@
1+[
2+ {
3+ "description": "remote ref",
4+ "schema": {"$ref": "http://localhost:1234/integer.json"},
5+ "tests": [
6+ {
7+ "description": "remote ref valid",
8+ "data": 1,
9+ "valid": true
10+ },
11+ {
12+ "description": "remote ref invalid",
13+ "data": "a",
14+ "valid": false
15+ }
16+ ]
17+ },
18+ {
19+ "description": "fragment within remote ref",
20+ "schema": {"$ref": "http://localhost:1234/subSchemas.json#/integer"},
21+ "tests": [
22+ {
23+ "description": "remote fragment valid",
24+ "data": 1,
25+ "valid": true
26+ },
27+ {
28+ "description": "remote fragment invalid",
29+ "data": "a",
30+ "valid": false
31+ }
32+ ]
33+ },
34+ {
35+ "description": "ref within remote ref",
36+ "schema": {
37+ "$ref": "http://localhost:1234/subSchemas.json#/refToInteger"
38+ },
39+ "tests": [
40+ {
41+ "description": "ref within ref valid",
42+ "data": 1,
43+ "valid": true
44+ },
45+ {
46+ "description": "ref within ref invalid",
47+ "data": "a",
48+ "valid": false
49+ }
50+ ]
51+ },
52+ {
53+ "description": "base URI change",
54+ "schema": {
55+ "$id": "http://localhost:1234/",
56+ "items": {
57+ "$id": "folder/",
58+ "items": {"$ref": "folderInteger.json"}
59+ }
60+ },
61+ "tests": [
62+ {
63+ "description": "base URI change ref valid",
64+ "data": [[1]],
65+ "valid": true
66+ },
67+ {
68+ "description": "base URI change ref invalid",
69+ "data": [["a"]],
70+ "valid": false
71+ }
72+ ]
73+ },
74+ {
75+ "description": "base URI change - change folder",
76+ "schema": {
77+ "$id": "http://localhost:1234/scope_change_defs1.json",
78+ "type" : "object",
79+ "properties": {
80+ "list": {"$ref": "#/definitions/baz"}
81+ },
82+ "definitions": {
83+ "baz": {
84+ "$id": "folder/",
85+ "type": "array",
86+ "items": {"$ref": "folderInteger.json"}
87+ }
88+ }
89+ },
90+ "tests": [
91+ {
92+ "description": "number is valid",
93+ "data": {"list": [1]},
94+ "valid": true
95+ },
96+ {
97+ "description": "string is invalid",
98+ "data": {"list": ["a"]},
99+ "valid": false
100+ }
101+ ]
102+ },
103+ {
104+ "description": "base URI change - change folder in subschema",
105+ "schema": {
106+ "$id": "http://localhost:1234/scope_change_defs2.json",
107+ "type" : "object",
108+ "properties": {
109+ "list": {"$ref": "#/definitions/baz/definitions/bar"}
110+ },
111+ "definitions": {
112+ "baz": {
113+ "$id": "folder/",
114+ "definitions": {
115+ "bar": {
116+ "type": "array",
117+ "items": {"$ref": "folderInteger.json"}
118+ }
119+ }
120+ }
121+ }
122+ },
123+ "tests": [
124+ {
125+ "description": "number is valid",
126+ "data": {"list": [1]},
127+ "valid": true
128+ },
129+ {
130+ "description": "string is invalid",
131+ "data": {"list": ["a"]},
132+ "valid": false
133+ }
134+ ]
135+ },
136+ {
137+ "description": "root ref in remote ref",
138+ "schema": {
139+ "$id": "http://localhost:1234/object",
140+ "type": "object",
141+ "properties": {
142+ "name": {"$ref": "name.json#/definitions/orNull"}
143+ }
144+ },
145+ "tests": [
146+ {
147+ "description": "string is valid",
148+ "data": {
149+ "name": "foo"
150+ },
151+ "valid": true
152+ },
153+ {
154+ "description": "null is valid",
155+ "data": {
156+ "name": null
157+ },
158+ "valid": true
159+ },
160+ {
161+ "description": "object is invalid",
162+ "data": {
163+ "name": {
164+ "name": null
165+ }
166+ },
167+ "valid": false
168+ }
169+ ]
170+ }
171+]
JSON-Schema-Test-Suite/tests/draft6/required.jsonnew file+60
@@ -0,0 +1,60 @@
1+[
2+ {
3+ "description": "required validation",
4+ "schema": {
5+ "properties": {
6+ "foo": {},
7+ "bar": {}
8+ },
9+ "required": ["foo"]
10+ },
11+ "tests": [
12+ {
13+ "description": "present required property is valid",
14+ "data": {"foo": 1},
15+ "valid": true
16+ },
17+ {
18+ "description": "non-present required property is invalid",
19+ "data": {"bar": 1},
20+ "valid": false
21+ },
22+ {
23+ "description": "ignores non-objects",
24+ "data": 12,
25+ "valid": true
26+ }
27+ ]
28+ },
29+ {
30+ "description": "required default validation",
31+ "schema": {
32+ "properties": {
33+ "foo": {}
34+ }
35+ },
36+ "tests": [
37+ {
38+ "description": "not required by default",
39+ "data": {},
40+ "valid": true
41+ }
42+ ]
43+ },
44+ {
45+ "description": "required with empty array",
46+ "schema": {
47+ "properties": {
48+ "foo": {}
49+ },
50+ "required": []
51+ },
52+ "tests": [
53+ {
54+ "description": "property not required",
55+ "data": {},
56+ "valid": true
57+ }
58+ ]
59+ }
60+]
JSON-Schema-Test-Suite/tests/draft6/type.jsonnew file+345
@@ -0,0 +1,345 @@
1+[
2+ {
3+ "description": "integer type matches integers",
4+ "schema": {"type": "integer"},
5+ "tests": [
6+ {
7+ "description": "an integer is an integer",
8+ "data": 1,
9+ "valid": true
10+ },
11+ {
12+ "description": "a float is not an integer",
13+ "data": 1.1,
14+ "valid": false
15+ },
16+ {
17+ "description": "a string is not an integer",
18+ "data": "foo",
19+ "valid": false
20+ },
21+ {
22+ "description": "a string is still not an integer, even if it looks like one",
23+ "data": "1",
24+ "valid": false
25+ },
26+ {
27+ "description": "an object is not an integer",
28+ "data": {},
29+ "valid": false
30+ },
31+ {
32+ "description": "an array is not an integer",
33+ "data": [],
34+ "valid": false
35+ },
36+ {
37+ "description": "a boolean is not an integer",
38+ "data": true,
39+ "valid": false
40+ },
41+ {
42+ "description": "null is not an integer",
43+ "data": null,
44+ "valid": false
45+ }
46+ ]
47+ },
48+ {
49+ "description": "number type matches numbers",
50+ "schema": {"type": "number"},
51+ "tests": [
52+ {
53+ "description": "an integer is a number",
54+ "data": 1,
55+ "valid": true
56+ },
57+ {
58+ "description": "a float is a number",
59+ "data": 1.1,
60+ "valid": true
61+ },
62+ {
63+ "description": "a string is not a number",
64+ "data": "foo",
65+ "valid": false
66+ },
67+ {
68+ "description": "a string is still not a number, even if it looks like one",
69+ "data": "1",
70+ "valid": false
71+ },
72+ {
73+ "description": "an object is not a number",
74+ "data": {},
75+ "valid": false
76+ },
77+ {
78+ "description": "an array is not a number",
79+ "data": [],
80+ "valid": false
81+ },
82+ {
83+ "description": "a boolean is not a number",
84+ "data": true,
85+ "valid": false
86+ },
87+ {
88+ "description": "null is not a number",
89+ "data": null,
90+ "valid": false
91+ }
92+ ]
93+ },
94+ {
95+ "description": "string type matches strings",
96+ "schema": {"type": "string"},
97+ "tests": [
98+ {
99+ "description": "1 is not a string",
100+ "data": 1,
101+ "valid": false
102+ },
103+ {
104+ "description": "a float is not a string",
105+ "data": 1.1,
106+ "valid": false
107+ },
108+ {
109+ "description": "a string is a string",
110+ "data": "foo",
111+ "valid": true
112+ },
113+ {
114+ "description": "a string is still a string, even if it looks like a number",
115+ "data": "1",
116+ "valid": true
117+ },
118+ {
119+ "description": "an object is not a string",
120+ "data": {},
121+ "valid": false
122+ },
123+ {
124+ "description": "an array is not a string",
125+ "data": [],
126+ "valid": false
127+ },
128+ {
129+ "description": "a boolean is not a string",
130+ "data": true,
131+ "valid": false
132+ },
133+ {
134+ "description": "null is not a string",
135+ "data": null,
136+ "valid": false
137+ }
138+ ]
139+ },
140+ {
141+ "description": "object type matches objects",
142+ "schema": {"type": "object"},
143+ "tests": [
144+ {
145+ "description": "an integer is not an object",
146+ "data": 1,
147+ "valid": false
148+ },
149+ {
150+ "description": "a float is not an object",
151+ "data": 1.1,
152+ "valid": false
153+ },
154+ {
155+ "description": "a string is not an object",
156+ "data": "foo",
157+ "valid": false
158+ },
159+ {
160+ "description": "an object is an object",
161+ "data": {},
162+ "valid": true
163+ },
164+ {
165+ "description": "an array is not an object",
166+ "data": [],
167+ "valid": false
168+ },
169+ {
170+ "description": "a boolean is not an object",
171+ "data": true,
172+ "valid": false
173+ },
174+ {
175+ "description": "null is not an object",
176+ "data": null,
177+ "valid": false
178+ }
179+ ]
180+ },
181+ {
182+ "description": "array type matches arrays",
183+ "schema": {"type": "array"},
184+ "tests": [
185+ {
186+ "description": "an integer is not an array",
187+ "data": 1,
188+ "valid": false
189+ },
190+ {
191+ "description": "a float is not an array",
192+ "data": 1.1,
193+ "valid": false
194+ },
195+ {
196+ "description": "a string is not an array",
197+ "data": "foo",
198+ "valid": false
199+ },
200+ {
201+ "description": "an object is not an array",
202+ "data": {},
203+ "valid": false
204+ },
205+ {
206+ "description": "an array is an array",
207+ "data": [],
208+ "valid": true
209+ },
210+ {
211+ "description": "a boolean is not an array",
212+ "data": true,
213+ "valid": false
214+ },
215+ {
216+ "description": "null is not an array",
217+ "data": null,
218+ "valid": false
219+ }
220+ ]
221+ },
222+ {
223+ "description": "boolean type matches booleans",
224+ "schema": {"type": "boolean"},
225+ "tests": [
226+ {
227+ "description": "an integer is not a boolean",
228+ "data": 1,
229+ "valid": false
230+ },
231+ {
232+ "description": "a float is not a boolean",
233+ "data": 1.1,
234+ "valid": false
235+ },
236+ {
237+ "description": "a string is not a boolean",
238+ "data": "foo",
239+ "valid": false
240+ },
241+ {
242+ "description": "an object is not a boolean",
243+ "data": {},
244+ "valid": false
245+ },
246+ {
247+ "description": "an array is not a boolean",
248+ "data": [],
249+ "valid": false
250+ },
251+ {
252+ "description": "a boolean is a boolean",
253+ "data": true,
254+ "valid": true
255+ },
256+ {
257+ "description": "null is not a boolean",
258+ "data": null,
259+ "valid": false
260+ }
261+ ]
262+ },
263+ {
264+ "description": "null type matches only the null object",
265+ "schema": {"type": "null"},
266+ "tests": [
267+ {
268+ "description": "an integer is not null",
269+ "data": 1,
270+ "valid": false
271+ },
272+ {
273+ "description": "a float is not null",
274+ "data": 1.1,
275+ "valid": false
276+ },
277+ {
278+ "description": "a string is not null",
279+ "data": "foo",
280+ "valid": false
281+ },
282+ {
283+ "description": "an object is not null",
284+ "data": {},
285+ "valid": false
286+ },
287+ {
288+ "description": "an array is not null",
289+ "data": [],
290+ "valid": false
291+ },
292+ {
293+ "description": "a boolean is not null",
294+ "data": true,
295+ "valid": false
296+ },
297+ {
298+ "description": "null is null",
299+ "data": null,
300+ "valid": true
301+ }
302+ ]
303+ },
304+ {
305+ "description": "multiple types can be specified in an array",
306+ "schema": {"type": ["integer", "string"]},
307+ "tests": [
308+ {
309+ "description": "an integer is valid",
310+ "data": 1,
311+ "valid": true
312+ },
313+ {
314+ "description": "a string is valid",
315+ "data": "foo",
316+ "valid": true
317+ },
318+ {
319+ "description": "a float is invalid",
320+ "data": 1.1,
321+ "valid": false
322+ },
323+ {
324+ "description": "an object is invalid",
325+ "data": {},
326+ "valid": false
327+ },
328+ {
329+ "description": "an array is invalid",
330+ "data": [],
331+ "valid": false
332+ },
333+ {
334+ "description": "a boolean is invalid",
335+ "data": true,
336+ "valid": false
337+ },
338+ {
339+ "description": "null is invalid",
340+ "data": null,
341+ "valid": false
342+ }
343+ ]
344+ }
345+]
JSON-Schema-Test-Suite/tests/draft6/uniqueItems.jsonnew file+79
@@ -0,0 +1,79 @@
1+[
2+ {
3+ "description": "uniqueItems validation",
4+ "schema": {"uniqueItems": true},
5+ "tests": [
6+ {
7+ "description": "unique array of integers is valid",
8+ "data": [1, 2],
9+ "valid": true
10+ },
11+ {
12+ "description": "non-unique array of integers is invalid",
13+ "data": [1, 1],
14+ "valid": false
15+ },
16+ {
17+ "description": "numbers are unique if mathematically unequal",
18+ "data": [1.0, 1.00, 1],
19+ "valid": false
20+ },
21+ {
22+ "description": "unique array of objects is valid",
23+ "data": [{"foo": "bar"}, {"foo": "baz"}],
24+ "valid": true
25+ },
26+ {
27+ "description": "non-unique array of objects is invalid",
28+ "data": [{"foo": "bar"}, {"foo": "bar"}],
29+ "valid": false
30+ },
31+ {
32+ "description": "unique array of nested objects is valid",
33+ "data": [
34+ {"foo": {"bar" : {"baz" : true}}},
35+ {"foo": {"bar" : {"baz" : false}}}
36+ ],
37+ "valid": true
38+ },
39+ {
40+ "description": "non-unique array of nested objects is invalid",
41+ "data": [
42+ {"foo": {"bar" : {"baz" : true}}},
43+ {"foo": {"bar" : {"baz" : true}}}
44+ ],
45+ "valid": false
46+ },
47+ {
48+ "description": "unique array of arrays is valid",
49+ "data": [["foo"], ["bar"]],
50+ "valid": true
51+ },
52+ {
53+ "description": "non-unique array of arrays is invalid",
54+ "data": [["foo"], ["foo"]],
55+ "valid": false
56+ },
57+ {
58+ "description": "1 and true are unique",
59+ "data": [1, true],
60+ "valid": true
61+ },
62+ {
63+ "description": "0 and false are unique",
64+ "data": [0, false],
65+ "valid": true
66+ },
67+ {
68+ "description": "unique heterogeneous types are valid",
69+ "data": [{}, [1], true, null, 1],
70+ "valid": true
71+ },
72+ {
73+ "description": "non-unique heterogeneous types are invalid",
74+ "data": [{}, [1], true, null, {}, 1],
75+ "valid": false
76+ }
77+ ]
78+ }
79+]
README.md+10−50
@@ -1,65 +1,25 @@
1−![hjsonschema logo](./logo.jpg)
1+# DEPRECATION NOTICE
22
3−A Haskell implementation of the most commonly used [JSON Schema](http://json-schema.org/) specification ([Draft 4](https://github.com/json-schema-org/json-schema-spec/wiki/Specification-Links#draft-4)).
3+`hjsonschema` was an attempt to build a very modular JSON Schema library. Validators have [a concrete type](src/JSONSchema/Validator/Types.hs) and can be mixed and matched into new [Specs](src/JSONSchema/Types.hs).
44
5−[Hackage](https://hackage.haskell.org/package/hjsonschema) / [GitHub](https://github.com/seagreen/hjsonschema) / [Travis CI](https://travis-ci.org/seagreen/hjsonschema)
6−
7−# Notes
5+However this flexibility came at the price of complicating the code. I don't think it was the right tradeoff, especially since situations where you'd want to change what validators make up a `Spec` at runtime seem rare.
86
9−+ As of 2017 [json-schema-org](https://github.com/json-schema-org/json-schema-spec) has begun releasing new drafts of the standard. Once this work stabilizes `hjsonschema` will add coverage for the latest draft.
7+Also, there are many parts of JSON Schema that `hjsonschema` doesn't implement properly (as you can see from the issue tracker). I'm hoping that a new JSON Schema library will come along that handles these correctly. In the meantime I'm happy to merge working fixes into here.
108
11−+ Requires [pcre](http://www.pcre.org/) (`pkgs.pcre` in Nixpkgs).
9+# Links
1210
13−+ Schemas with circular references can cause infinite loops. hjsonschema does loop detection but it may not be solid yet -- please open an issue if you find a situation where it fails.
11+[Hackage](https://hackage.haskell.org/package/hjsonschema) / [GitHub](https://github.com/seagreen/hjsonschema) / [Travis CI](https://travis-ci.org/seagreen/hjsonschema)
1412
1513# Example
1614
1715See [here](https://github.com/seagreen/hjsonschema/blob/master/examples/Simple.hs).
1816
19−# Tests
20−
21−Run all tests:
22−
23−`stack test`
24−
25−Run only local tests:
26−
27−`stack test hjsonschema:local`
28−
29−Run remote tests (makes GETs to json-schema.org, also temporarily starts an HTTP server on port 1234):
30−
31−`stack test hjsonschema:remote`
32−
33−# Details
34−
35−## Goals
17+# System dependencies
3618
37−+ Be a correct and fast implementation of the spec.
38−
39−+ Be a useful reference for implementers in other languages. Haskell's high level nature, expressive type system and referential transparency suit this purpose well.
40−
41−## Good Parts
42−
43−+ Passes all the required tests in the [language agnostic test suite](https://github.com/json-schema/JSON-Schema-Test-Suite).
44−
45−+ Very modular, which should make it easy to support future versions of the specification.
46−
47−## Bad Parts
48−
49−+ Uses the [pcre-heavy](https://hackage.haskell.org/package/pcre-heavy) regular expression library for the "pattern" validator. It should use a library based on the ECMA 262 regex dialect, which the [spec](http://json-schema.org/latest/json-schema-validation.html#anchor33) requires.
50−
51−+ Currently doesn't support the optional `"format"` validators.
19++ Requires [pcre](http://www.pcre.org/) (`pkgs.pcre` in Nixpkgs).
5220
5321## Vendoring
5422
55−+ `JSON-Schema-Test-Suite` is vendored from commit # aabcb3427745ade7a0b4d49ff016ad7eda8b898b [here](https://github.com/json-schema-org/JSON-Schema-Test-Suite).
56−
57−+ `src/draft4.json` is from commit # f3d5aeb5ffbe9d9a5a0ceb761dc47c7c4c2efa68 [here](https://github.com/json-schema/json-schema).
58−
59−## Credits
60−
61−[TJ Weigel](http://tjweigel.com/) created the logo.
62−
63−[Tim Baumann](https://github.com/timjb) wrote [aeson-schema](https://hackage.haskell.org/package/aeson-schema), on which hjsonschema's test code and its implementation of `SchemaGraph` were based.
23++ `JSON-Schema-Test-Suite` is vendored from commit # c1b12bf699f29a04b4286711c6e3bbfba66f21e5 [here](https://github.com/json-schema-org/JSON-Schema-Test-Suite).
6424
65−[Julian Berman](https://github.com/Julian) maintains the fantastic [language agnostic test suite](https://github.com/json-schema/JSON-Schema-Test-Suite).
25++ `src/draft4.json` is from commit # c1b12bf699f29a04b4286711c6e3bbfba66f21e5 [here](https://github.com/json-schema/json-schema). The [root ref in remote ref](./JSON-Schema-Test-Suite/tests/draft4/refRemote.json) test has been modified to fix [#175](https://github.com/json-schema-org/JSON-Schema-Test-Suite/issues/175).
changelog.md+57
@@ -1,4 +1,61 @@
1+# 1.8.0
2+
3++ Add GHC 8.4 support (thanks @4e6 !).
4++ Drop GHC 7.10 support.
5++ Fix JSON Pointer resolution error.
6+
7+# 1.8.0
8+
9++ Allow HTTPS references (thanks @creichert!).
10++ Use `safe-exceptions` to eliminate the risk of catching asynchronous exceptions.
11+
12+# 1.7.2
13+
14++ Remove upper bounds.
15+
16+# 1.7.1
17+
18++ Bump http-types.
19+
20+# 1.7.0
21+
22++ Test with GHC 8.2. Drop GHC 7.8.
23++ Rework `allUniqueValues` related utility functions.
24+
25+# 1.6.3
26+
27++ Bump hjsonpointer and QuickCheck.
28+
29+# 1.6.2
30+
31++ Bump aeson.
32+
33+# 1.6.1
34+
35++ Fix Haddocks.
36+
37+# 1.6.0
38+
39++ Fix defect where validators alongside "$ref" weren't ignored.
40+
41++ Fix defect where local references would fail if an "id" key had set resolution scope to start from a different document.
42+
43++ Vendor latest tests.
44+
45++ Remove `ReferencedSchemas`.
46+
47++ Create `Scope` to hold information that changes during validation.
48+
49++ Use a sum type for "type" values. Thanks to Philip Weaver (GitHub @pheaver).
50+
51+# 1.5.0.1
52+
53++ Raise test dep upper bounds.
54+
55+# 1.5.0.0
56+
157+ Report details of `"required"` validator failure.
58++ Bump `directory`.
259
360# 1.4.0.0
461
examples/AlternateSchema.hs+87−60
@@ -5,28 +5,24 @@
55-- to copy this module instead of the 'JSONSchema.Draft4'. While it's
66-- less convenient to write schemas in Haskell without a record type, you
77-- can get the implementation finished with far fewer lines of code.
8−
98module AlternateSchema where
109
1110import Protolude
1211
13−import Data.Aeson (FromJSON(..), Value(..),
14− decode)
15−import qualified Data.Aeson as AE
16−import qualified Data.ByteString.Lazy as LBS
17−import qualified Data.HashMap.Strict as HM
18−import Data.Maybe (fromMaybe)
19−import Data.Profunctor (Profunctor (..))
20−
21−import JSONSchema.Draft4 (ValidatorFailure(..),
22− metaSchemaBytes)
23−import JSONSchema.Fetch (ReferencedSchemas(..),
24− SchemaWithURI(..))
25−import qualified JSONSchema.Fetch as FE
26−import JSONSchema.Types (Schema(..), Spec(..))
27−import qualified JSONSchema.Types as JT
28−import qualified JSONSchema.Validator.Draft4 as D4
29−import JSONSchema.Validator.Reference (updateResolutionScope)
12+import Data.Aeson (FromJSON(..), Value(..), decodeStrict)
13+import qualified Data.Aeson as AE
14+import qualified Data.HashMap.Strict as HM
15+import Data.Maybe (fromMaybe)
16+import Data.Profunctor (Profunctor(..))
17+
18+import JSONSchema.Draft4 (ValidatorFailure(..), metaSchemaBytes)
19+import JSONSchema.Fetch (SchemaWithURI(..), URISchemaMap(..))
20+import qualified JSONSchema.Fetch as FE
21+import JSONSchema.Types (Schema(..), Spec(..))
22+import qualified JSONSchema.Types as JT
23+import qualified JSONSchema.Validator.Draft4 as D4
24+import JSONSchema.Validator.Reference (BaseURI(..), Scope(..),
25+ updateResolutionScope)
3026
3127--------------------------------------------------
3228-- * Basic fetching tools
@@ -46,72 +42,97 @@ draft4FetchInfo = FE.FetchInfo embedded (lookup "id") (lookup "$ref")
4642 Just (String t) -> Just t
4743 _ -> Nothing
4844
45+-- | An implementation of 'JT.embedded'.
4946embedded :: Schema -> ([Schema], [Schema])
50−embedded s = JT.embedded (d4Spec (ReferencedSchemas s mempty) mempty Nothing) s
47+embedded s =
48+ JT.embedded (d4Spec mempty mempty (Scope s Nothing (BaseURI Nothing))) s
5149
5250--------------------------------------------------
5351-- * Main API
5452--------------------------------------------------
5553
5654validate
57− :: ReferencedSchemas Schema
58− -> Maybe Text
59− -> Schema
55+ :: URISchemaMap Schema
56+ -> SchemaWithURI Schema
6057 -> Value
6158 -> [ValidatorFailure]
62−validate rs = continueValidating rs (D4.VisitedSchemas [(Nothing, Nothing)])
59+validate schemaMap sw =
60+ JT.validate (d4Spec schemaMap visited scope) (_swSchema sw)
61+ where
62+ visited :: D4.VisitedSchemas
63+ visited = D4.VisitedSchemas [(Nothing, Nothing)]
6364
64−-- A schema for schemas themselves, using @src/draft4.json@ which is loaded
65+ schemaId :: Maybe Text
66+ schemaId = FE._fiId draft4FetchInfo (_swSchema sw)
67+
68+ scope :: Scope Schema
69+ scope = Scope
70+ { _topLevelDocument = _swSchema sw
71+ , _documentURI = _swURI sw
72+ , _currentBaseURI = updateResolutionScope (BaseURI (_swURI sw))
73+ schemaId
74+ }
75+
76+-- | A schema for schemas themselves. Uses @src/draft4.json@ which is loaded
6577-- at compile time.
6678metaSchema :: Schema
6779metaSchema =
6880 fromMaybe (panic "Schema decode failed (this should never happen)")
69− . decode
70− . LBS.fromStrict
81+ . decodeStrict
7182 $ metaSchemaBytes
7283
7384checkSchema :: Schema -> [ValidatorFailure]
74−checkSchema = validate referenced Nothing metaSchema . Object . _unSchema
85+checkSchema = validate schemaMap (SchemaWithURI metaSchema Nothing)
86+ . Object
87+ . _unSchema
7588 where
76− referenced :: ReferencedSchemas Schema
77− referenced = ReferencedSchemas
78− metaSchema
79− (HM.singleton "http://json-schema.org/draft-04/schema"
89+ schemaMap :: URISchemaMap Schema
90+ schemaMap =
91+ URISchemaMap (HM.singleton "http://json-schema.org/draft-04/schema"
8092 metaSchema)
8193
8294--------------------------------------------------
8395-- * Spec
8496--------------------------------------------------
8597
86−continueValidating
87− :: ReferencedSchemas Schema
98+validateSubschema
99+ :: URISchemaMap Schema
88100 -> D4.VisitedSchemas
89− -> Maybe Text
101+ -> Scope Schema
90102 -> Schema
91103 -> Value
92104 -> [ValidatorFailure]
93−continueValidating referenced visited mURI sc =
94− JT.validate (d4Spec referenced visited newScope) sc
105+validateSubschema schemaMap visited scope schema =
106+ JT.validate (d4Spec schemaMap visited newScope) schema
95107 where
96108 schemaId :: Maybe Text
97− schemaId = case HM.lookup "id" (_unSchema sc) of
98− Just (String t) -> Just t
99− _ -> Nothing
109+ schemaId = FE._fiId draft4FetchInfo schema
100110
101− newScope :: Maybe Text
102− newScope = updateResolutionScope mURI schemaId
111+ newScope :: Scope Schema
112+ newScope = scope
113+ { _currentBaseURI = updateResolutionScope (_currentBaseURI scope)
114+ schemaId
115+ }
103116
104117d4Spec
105− :: ReferencedSchemas Schema
118+ :: URISchemaMap Schema
106119 -> D4.VisitedSchemas
107− -> Maybe Text
120+ -> Scope Schema
108121 -> Spec Schema ValidatorFailure
109122 -- ^ Here we reuses 'ValidatorFailure' from
110123 -- 'JSONSchema.Draft4.Failure'. If your validators have different
111124 -- failure possibilities you'll need to create your own validator
112125 -- failure type.
113−d4Spec referenced visited scope =
114− Spec
126+d4Spec schemaMap visited scope =
127+ Spec $
128+ [ dimap
129+ f
130+ FailureRef
131+ (D4.refValidator (FE.getReference schemaMap) updateScope
132+ valRef visited scope)
133+ ]
134+
135+ <> fmap (lmap disableIfRefPresent)
115136 [ dimap f FailureMultipleOf D4.multipleOfValidator
116137 , dimap f FailureMaximum D4.maximumValidator
117138 , dimap f FailureMinimum D4.minimumValidator
@@ -129,6 +150,7 @@ d4Spec referenced visited scope =
129150 D4.IRInvalidItems e -> FailureItems e
130151 D4.IRInvalidAdditional e -> FailureAdditionalItems e)
131152 (D4.itemsRelatedValidator descend)
153+ , lmap f D4.definitionsEmbedded
132154
133155 , dimap f FailureMaxProperties D4.maxPropertiesValidator
134156 , dimap f FailureMinProperties D4.minPropertiesValidator
@@ -139,10 +161,6 @@ d4Spec referenced visited scope =
139161 FailurePropertiesRelated
140162 (D4.propertiesRelatedValidator descend)
141163
142− , dimap
143− f
144− FailureRef
145− (D4.refValidator visited scope (FE.getReference referenced) getRef)
146164 , dimap f FailureEnum D4.enumValidator
147165 , dimap f FailureType D4.typeValidator
148166 , dimap f FailureAllOf (D4.allOfValidator lateral)
@@ -152,22 +170,31 @@ d4Spec referenced visited scope =
152170 ]
153171 where
154172 f :: FromJSON a => Schema -> Maybe a
155− f (Schema a) = case AE.fromJSON (Object a) of
156− AE.Error _ -> Nothing
157− AE.Success b -> Just b
158−
159− -- 'Maybe Text' is the URI the referenced schema is fetched from,
160− -- this probably needs a 'newtype' wrapper.
161− getRef
173+ f (Schema a) =
174+ case AE.fromJSON (Object a) of
175+ AE.Error _ -> Nothing
176+ AE.Success b -> Just b
177+
178+ disableIfRefPresent :: Schema -> Schema
179+ disableIfRefPresent schema =
180+ case FE._fiRef draft4FetchInfo schema of
181+ Nothing -> schema
182+ Just _ -> Schema mempty
183+
184+ updateScope :: BaseURI -> Schema -> BaseURI
185+ updateScope uri schema =
186+ updateResolutionScope uri (FE._fiId draft4FetchInfo schema)
187+
188+ valRef
162189 :: D4.VisitedSchemas
163− -> Maybe Text
190+ -> Scope Schema
164191 -> Schema
165192 -> Value
166193 -> [ValidatorFailure]
167− getRef = continueValidating referenced
194+ valRef vis sc = JT.validate (d4Spec schemaMap vis sc)
168195
169196 descend :: Schema -> Value -> [ValidatorFailure]
170− descend = continueValidating referenced mempty scope
197+ descend = validateSubschema schemaMap mempty scope
171198
172199 lateral :: Schema -> Value -> [ValidatorFailure]
173− lateral = continueValidating referenced visited scope
200+ lateral = validateSubschema schemaMap visited scope
examples/Simple.hs+7−8
@@ -1,22 +1,21 @@
1−
21module Simple where
32
43import Protolude
54
6−import Data.Aeson (Value(..), decode, toJSON)
7−import qualified Data.ByteString.Lazy as LBS
8−import qualified Data.List.NonEmpty as NE
9−import Data.Maybe (fromMaybe)
5+import Data.Aeson (Value(..), decodeStrict, toJSON)
6+import qualified Data.ByteString as BS
7+import qualified Data.List.NonEmpty as NE
8+import Data.Maybe (fromMaybe)
109
11−import qualified JSONSchema.Draft4 as D4
10+import qualified JSONSchema.Draft4 as D4
1211
1312badData :: Value
1413badData = toJSON [True, True]
1514
1615example :: IO ()
1716example = do
18− bts <- LBS.readFile "./examples/json/unique.json"
19− let schema = fromMaybe (panic "Invalid schema JSON.") (decode bts)
17+ bts <- BS.readFile "./examples/json/unique.json"
18+ let schema = fromMaybe (panic "Invalid schema JSON.") (decodeStrict bts)
2019 schemaWithURI = D4.SchemaWithURI
2120 schema
2221 Nothing -- This would be the URI of the schema
examples/TwoStep.hs+3−4
@@ -10,15 +10,14 @@
1010-- 'fetchHTTPAndValidate' which fetched references over HTTP (though it
1111-- didn't matter because the last schema didn't actually have any).
1212-- This time we need to get them from the filesystem.
13−
1413module TwoStep where
1514
1615import Protolude
1716
18−import Data.Aeson (Value (..), toJSON)
19−import qualified Data.List.NonEmpty as NE
17+import Data.Aeson (Value(..), toJSON)
18+import qualified Data.List.NonEmpty as NE
2019
21−import qualified JSONSchema.Draft4 as D4
20+import qualified JSONSchema.Draft4 as D4
2221import qualified JSONSchema.Validator.Draft4 as VAL
2322
2423schema :: D4.Schema
hjsonschema.cabal+25−29
@@ -1,5 +1,5 @@
11name: hjsonschema
2−version: 1.4.0.0
2+version: 1.9.0
33synopsis: JSON Schema library
44homepage: https://github.com/seagreen/hjsonschema
55license: MIT
@@ -9,6 +9,8 @@ maintainer: ian@housejeffries.com
99category: Data
1010build-type: Simple
1111cabal-version: >=1.10
12+-- Rerun multi-ghc-travis (executable make-travis-yml-2) after changing:
13+Tested-With: GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.1
1214extra-source-files:
1315 changelog.md
1416 JSON-Schema-Test-Suite/remotes/*.json
@@ -32,7 +34,6 @@ library
3234 NoImplicitPrelude
3335 OverloadedStrings
3436 ScopedTypeVariables
35− TupleSections
3637 if impl(ghc >= 8)
3738 default-extensions: StrictData
3839 ghc-options:
@@ -57,27 +58,28 @@ library
5758 JSONSchema.Validator.Draft4.Object.Properties
5859 , Import
5960 build-depends:
60− base >= 4.7 && < 4.10
61+ base >= 4.7 && < 5
6162 -- 0.11 is for `.:!`:
62− , aeson >= 0.11 && < 1.2
63− , bytestring >= 0.10 && < 0.11
64− , containers >= 0.5 && < 0.6
65− , file-embed >= 0.0.8 && < 0.1
66− , filepath >= 1.3 && < 1.5
67− , hashable >= 1.2 && < 1.3
68− , hjsonpointer >= 1.1 && < 1.2
63+ , aeson >= 0.11
64+ , bytestring >= 0.10
65+ , containers >= 0.5
66+ , file-embed >= 0.0.8
67+ , filepath >= 1.3
68+ , hashable >= 1.2
69+ , hjsonpointer >= 1.1
6970 -- 0.4.30 is for parseUrlThrow:
70− , http-client >= 0.4.30 && < 0.6
71− , http-types >= 0.8 && < 0.10
72− , pcre-heavy >= 1.0 && < 1.1
73− , profunctors >= 5.0 && < 5.3
74− , protolude >= 0.1.10 && < 1.2
75− , QuickCheck >= 2.8 && < 2.10
76− , scientific >= 0.3 && < 0.4
77− , semigroups >= 0.18 && < 0.19
78− , unordered-containers >= 0.2 && < 0.3
79− , text >= 1.1 && < 1.3
80− , vector >= 0.10 && < 1.0
71+ , http-client >= 0.4.30
72+ , http-client-tls >= 0.3
73+ , http-types >= 0.8
74+ , pcre-heavy >= 1.0
75+ , profunctors >= 5.0
76+ , protolude >= 0.1.10
77+ , QuickCheck >= 2.8
78+ , safe-exceptions >= 0.1.6
79+ , scientific >= 0.3
80+ , unordered-containers >= 0.2
81+ , text >= 1.1
82+ , vector >= 0.10
8183
8284test-suite local
8385 hs-source-dirs:
@@ -112,15 +114,14 @@ test-suite local
112114 , hjsonschema
113115 , profunctors
114116 , protolude
115− , semigroups
116117 , text
117118 , QuickCheck
118119 , unordered-containers
119120 , vector
120121
121122 -- directory-1.2.5 required for `listDirectory`:
122− , directory >= 1.2.5 && < 1.3
123− , hspec >= 2.2 && < 2.4
123+ , directory >= 1.2.5
124+ , hspec >= 2.2
124125
125126test-suite remote
126127 hs-source-dirs:
@@ -151,7 +152,6 @@ test-suite remote
151152 , hjsonschema
152153 , profunctors
153154 , protolude
154− , semigroups
155155 , text
156156 , unordered-containers
157157 , vector
@@ -160,7 +160,3 @@ test-suite remote
160160 , hspec
161161 , wai-app-static
162162 , warp
163−
164−source-repository head
165− type: git
166− location: git://github.com/seagreen/hjsonschema.git
logo.jpgdeleted

Binary file not shown.

shell.nix+5−3
@@ -1,13 +1,15 @@
1+{ghc}:
12with (import <nixpkgs> {});
23
34haskell.lib.buildStackProject {
45 name = "none";
56 inherit ghc;
67 buildInputs = [
7− pkgconfig
88 pcre
99
10− # for `git:` references in stack.yml:
11− git
10+ git # for `git:` references in stack.yml.
11+ ncurses # for intero
12+ pkgconfig
13+ zlib
1214 ];
1315}
src/Import.hs+15−8
@@ -1,12 +1,19 @@
11
2−module Import (module Export) where
2+module Import (module Export, fromJSONEither) where
33
4−import Protolude as Export
4+import Protolude as Export
55
6−import Data.Aeson as Export
6+import Data.Aeson as Export
77import Data.HashMap.Strict as Export (HashMap)
8−import Data.List as Export (length, null) -- for older GHCs
9−import Data.List.NonEmpty as Export (NonEmpty)
10−import Data.Vector as Export (Vector)
11−import Test.QuickCheck as Export hiding ((.&.), Failure,
12− Result, Success)
8+import Data.List.NonEmpty as Export (NonEmpty)
9+import Data.Vector as Export (Vector)
10+import Test.QuickCheck as Export hiding (Failure, Result, Success,
11+ (.&.))
12+
13+import qualified Data.Text as T
14+
15+fromJSONEither :: FromJSON a => Value -> Either Text a
16+fromJSONEither a =
17+ case fromJSON a of
18+ Error e -> Left (T.pack e)
19+ Success b -> Right b
src/JSONSchema/Draft4.hs+21−30
@@ -22,8 +22,7 @@ module JSONSchema.Draft4
2222 , ValidatorFailure(..)
2323
2424 -- * Fetching tools
25− , ReferencedSchemas(..)
26− , FE.URISchemaMap(..)
25+ , URISchemaMap(..)
2726 , referencesViaHTTP
2827 , referencesViaFilesystem
2928
@@ -38,23 +37,19 @@ module JSONSchema.Draft4
3837
3938import Import
4039
41−import Control.Arrow (left)
42−import qualified Data.ByteString as BS
43−import Data.FileEmbed (embedFile,
44− makeRelativeToProject)
45−import qualified Data.HashMap.Strict as HM
46−import qualified Data.List.NonEmpty as NE
47−import Data.Maybe (fromMaybe)
40+import qualified Data.ByteString as BS
41+import Data.FileEmbed (embedFile, makeRelativeToProject)
42+import qualified Data.HashMap.Strict as HM
43+import qualified Data.List.NonEmpty as NE
44+import Data.Maybe (fromMaybe)
4845
49−import JSONSchema.Draft4.Failure (Invalid(..),
50− SchemaInvalid(..),
46+import JSONSchema.Draft4.Failure (Invalid(..), SchemaInvalid(..),
5147 ValidatorFailure(..))
52−import JSONSchema.Draft4.Schema (Schema)
53−import qualified JSONSchema.Draft4.Schema as SC
54−import qualified JSONSchema.Draft4.Spec as Spec
55−import JSONSchema.Fetch (ReferencedSchemas(..),
56− SchemaWithURI(..))
57−import qualified JSONSchema.Fetch as FE
48+import JSONSchema.Draft4.Schema (Schema)
49+import qualified JSONSchema.Draft4.Schema as SC
50+import qualified JSONSchema.Draft4.Spec as Spec
51+import JSONSchema.Fetch (SchemaWithURI(..), URISchemaMap(..))
52+import qualified JSONSchema.Fetch as FE
5853
5954data HTTPValidationFailure
6055 = HVRequest FE.HTTPFailure
@@ -70,11 +65,11 @@ fetchHTTPAndValidate
7065 -> IO (Either HTTPValidationFailure ())
7166fetchHTTPAndValidate sw v = do
7267 res <- referencesViaHTTP sw
73− pure (g =<< f =<< left HVRequest res)
68+ pure (g =<< f =<< first HVRequest res)
7469 where
7570 f :: FE.URISchemaMap Schema
7671 -> Either HTTPValidationFailure (Value -> [ValidatorFailure])
77− f references = left HVSchema (checkSchema references sw)
72+ f references = first HVSchema (checkSchema references sw)
7873
7974 g :: (Value -> [ValidatorFailure]) -> Either HTTPValidationFailure ()
8075 g val = case NE.nonEmpty (val v) of
@@ -100,11 +95,11 @@ fetchFilesystemAndValidate
10095 -> IO (Either FilesystemValidationFailure ())
10196fetchFilesystemAndValidate sw v = do
10297 res <- referencesViaFilesystem sw
103− pure (g =<< f =<< left FVRead res)
98+ pure (g =<< f =<< first FVRead res)
10499 where
105100 f :: FE.URISchemaMap Schema
106101 -> Either FilesystemValidationFailure (Value -> [ValidatorFailure])
107− f references = left FVSchema (checkSchema references sw)
102+ f references = first FVSchema (checkSchema references sw)
108103
109104 g :: (Value -> [ValidatorFailure]) -> Either FilesystemValidationFailure ()
110105 g val = case NE.nonEmpty (val v) of
@@ -143,10 +138,7 @@ checkSchema
143138checkSchema sm sw =
144139 case NE.nonEmpty failures of
145140 Just fs -> Left (SchemaInvalid fs)
146− Nothing -> Right (Spec.specValidate
147− (ReferencedSchemas (_swSchema sw)
148− (FE._unURISchemaMap sm))
149− sw)
141+ Nothing -> Right (Spec.specValidate sm sw)
150142 where
151143 failures :: [(Maybe Text, NonEmpty ValidatorFailure)]
152144 failures =
@@ -169,12 +161,11 @@ metaSchemaBytes =
169161-- (if so the returned list will be empty).
170162schemaValidity :: Schema -> [ValidatorFailure]
171163schemaValidity =
172− Spec.specValidate referenced (SchemaWithURI metaSchema Nothing) . toJSON
164+ Spec.specValidate schemaMap (SchemaWithURI metaSchema Nothing) . toJSON
173165 where
174− referenced :: ReferencedSchemas Schema
175− referenced = ReferencedSchemas
176− metaSchema
177− (HM.singleton "http://json-schema.org/draft-04/schema"
166+ schemaMap :: URISchemaMap Schema
167+ schemaMap =
168+ URISchemaMap (HM.singleton "http://json-schema.org/draft-04/schema"
178169 metaSchema)
179170
180171-- | Check that a set of referenced schemas are valid
src/JSONSchema/Draft4/Failure.hs+1−2
@@ -1,9 +1,8 @@
1−
21module JSONSchema.Draft4.Failure where
32
43import Import
54
6−import JSONSchema.Draft4.Schema (Schema)
5+import JSONSchema.Draft4.Schema (Schema)
76import qualified JSONSchema.Validator.Draft4 as VAL
87
98-- | Used to report an entire instance being invalidated, as opposed
src/JSONSchema/Draft4/Schema.hs+6−7
@@ -1,14 +1,13 @@
1−
21module JSONSchema.Draft4.Schema where
32
4−import Import hiding (mapMaybe)
3+import Import hiding (mapMaybe)
54
6−import qualified Data.HashMap.Strict as HM
7−import Data.List.NonEmpty (NonEmpty)
8−import Data.Maybe (fromJust, isJust)
5+import qualified Data.HashMap.Strict as HM
6+import Data.List.NonEmpty (NonEmpty)
7+import Data.Maybe (fromJust, isJust)
98import Data.Scientific
10−import qualified Data.Set as Set
11−import qualified Data.Text as T
9+import qualified Data.Set as Set
10+import qualified Data.Text as T
1211
1312import qualified JSONSchema.Validator.Draft4 as D4
1413import JSONSchema.Validator.Utils
src/JSONSchema/Draft4/Spec.hs+61−39
@@ -1,53 +1,73 @@
1−
21module JSONSchema.Draft4.Spec where
32
43import Import
54
6−import Data.Maybe (fromMaybe)
7−import Data.Profunctor (Profunctor(..))
5+import Data.Maybe (fromMaybe)
6+import Data.Profunctor (Profunctor(..))
87
98import JSONSchema.Draft4.Failure
10−import JSONSchema.Draft4.Schema (Schema(..))
11−import JSONSchema.Fetch (ReferencedSchemas(..),
12− SchemaWithURI(..))
13−import qualified JSONSchema.Fetch as FE
14−import JSONSchema.Types (Spec(..))
15−import qualified JSONSchema.Types as JT
9+import JSONSchema.Draft4.Schema (Schema(..), emptySchema)
10+import JSONSchema.Fetch (SchemaWithURI(..), URISchemaMap(..))
11+import qualified JSONSchema.Fetch as FE
12+import JSONSchema.Types (Spec(..))
13+import qualified JSONSchema.Types as JT
1614import JSONSchema.Validator.Draft4
17−import JSONSchema.Validator.Reference (updateResolutionScope)
15+import JSONSchema.Validator.Reference (BaseURI(..), Scope(..),
16+ updateResolutionScope)
1817
18+-- | An implementation of 'JT.embedded'.
1919embedded :: Schema -> ([Schema], [Schema])
20−embedded s = JT.embedded (d4Spec (ReferencedSchemas s mempty) mempty Nothing) s
20+embedded s =
21+ JT.embedded (d4Spec mempty mempty (Scope s Nothing (BaseURI Nothing))) s
2122
2223specValidate
23− :: ReferencedSchemas Schema
24+ :: URISchemaMap Schema
2425 -> SchemaWithURI Schema
2526 -> Value
2627 -> [ValidatorFailure]
27−specValidate rs =
28− continueValidating rs (VisitedSchemas [(Nothing, Nothing)])
28+specValidate schemaMap sw =
29+ JT.validate (d4Spec schemaMap visited scope) (_swSchema sw)
30+ where
31+ visited :: VisitedSchemas
32+ visited = VisitedSchemas [(Nothing, Nothing)]
33+
34+ scope :: Scope Schema
35+ scope = Scope
36+ { _topLevelDocument = _swSchema sw
37+ , _documentURI = _swURI sw
38+ , _currentBaseURI = updateResolutionScope (BaseURI (_swURI sw))
39+ (_schemaId (_swSchema sw))
40+ }
2941
30−continueValidating
31− :: ReferencedSchemas Schema
42+validateSubschema
43+ :: URISchemaMap Schema
3244 -> VisitedSchemas
33− -> SchemaWithURI Schema
45+ -> Scope Schema
46+ -> Schema
3447 -> Value
3548 -> [ValidatorFailure]
36−continueValidating referenced visited sw =
37− JT.validate (d4Spec referenced visited currentScope)
38− (_swSchema sw)
49+validateSubschema schemaMap visited scope schema =
50+ JT.validate (d4Spec schemaMap visited newScope) schema
3951 where
40− currentScope :: Maybe Text
41− currentScope = updateResolutionScope
42− (_swURI sw)
43− (_schemaId (_swSchema sw))
52+ newScope :: Scope Schema
53+ newScope = scope
54+ { _currentBaseURI = updateResolutionScope (_currentBaseURI scope)
55+ (_schemaId schema)
56+ }
4457
4558d4Spec
46− :: ReferencedSchemas Schema
59+ :: URISchemaMap Schema
4760 -> VisitedSchemas
48− -> Maybe Text
61+ -> Scope Schema
4962 -> Spec Schema ValidatorFailure
50−d4Spec referenced visited scope = Spec
63+d4Spec schemaMap visited scope = Spec $
64+ [ dimap
65+ (fmap Ref . _schemaRef)
66+ FailureRef
67+ (refValidator (FE.getReference schemaMap) updateScope valRef visited scope)
68+ ]
69+
70+ <> fmap (lmap disableIfRefPresent)
5171 [ dimap (fmap MultipleOf . _schemaMultipleOf) FailureMultipleOf multipleOfValidator
5272 , dimap
5373 (\s -> Maximum (fromMaybe False (_schemaExclusiveMaximum s)) <$> _schemaMaximum s)
@@ -98,10 +118,6 @@ d4Spec referenced visited scope = Spec
98118 FailurePropertiesRelated
99119 (propertiesRelatedValidator descend)
100120
101− , dimap
102− (\s -> Ref <$> _schemaRef s)
103− FailureRef
104− (refValidator visited scope (FE.getReference referenced) getRef)
105121 , dimap (fmap EnumValidator . _schemaEnum) FailureEnum enumValidator
106122 , dimap (fmap TypeContext . _schemaType) FailureType typeValidator
107123 , dimap (fmap AllOf . _schemaAllOf) FailureAllOf (allOfValidator lateral)
@@ -110,19 +126,25 @@ d4Spec referenced visited scope = Spec
110126 , dimap (fmap NotValidator . _schemaNot) FailureNot (notValidator lateral)
111127 ]
112128 where
113− getRef
129+ disableIfRefPresent :: Schema -> Schema
130+ disableIfRefPresent schema =
131+ case _schemaRef schema of
132+ Nothing -> schema
133+ Just _ -> emptySchema
134+
135+ updateScope :: BaseURI -> Schema -> BaseURI
136+ updateScope uri schema = updateResolutionScope uri (_schemaId schema)
137+
138+ valRef
114139 :: VisitedSchemas
115− -> Maybe Text
140+ -> Scope Schema
116141 -> Schema
117142 -> Value
118143 -> [ValidatorFailure]
119− getRef newVisited newScope schema =
120− continueValidating referenced newVisited (SchemaWithURI schema newScope)
144+ valRef vis sc = JT.validate (d4Spec schemaMap vis sc)
121145
122146 descend :: Schema -> Value -> [ValidatorFailure]
123− descend schema =
124− continueValidating referenced mempty (SchemaWithURI schema scope)
147+ descend = validateSubschema schemaMap mempty scope
125148
126149 lateral :: Schema -> Value -> [ValidatorFailure]
127− lateral schema =
128− continueValidating referenced visited (SchemaWithURI schema scope)
150+ lateral = validateSubschema schemaMap visited scope
src/JSONSchema/Fetch.hs+46−65
@@ -1,18 +1,18 @@
1−
21module JSONSchema.Fetch where
32
43import Import
54
6−import Control.Arrow (left)
7−import Control.Exception (IOException, catch)
8−import Control.Monad (foldM)
9−import qualified Data.ByteString as BS
10−import qualified Data.ByteString.Lazy as LBS
11−import qualified Data.HashMap.Strict as HM
12−import qualified Data.Text as T
13−import qualified Network.HTTP.Client as NC
14−
15−import JSONSchema.Validator.Reference (resolveReference,
5+import qualified Control.Exception.Safe as Safe
6+import Control.Monad (foldM)
7+import qualified Data.ByteString as BS
8+import qualified Data.ByteString.Lazy as LBS
9+import qualified Data.HashMap.Strict as HM
10+import qualified Data.Semigroup as S
11+import qualified Data.Text as T
12+import qualified Network.HTTP.Client as NC
13+import qualified Network.HTTP.Client.TLS as NCTLS
14+
15+import JSONSchema.Validator.Reference (BaseURI(..), resolveReference,
1616 updateResolutionScope)
1717
1818--------------------------------------------------
@@ -27,49 +27,22 @@ data FetchInfo schema = FetchInfo
2727 , _fiRef :: schema -> Maybe Text
2828 }
2929
30−data ReferencedSchemas schema = ReferencedSchemas
31− { _rsStarting :: !schema
32− -- ^ Used to resolve relative references when we don't know what the scope
33− -- of the current schema is. This only happens with starting schemas
34− -- because if we're using a remote schema we had to know its URI in order
35− -- to fetch it.
36− --
37− -- Tracking the starting schema (instead of just resolving the reference to
38− -- the current schema being used for validation) is necessary for cases
39− -- where schemas are embedded inside one another. For instance in this
40− -- case not distinguishing the starting and "foo" schemas sends the code
41− -- into an infinite loop:
42− --
43− -- {
44− -- "additionalProperties": false,
45− -- "properties": {
46− -- "foo": {
47− -- "$ref": "#"
48− -- }
49− -- }
50− -- }
51− , _rsSchemaMap :: !(HashMap Text schema)
52− -- ^ Map of URIs to schemas.
53− } deriving (Eq, Show)
54−
5530-- | Keys are URIs (without URI fragments).
5631newtype URISchemaMap schema
5732 = URISchemaMap { _unURISchemaMap :: HashMap Text schema }
58− deriving (Eq, Show)
33+ deriving (Eq, Show, S.Semigroup, Monoid)
5934
35+-- | A top-level schema along with its location.
6036data SchemaWithURI schema = SchemaWithURI
6137 { _swSchema :: !schema
6238 , _swURI :: !(Maybe Text)
63− -- ^ This is the URI identifying the document containing the schema.
39+ -- ^ This is the URI from which the document was originally fetched.
6440 -- It's different than the schema's "id" field, which controls scope
6541 -- when resolving references contained in the schema.
66−
67− -- TODO: Make the no URI fragment requirement unnecessary.
6842 } deriving (Eq, Show)
6943
70−getReference :: ReferencedSchemas schema -> Maybe Text -> Maybe schema
71−getReference referenced Nothing = Just (_rsStarting referenced)
72−getReference referenced (Just t) = HM.lookup t (_rsSchemaMap referenced)
44+getReference :: URISchemaMap schema -> Text -> Maybe schema
45+getReference schemaMap t = HM.lookup t (_unURISchemaMap schemaMap)
7346
7447--------------------------------------------------
7548-- * Fetch via HTTP
@@ -88,9 +61,9 @@ referencesViaHTTP'
8861 -> SchemaWithURI schema
8962 -> IO (Either HTTPFailure (URISchemaMap schema))
9063referencesViaHTTP' info sw = do
91− manager <- NC.newManager NC.defaultManagerSettings
64+ manager <- NC.newManager NCTLS.tlsManagerSettings
9265 let f = referencesMethodAgnostic (getURL manager) info sw
93− catch (left HTTPParseFailure <$> f) handler
66+ Safe.catch (first HTTPParseFailure <$> f) handler
9467 where
9568 getURL :: NC.Manager -> Text -> IO BS.ByteString
9669 getURL man url = do
@@ -116,7 +89,8 @@ referencesViaFilesystem'
11689 => FetchInfo schema
11790 -> SchemaWithURI schema
11891 -> IO (Either FilesystemFailure (URISchemaMap schema))
119−referencesViaFilesystem' info sw = catch (left FSParseFailure <$> f) handler
92+referencesViaFilesystem' info sw =
93+ Safe.catch (first FSParseFailure <$> f) handler
12094 where
12195 f :: IO (Either Text (URISchemaMap schema))
12296 f = referencesMethodAgnostic (BS.readFile . T.unpack) info sw
@@ -155,27 +129,33 @@ getRecursiveReferences fetchRef info referenced sw =
155129 f :: Either Text (URISchemaMap schema)
156130 -> SchemaWithURI schema
157131 -> IO (Either Text (URISchemaMap schema))
158− f (Left e) _ = pure (Left e)
159− f (Right (URISchemaMap usm)) (SchemaWithURI schema mUri) =
132+ f (Left e) _ = pure (Left e)
133+ f (Right (URISchemaMap schemaMap)) (SchemaWithURI schema mURI) =
160134 case newRef of
161− Nothing -> pure (Right (URISchemaMap usm))
135+ Nothing -> pure (Right (URISchemaMap schemaMap))
162136 Just uri -> do
163137 bts <- fetchRef uri
164138 case eitherDecodeStrict bts of
165− Left e -> pure . Left . T.pack $ e
166− Right schm -> getRecursiveReferences
167− fetchRef
168− info
169− (URISchemaMap (HM.insert uri schm usm))
170− (SchemaWithURI schm (Just uri))
139+ Left e -> pure . Left . T.pack $ e
140+ Right s -> getRecursiveReferences
141+ fetchRef
142+ info
143+ (URISchemaMap (HM.insert uri s schemaMap))
144+ (SchemaWithURI s (Just uri))
171145 where
172146 newRef :: Maybe Text
173− newRef
174− | Just (Just uri,_) <- resolveReference mUri <$> _fiRef info schema
175− = case HM.lookup uri usm of
176− Nothing -> Just uri
177− Just _ -> Nothing
178− | otherwise = Nothing
147+ newRef = do
148+ ref <- _fiRef info schema
149+
150+ -- Consider the reference before updating the scope.
151+ -- If it's a only a fragment this isn't referencing
152+ -- a new document.
153+ void (fst (resolveReference (BaseURI Nothing) ref))
154+
155+ uri <- fst (resolveReference (BaseURI mURI) ref)
156+ case HM.lookup uri schemaMap of
157+ Nothing -> Just uri
158+ Just _ -> Nothing
179159
180160-- | Return the schema passed in as an argument, as well as every
181161-- subschema contained within it.
@@ -184,11 +164,12 @@ includeSubschemas
184164 FetchInfo schema
185165 -> SchemaWithURI schema
186166 -> [SchemaWithURI schema]
187−includeSubschemas info (SchemaWithURI schema mUri) =
188− SchemaWithURI schema mUri
167+includeSubschemas info (SchemaWithURI schema mURI) =
168+ SchemaWithURI schema mURI
189169 : (includeSubschemas info =<< subSchemas)
190170 where
191171 subSchemas :: [SchemaWithURI schema]
192172 subSchemas =
193− (\a -> SchemaWithURI a (updateResolutionScope mUri (_fiId info schema)))
194− <$> uncurry (<>) (_fiEmbedded info schema)
173+ let newScope = updateResolutionScope (BaseURI mURI) (_fiId info schema)
174+ updateScope s = SchemaWithURI s (_unBaseURI newScope)
175+ in updateScope <$> uncurry (<>) (_fiEmbedded info schema)
src/JSONSchema/Types.hs−1
@@ -1,4 +1,3 @@
1−
21module JSONSchema.Types where
32
43import Import
src/JSONSchema/Validator/Draft4.hs+19−19
@@ -1,5 +1,7 @@
11-- | Turn the validation functions into actual 'Validator's.
2−
2+--
3+-- This is frankly a lot of busywork. It can perhaps be moved into the
4+-- validator modules themselves once we're sure this is the right design.
35module JSONSchema.Validator.Draft4
46 ( module JSONSchema.Validator.Draft4
57 , module Export
@@ -7,18 +9,16 @@ module JSONSchema.Validator.Draft4
79
810import Import
911
10−import qualified Data.HashMap.Strict as HM
11−import qualified Data.List.NonEmpty as NE
12−import Data.Maybe (catMaybes, maybe, maybeToList)
13−import Data.Text (Text)
12+import qualified Data.HashMap.Strict as HM
13+import qualified Data.List.NonEmpty as NE
1414
15−import JSONSchema.Validator.Draft4.Any as Export
16−import JSONSchema.Validator.Draft4.Array as Export
15+import JSONSchema.Validator.Draft4.Any as Export
16+import JSONSchema.Validator.Draft4.Array as Export
1717import JSONSchema.Validator.Draft4.Number as Export
1818import JSONSchema.Validator.Draft4.Object as Export
1919import JSONSchema.Validator.Draft4.String as Export
20−import JSONSchema.Validator.Types (Validator(..))
21−import JSONSchema.Validator.Utils (fromJSONEither)
20+import JSONSchema.Validator.Reference (BaseURI(..), Scope(..))
21+import JSONSchema.Validator.Types (Validator(..))
2222
2323-- | For internal use.
2424--
@@ -75,6 +75,8 @@ minItemsValidator = Validator noEmbedded (run minItemsVal)
7575uniqueItemsValidator :: Validator a (Maybe UniqueItems) UniqueItemsInvalid
7676uniqueItemsValidator = Validator noEmbedded (run uniqueItemsVal)
7777
78+-- TODO: Add tests to the language agnostic test suite to
79+-- make sure @"additionalItems"@ subschemas are embedded correctly.
7880itemsRelatedValidator
7981 :: (schema -> Value -> [err])
8082 -> Validator schema (ItemsRelated schema) (ItemsRelatedInvalid err)
@@ -145,7 +147,7 @@ propertiesRelatedValidator f =
145147 <> HM.elems (fromMaybe mempty (_propPattern a))
146148 <> case _propAdditional a of
147149 Just (AdditionalPropertiesObject b) -> [b]
148− _ -> mempty
150+ _ -> mempty
149151 ))
150152 (\a b -> case fromJSONEither b of
151153 Left _ -> mempty
@@ -159,9 +161,6 @@ instance FromJSON schema => FromJSON (Definitions schema) where
159161 parseJSON = withObject "Definitions" $ \o ->
160162 Definitions <$> o .: "definitions"
161163
162−-- TODO: Add tests to the language agnostic test suite to
163−-- make sure these schemas are embedded correctly
164−-- (and do so for @"additionalItems"@ as well).
165164definitionsEmbedded
166165 :: Validator
167166 schema
@@ -180,15 +179,16 @@ definitionsEmbedded =
180179
181180refValidator
182181 :: (FromJSON schema, ToJSON schema)
183− => VisitedSchemas
184− -> Maybe Text
185− -> (Maybe Text -> Maybe schema)
186− -> (VisitedSchemas -> Maybe Text -> schema -> Value -> [err])
182+ => (Text -> Maybe schema)
183+ -> (BaseURI -> schema -> BaseURI)
184+ -> (VisitedSchemas -> Scope schema -> schema -> Value -> [err])
185+ -> VisitedSchemas
186+ -> Scope schema
187187 -> Validator a (Maybe Ref) (RefInvalid err)
188−refValidator visited scope getRef f =
188+refValidator getRef updateScope f visited scope =
189189 Validator
190190 noEmbedded
191− (run (refVal visited scope getRef f))
191+ (run (refVal getRef updateScope f visited scope))
192192
193193enumValidator :: Validator a (Maybe EnumValidator) EnumInvalid
194194enumValidator = Validator noEmbedded (run enumVal)
src/JSONSchema/Validator/Draft4/Any.hs+217−59
@@ -1,20 +1,24 @@
1−
21module JSONSchema.Validator.Draft4.Any where
32
4−import Import
5−
6−import Data.List.NonEmpty (NonEmpty((:|)))
7−import qualified Data.List.NonEmpty as NE
8−import qualified Data.Scientific as SCI
9−import Data.Semigroup (Semigroup) -- for older GHCs
10−import Data.Set (Set)
11−import qualified Data.Set as S
12−import qualified JSONPointer as JP
13−
14−import qualified JSONSchema.Validator.Utils as UT
15−import JSONSchema.Validator.Reference (URIBaseAndFragment,
16− resolveFragment,
3+import Import hiding ((<>))
4+
5+import Data.Aeson.TH (constructorTagModifier)
6+import Data.Char (toLower)
7+import qualified Data.HashMap.Strict as HM
8+import Data.List.NonEmpty (NonEmpty((:|)))
9+import qualified Data.List.NonEmpty as NE
10+import qualified Data.Scientific as SCI
11+import Data.Semigroup
12+import Data.Set (Set)
13+import qualified Data.Set as Set
14+import Data.Text.Encoding.Error (UnicodeException)
15+import qualified JSONPointer as JP
16+import Network.HTTP.Types.URI (urlDecode)
17+
18+import JSONSchema.Validator.Reference (BaseURI(..), Scope(..),
19+ URIAndFragment,
1720 resolveReference)
21+import qualified JSONSchema.Validator.Utils as UT
1822
1923--------------------------------------------------
2024-- * $ref
@@ -39,42 +43,156 @@ data RefInvalid err
3943 -- Also note that ideally we would enforce in the type system that any
4044 -- failing references be dealt with before valididation. Then this could
4145 -- be removed entirely.
42− | RefPointerResolution Text
43− | RefLoop Text VisitedSchemas URIBaseAndFragment
46+ | RefPointerResolution JSONPointerError
47+ | RefLoop Text VisitedSchemas URIAndFragment
4448 | RefInvalid Text Value (NonEmpty err)
4549 -- ^ 'Text' is the URI and 'Value' is the linked schema.
4650 deriving (Eq, Show)
4751
4852newtype VisitedSchemas
49− = VisitedSchemas { _unVisited :: [URIBaseAndFragment] }
53+ = VisitedSchemas { _unVisited :: [URIAndFragment] }
5054 deriving (Eq, Show, Semigroup, Monoid)
5155
5256refVal
5357 :: forall err schema. (FromJSON schema, ToJSON schema)
54− => VisitedSchemas
55− -> Maybe Text
56− -> (Maybe Text -> Maybe schema)
57− -> (VisitedSchemas -> Maybe Text -> schema -> Value -> [err])
58+ => (Text -> Maybe schema)
59+ -- ^ Look up a schema.
60+ -> (BaseURI -> schema -> BaseURI)
61+ -- ^ Update scope (needed after moving deeper into nested schemas).
62+ -> (VisitedSchemas -> Scope schema -> schema -> Value -> [err])
63+ -- ^ Validate data.
64+ -> VisitedSchemas
65+ -> Scope schema
5866 -> Ref
5967 -> Value
6068 -> Maybe (RefInvalid err)
61−refVal visited scope getRef f (Ref reference) x
69+refVal getRef updateScope val visited scope (Ref reference) x
6270 | (mURI, mFragment) `elem` _unVisited visited =
6371 Just (RefLoop reference visited (mURI, mFragment))
64− | otherwise =
65− case getRef mURI of
66− Nothing -> Just (RefResolution reference)
67− Just schema ->
68− case resolveFragment mFragment schema of
69− Nothing -> Just (RefPointerResolution reference)
70− Just s ->
71− let newVisited = (VisitedSchemas [(mURI, mFragment)]
72− <> visited)
73− errs = f newVisited mURI s x
74− in RefInvalid reference (toJSON schema)
75− <$> NE.nonEmpty errs
72+ | otherwise = leftToMaybe $ do
73+
74+ -- Get the referenced document
75+
76+ (newScope, doc) <- first RefResolution
77+ $ getDocument getRef updateScope scope mURI reference
78+
79+ -- Get the correct subschema within that document.
80+
81+ res <- case mFragment of
82+ Nothing -> Right (newScope, doc)
83+ Just fragment -> first RefPointerResolution
84+ $ resolveFragment updateScope newScope fragment
85+ let (finalScope, schema) = res
86+
87+ -- Check if that schema is valid.
88+
89+ let newVisited = VisitedSchemas [(_documentURI newScope, mFragment)]
90+ <> visited
91+ failures = val newVisited finalScope schema x
92+ first (RefInvalid reference (toJSON schema))
93+ . maybeToLeft ()
94+ $ NE.nonEmpty failures
7695 where
77− (mURI, mFragment) = resolveReference scope reference
96+ mURI :: Maybe Text
97+ mFragment :: Maybe Text
98+ (mURI, mFragment) = resolveReference (_currentBaseURI scope) reference
99+
100+getDocument
101+ :: forall schema. (Text -> Maybe schema)
102+ -> (BaseURI -> schema -> BaseURI)
103+ -> Scope schema
104+ -> Maybe Text
105+ -> Text
106+ -> Either Text (Scope schema, schema)
107+ -- ^ 'Left' is the URI of the document we failed to resolve.
108+getDocument getRef updateScope scope mURI reference =
109+ case mURI <* fst (resolveReference (BaseURI Nothing) reference) of
110+ Nothing -> Right topOfThisDoc
111+ Just uri ->
112+ case getRef uri of
113+ Nothing -> Left uri
114+ Just s -> Right ( Scope s mURI (updateScope (BaseURI mURI) s)
115+ , s
116+ )
117+ where
118+ topOfThisDoc :: (Scope schema, schema)
119+ topOfThisDoc =
120+ ( scope { _currentBaseURI =
121+ updateScope (BaseURI (_documentURI scope))
122+ (_topLevelDocument scope)
123+ }
124+ , _topLevelDocument scope
125+ )
126+
127+data JSONPointerError
128+ = URLDecodingError UnicodeException
129+ -- ^ Aspirationally internal.
130+ | FormatError JP.FormatError
131+ | ResolutionError JP.ResolutionError
132+ | SubschemaDecodingError Text
133+ -- ^ Aspirationally internal.
134+ deriving (Eq, Show)
135+
136+resolveFragment
137+ :: (FromJSON schema, ToJSON schema)
138+ => (BaseURI -> schema -> BaseURI)
139+ -> Scope schema
140+ -> Text
141+ -> Either JSONPointerError (Scope schema, schema)
142+resolveFragment updateScope scope fragment = do
143+ urlDecoded <- first URLDecodingError
144+ . decodeUtf8'
145+ . urlDecode True
146+ . encodeUtf8
147+ $ fragment
148+ JP.Pointer tokens <- first FormatError (JP.unescape urlDecoded)
149+ let acc = (toJSON (_topLevelDocument scope), _currentBaseURI scope)
150+ (schemaVal, base) <- foldM go acc tokens
151+ schema <- first SubschemaDecodingError (fromJSONEither schemaVal)
152+ pure (scope { _currentBaseURI = base }, schema)
153+ where
154+ -- We have to step through the document JSON Pointer token
155+ -- by JSON Pointer token so that we can update the scope
156+ -- based on each @"id"@ we encounter.
157+ --
158+ -- TODO: Do we need specialized code to skip @"id"@s such
159+ -- as property keys that aren't meant to change scope?
160+ -- Perhaps this should be added to the language agnostic
161+ -- test suite as well.
162+ --
163+ -- In the meantime 'newBaseURIFromFragment' drops all keys
164+ -- from JSON objects except "id", which at least prevents
165+ -- SubschemaDecodingError in a situation where one of the
166+ -- values we step through isn't a valid schema.
167+ go :: (Value, BaseURI)
168+ -> JP.Token
169+ -> Either JSONPointerError (Value, BaseURI)
170+ go (lastVal, baseURI) tok = do
171+ v <- first ResolutionError (JP.resolveToken tok lastVal)
172+ newBase <- newBaseURIFromFragment updateScope baseURI v
173+ Right (v, newBase)
174+
175+-- | Update the 'BaseURI' (the store of the current "id" value)
176+-- after resolving one token of a JSON Pointer and stepping into
177+-- a new 'Value'.
178+newBaseURIFromFragment
179+ :: FromJSON schema
180+ => (BaseURI -> schema -> BaseURI)
181+ -> BaseURI
182+ -> Value
183+ -> Either JSONPointerError BaseURI
184+newBaseURIFromFragment updateScope baseURI v =
185+ case v of
186+ Object hm -> do
187+ let hmWithOnlyId = case HM.lookup idKey hm of
188+ Nothing -> mempty
189+ Just idVal -> HM.singleton idKey idVal
190+ schema <- first SubschemaDecodingError (fromJSONEither (Object hmWithOnlyId))
191+ Right (updateScope baseURI schema)
192+ _ -> Right baseURI
193+ where
194+ idKey :: Text
195+ idKey = "id"
78196
79197--------------------------------------------------
80198-- * enum
@@ -109,7 +227,10 @@ instance Arbitrary EnumValidator where
109227 Just ne -> pure (EnumValidator ne)
110228 where
111229 toUnique :: [Value] -> [Value]
112− toUnique = fmap UT._unOrdValue . S.toList . S.fromList . fmap UT.OrdValue
230+ toUnique = fmap UT._unOrdValue
231+ . Set.toList
232+ . Set.fromList
233+ . fmap UT.OrdValue
113234
114235data EnumInvalid
115236 = EnumInvalid EnumValidator Value
@@ -117,9 +238,9 @@ data EnumInvalid
117238
118239enumVal :: EnumValidator -> Value -> Maybe EnumInvalid
119240enumVal a@(EnumValidator vs) x
120− | not (UT.allUniqueValues' vs) = Nothing
121− | x `elem` vs = Nothing
122− | otherwise = Just $ EnumInvalid a x
241+ | not (UT.allUniqueValues vs) = Nothing
242+ | x `elem` vs = Nothing
243+ | otherwise = Just $ EnumInvalid a x
123244
124245--------------------------------------------------
125246-- * type
@@ -137,10 +258,25 @@ instance FromJSON TypeContext where
137258 TypeContext <$> o .: "type"
138259
139260data TypeValidator
140− = TypeValidatorString Text
141− | TypeValidatorArray (Set Text)
261+ = TypeValidatorString SchemaType
262+ | TypeValidatorArray (Set SchemaType)
142263 deriving (Eq, Show)
143264
265+instance Semigroup TypeValidator where
266+ (<>) x y
267+ | isEmpty x = x
268+ | isEmpty y = y
269+ | x == y = x
270+ | otherwise = TypeValidatorArray (setFromTypeValidator x
271+ `Set.union`
272+ setFromTypeValidator y)
273+ where
274+ isEmpty :: TypeValidator -> Bool
275+ isEmpty (TypeValidatorString _) = False
276+ isEmpty (TypeValidatorArray ts) = Set.null ts
277+
278+ stimes = stimesIdempotent
279+
144280instance FromJSON TypeValidator where
145281 parseJSON v = fmap TypeValidatorString (parseJSON v)
146282 <|> fmap TypeValidatorArray (parseJSON v)
@@ -150,40 +286,63 @@ instance ToJSON TypeValidator where
150286 toJSON (TypeValidatorArray ts) = toJSON ts
151287
152288instance Arbitrary TypeValidator where
153− arbitrary = oneof [ TypeValidatorString <$> UT.arbitraryText
154− , TypeValidatorArray <$> UT.arbitrarySetOfText
289+ arbitrary = oneof [ TypeValidatorString <$> arbitrary
290+ , TypeValidatorArray <$> arbitrary
155291 ]
156292
293+data SchemaType
294+ = SchemaObject
295+ | SchemaArray
296+ | SchemaString
297+ | SchemaNumber
298+ | SchemaInteger
299+ | SchemaBoolean
300+ | SchemaNull
301+ deriving (Eq, Ord, Show, Bounded, Enum, Generic)
302+
303+instance FromJSON SchemaType where
304+ parseJSON = genericParseJSON
305+ defaultOptions
306+ { constructorTagModifier = fmap toLower . drop 6 }
307+
308+instance ToJSON SchemaType where
309+ toJSON = genericToJSON
310+ defaultOptions
311+ { constructorTagModifier = fmap toLower . drop 6 }
312+
313+instance Arbitrary SchemaType where
314+ arbitrary = arbitraryBoundedEnum
315+
157316data TypeValidatorInvalid
158317 = TypeValidatorInvalid TypeValidator Value
159318 deriving (Eq, Show)
160319
161320typeVal :: TypeContext -> Value -> Maybe TypeValidatorInvalid
162321typeVal (TypeContext tv) x
163− | S.null matches = Just (TypeValidatorInvalid tv x)
164− | otherwise = Nothing
322+ | Set.null matches = Just (TypeValidatorInvalid tv x)
323+ | otherwise = Nothing
165324 where
166325 -- There can be more than one match because a 'Value' can be both a
167326 -- @"number"@ and an @"integer"@.
168− matches :: Set Text
169− matches = S.intersection okTypes (setFromTypeValidator tv)
327+ matches :: Set SchemaType
328+ matches = Set.intersection okTypes (setFromTypeValidator tv)
170329
171− okTypes :: Set Text
330+ okTypes :: Set SchemaType
172331 okTypes =
173332 case x of
174− Null -> S.singleton "null"
175− (Array _) -> S.singleton "array"
176− (Bool _) -> S.singleton "boolean"
177− (Object _) -> S.singleton "object"
178− (String _) -> S.singleton "string"
333+ Null -> Set.singleton SchemaNull
334+ (Array _) -> Set.singleton SchemaArray
335+ (Bool _) -> Set.singleton SchemaBoolean
336+ (Object _) -> Set.singleton SchemaObject
337+ (String _) -> Set.singleton SchemaString
179338 (Number y) ->
180339 if SCI.isInteger y
181− then S.fromList ["number", "integer"]
182− else S.singleton "number"
340+ then Set.fromList [SchemaNumber, SchemaInteger]
341+ else Set.singleton SchemaNumber
183342
184343-- | Internal.
185−setFromTypeValidator :: TypeValidator -> Set Text
186−setFromTypeValidator (TypeValidatorString t) = S.singleton t
344+setFromTypeValidator :: TypeValidator -> Set SchemaType
345+setFromTypeValidator (TypeValidatorString t) = Set.singleton t
187346setFromTypeValidator (TypeValidatorArray ts) = ts
188347
189348--------------------------------------------------
@@ -240,8 +399,7 @@ anyOfVal
240399 -> Value
241400 -> Maybe (AnyOfInvalid err)
242401anyOfVal f (AnyOf subSchemas) x
243− -- Replace with @null@ once we drop GHC 7.8:
244− | any (((==) 0 . length) . snd) perhapsFailures = Nothing
402+ | any (null . snd) perhapsFailures = Nothing
245403 | otherwise = AnyOfInvalid <$> NE.nonEmpty failures
246404 where
247405 perhapsFailures :: [(JP.Index, [err])]
src/JSONSchema/Validator/Draft4/Array.hs+8−7
@@ -1,11 +1,10 @@
1−
21module JSONSchema.Validator.Draft4.Array where
32
43import Import
54
6−import qualified Data.List.NonEmpty as NE
7−import qualified Data.Vector as V
8−import qualified JSONPointer as JP
5+import qualified Data.List.NonEmpty as NE
6+import qualified Data.Vector as V
7+import qualified JSONPointer as JP
98
109import JSONSchema.Validator.Utils (allUniqueValues)
1110
@@ -67,7 +66,7 @@ instance FromJSON UniqueItems where
6766 parseJSON = withObject "UniqueItems" $ \o ->
6867 UniqueItems <$> o .: "uniqueItems"
6968
70−data UniqueItemsInvalid
69+newtype UniqueItemsInvalid
7170 = UniqueItemsInvalid (Vector Value)
7271 deriving (Eq, Show)
7372
@@ -174,7 +173,8 @@ itemsVal f a xs =
174173 :: schema
175174 -> (JP.Index, Value)
176175 -> Maybe (JP.Index, NonEmpty err)
177− validateElem schema (index,x) = (index,) <$> NE.nonEmpty (f schema x)
176+ validateElem schema (index,x) =
177+ (\v -> (index, v)) <$> NE.nonEmpty (f schema x)
178178
179179--------------------------------------------------
180180-- * additionalItems
@@ -219,6 +219,7 @@ additionalItemsVal _ (AdditionalBool False) xs =
219219 AdditionalItemsBoolInvalid <$> NE.nonEmpty xs
220220additionalItemsVal f (AdditionalObject subSchema) xs =
221221 let res = mapMaybe
222− (\(index,x) -> (index,) <$> NE.nonEmpty (f subSchema x))
222+ (\(index,x) -> (\v -> (index, v))
223+ <$> NE.nonEmpty (f subSchema x))
223224 xs
224225 in AdditionalItemsObjectInvalid <$> NE.nonEmpty res
src/JSONSchema/Validator/Draft4/Number.hs+1−2
@@ -1,9 +1,8 @@
1−
21module JSONSchema.Validator.Draft4.Number where
32
43import Import
54
6−import Data.Fixed (mod')
5+import Data.Fixed (mod')
76import Data.Scientific (Scientific)
87
98--------------------------------------------------
src/JSONSchema/Validator/Draft4/Object.hs+6−10
@@ -1,4 +1,3 @@
1−
21module JSONSchema.Validator.Draft4.Object
32 ( module JSONSchema.Validator.Draft4.Object
43 , module JSONSchema.Validator.Draft4.Object.Properties
@@ -6,11 +5,11 @@ module JSONSchema.Validator.Draft4.Object
65
76import Import
87
9−import qualified Data.HashMap.Strict as HM
10−import qualified Data.List.NonEmpty as NE
11−import Data.Set (Set)
12−import qualified Data.Set as Set
13−import qualified Data.Text as T
8+import qualified Data.HashMap.Strict as HM
9+import qualified Data.List.NonEmpty as NE
10+import Data.Set (Set)
11+import qualified Data.Set as Set
12+import qualified Data.Text as T
1413
1514import JSONSchema.Validator.Draft4.Object.Properties
1615import JSONSchema.Validator.Utils
@@ -96,9 +95,6 @@ data RequiredInvalid
9695
9796requiredVal :: Required -> HashMap Text Value -> Maybe RequiredInvalid
9897requiredVal r@(Required ts) x
99− -- NOTE: When we no longer need to support GHCs before 7.10
100− -- we can use null from Prelude throughout the library
101− -- instead of specialized versions.
10298 | Set.null ts = Nothing
10399 | Set.null leftovers = Nothing
104100 | otherwise = Just (RequiredInvalid r leftovers x)
@@ -145,7 +141,7 @@ data DependencyMemberInvalid err
145141 | PropertyDepInvalid (Set Text) (HashMap Text Value)
146142 deriving (Eq, Show)
147143
148−data DependenciesInvalid err
144+newtype DependenciesInvalid err
149145 = DependenciesInvalid (HashMap Text (DependencyMemberInvalid err))
150146 deriving (Eq, Show)
151147
src/JSONSchema/Validator/Draft4/Object/Properties.hs+6−6
@@ -1,17 +1,17 @@
1−
21module JSONSchema.Validator.Draft4.Object.Properties where
32
43import Import
54
6−import qualified Data.Hashable as HA
7−import qualified Data.HashMap.Strict as HM
8−import qualified Data.List.NonEmpty as NE
9−import Data.Text.Encoding (encodeUtf8)
10−import qualified JSONPointer as JP
5+import qualified Data.Hashable as HA
6+import qualified Data.HashMap.Strict as HM
7+import qualified Data.List.NonEmpty as NE
8+import Data.Text.Encoding (encodeUtf8)
9+import qualified JSONPointer as JP
1110import qualified Text.Regex.PCRE.Heavy as RE
1211
1312data PropertiesRelated schema = PropertiesRelated
1413 { _propProperties :: Maybe (HashMap Text schema)
14+ -- ^ 'Maybe' is used to distinguish whether the key is present or not.
1515 , _propPattern :: Maybe (HashMap Text schema)
1616 , _propAdditional :: Maybe (AdditionalProperties schema)
1717 } deriving (Eq, Show)
src/JSONSchema/Validator/Draft4/String.hs+2−3
@@ -1,10 +1,9 @@
1−
21module JSONSchema.Validator.Draft4.String where
32
43import Import
54
6−import qualified Data.Text as T
7−import Data.Text.Encoding (encodeUtf8)
5+import qualified Data.Text as T
6+import Data.Text.Encoding (encodeUtf8)
87import qualified Text.Regex.PCRE.Heavy as RE
98
109--------------------------------------------------
src/JSONSchema/Validator/Reference.hs+28−36
@@ -3,42 +3,34 @@
33--
44-- And is extended for JSON Schema here:
55-- <http://json-schema.org/latest/json-schema-core.html#anchor26>
6−
76module JSONSchema.Validator.Reference where
87
98import Import
109
11−import qualified Data.Text as T
12−import Data.Text.Encoding (decodeUtf8, encodeUtf8)
13−import qualified JSONPointer as JP
14−import Network.HTTP.Types.URI (urlDecode)
15−import System.FilePath ((</>), dropFileName)
10+import qualified Data.Text as T
11+import System.FilePath (dropFileName, (</>))
12+
13+data Scope schema = Scope
14+ { _topLevelDocument :: schema
15+ , _documentURI :: Maybe Text
16+ , _currentBaseURI :: BaseURI
17+ } deriving (Eq, Show)
1618
17−-- | TODO: Replace these with actual URI data types.
18−type URIBase = Maybe Text
19−type URIBaseAndFragment = (Maybe Text, Maybe Text)
19+newtype BaseURI
20+ = BaseURI { _unBaseURI :: Maybe Text }
21+ deriving (Eq, Show)
2022
21−updateResolutionScope :: URIBase -> Maybe Text -> URIBase
22−updateResolutionScope mScope idKeyword
23− | Just t <- idKeyword = fst . baseAndFragment $ resolveScopeAgainst mScope t
24− | otherwise = mScope
23+-- | TODO: no `type`s.
24+type URIAndFragment = (Maybe Text, Maybe Text)
2525
26−resolveReference :: URIBase -> Text -> URIBaseAndFragment
27−resolveReference mScope t = baseAndFragment $ resolveScopeAgainst mScope t
26+updateResolutionScope :: BaseURI -> Maybe Text -> BaseURI
27+updateResolutionScope base idKeyword =
28+ case idKeyword of
29+ Just t -> BaseURI . fst . baseAndFragment $ resolveScopeAgainst base t
30+ Nothing -> base
2831
29−resolveFragment
30− :: (FromJSON schema, ToJSON schema)
31− => Maybe Text
32− -> schema
33− -> Maybe schema
34−resolveFragment Nothing schema = Just schema
35−resolveFragment (Just pointer) schema = do
36− let urlDecoded = decodeUtf8 . urlDecode True . encodeUtf8 $ pointer
37− p <- either (const Nothing) Just (JP.unescape urlDecoded)
38− x <- either (const Nothing) Just (JP.resolve p (toJSON schema))
39− case fromJSON x of
40− Error _ -> Nothing
41− Success schema' -> Just schema'
32+resolveReference :: BaseURI -> Text -> URIAndFragment
33+resolveReference base t = baseAndFragment (resolveScopeAgainst base t)
4234
4335--------------------------------------------------
4436-- * Helpers
@@ -47,10 +39,10 @@ resolveFragment (Just pointer) schema = do
4739isRemoteReference :: Text -> Bool
4840isRemoteReference = T.isInfixOf "://"
4941
50−baseAndFragment :: Text -> URIBaseAndFragment
42+baseAndFragment :: Text -> URIAndFragment
5143baseAndFragment = f . T.splitOn "#"
5244 where
53− f :: [Text] -> URIBaseAndFragment
45+ f :: [Text] -> URIAndFragment
5446 f [x] = (g x, Nothing)
5547 f [x,y] = (g x, g y)
5648 f _ = (Nothing, Nothing)
@@ -58,9 +50,9 @@ baseAndFragment = f . T.splitOn "#"
5850 g "" = Nothing
5951 g x = Just x
6052
61−resolveScopeAgainst :: Maybe Text -> Text -> Text
62−resolveScopeAgainst Nothing t = t
63−resolveScopeAgainst (Just scope) t
53+resolveScopeAgainst :: BaseURI -> Text -> Text
54+resolveScopeAgainst (BaseURI Nothing) t = t
55+resolveScopeAgainst (BaseURI (Just base)) t
6456 | isRemoteReference t = t
6557 | otherwise = smartAppend
6658 where
@@ -69,11 +61,11 @@ resolveScopeAgainst (Just scope) t
6961 -- to cut it off before appending.
7062 smartAppend :: Text
7163 smartAppend =
72− case baseAndFragment scope of
73− (Just base,_) ->
64+ case baseAndFragment base of
65+ (Just uri,_) ->
7466 case T.unpack t of
7567 -- We want "/foo" and "#/bar" to combine into
7668 -- "/foo#/bar" not "/foo/#/bar".
7769 '#':_ -> base <> t
78− _ -> T.pack (dropFileName (T.unpack base) </> T.unpack t)
70+ _ -> T.pack (dropFileName (T.unpack uri) </> T.unpack t)
7971 _ -> t
src/JSONSchema/Validator/Types.hs−1
@@ -1,4 +1,3 @@
1−
21module JSONSchema.Validator.Types where
32
43import Import
src/JSONSchema/Validator/Utils.hs+11−27
@@ -1,16 +1,15 @@
1−
21module JSONSchema.Validator.Utils where
32
43import Import
54
6−import Control.Monad (fail)
5+import Control.Monad (fail)
76import qualified Data.HashMap.Strict as HM
8−import qualified Data.List.NonEmpty as NE
9−import Data.Scientific (Scientific, fromFloatDigits)
10−import Data.Set (Set)
11−import qualified Data.Set as S
12−import qualified Data.Text as T
13−import qualified Data.Vector as V
7+import qualified Data.List.NonEmpty as NE
8+import Data.Scientific (Scientific, fromFloatDigits)
9+import Data.Set (Set)
10+import qualified Data.Set as S
11+import qualified Data.Text as T
12+import qualified Data.Vector as V
1413
1514--------------------------------------------------
1615-- * QuickCheck
@@ -83,16 +82,11 @@ instance Arbitrary a => Arbitrary (NonEmpty' a) where
8382-- * allUniqueValues
8483--------------------------------------------------
8584
86−allUniqueValues :: Vector Value -> Bool
87−allUniqueValues = allUnique . fmap OrdValue . V.toList
88−
89−-- NOTE: When we no longer support GHC 7.8 we can generalize
90−-- allUnique to work on any Foldable and remove this function.
91−allUniqueValues' :: NonEmpty Value -> Bool
92−allUniqueValues' = allUnique . fmap OrdValue . NE.toList
85+allUniqueValues :: (Foldable f, Functor f) => f Value -> Bool
86+allUniqueValues = allUnique . fmap OrdValue
9387
94−allUnique :: (Ord a) => [a] -> Bool
95−allUnique xs = S.size (S.fromList xs) == length xs
88+allUnique :: (Foldable f, Ord a) => f a -> Bool
89+allUnique xs = S.size (S.fromList (toList xs)) == length xs
9690
9791-- | OrdValue's Ord instance needs benchmarking, but it allows us to
9892-- use our 'allUnique' function instead of O(n^2) nub, so it's probably
@@ -123,13 +117,3 @@ instance Ord OrdValue where
123117
124118 (OrdValue (Object x)) `compare` (OrdValue (Object y)) =
125119 HM.toList (OrdValue <$> x) `compare` HM.toList (OrdValue <$> y)
126−
127−--------------------------------------------------
128−-- * other
129−--------------------------------------------------
130−
131−fromJSONEither :: FromJSON a => Value -> Either Text a
132−fromJSONEither a =
133− case fromJSON a of
134− Error e -> Left (T.pack e)
135− Success b -> Right b
stack.yamlnew file+2
@@ -0,0 +1,2 @@
1+resolver: lts-10.8
2+pvp-bounds: upper-revision
test/Local.hs+10−14
@@ -1,21 +1,18 @@
1−
21module Main where
32
43import Protolude
54
65import Data.Aeson
76import qualified Data.List.NonEmpty as NE
8−import qualified System.Timeout as TO
7+import qualified System.Timeout as TO
98import Test.Hspec
10−import Test.QuickCheck (property)
9+import Test.QuickCheck (property)
1110
12−import qualified JSONSchema.Draft4 as D4
13−import JSONSchema.Fetch (ReferencedSchemas(..),
14− URISchemaMap(..))
15−import qualified JSONSchema.Types as JT
11+import qualified JSONSchema.Draft4 as D4
12+import qualified JSONSchema.Types as JT
1613import qualified Local.Failure
17−import qualified Local.Validation
1814import qualified Local.Reference
15+import qualified Local.Validation
1916import Shared
2017
2118-- Examples
@@ -35,12 +32,10 @@ main = do
3532 -- Language agnostic tests
3633 ts <- readSchemaTests
3734 dir
38− (\a -> not (isHTTPTest a || skipOptional a))
35+ (\a -> not (isHTTPTest a || skipTest a))
3936
4037 -- Custom supplements to the language agnostic tests
41− supplementTs <- readSchemaTests
42− supplementDir
43− (\a -> not (isHTTPTest a || skipOptional a))
38+ supplementTs <- readSchemaTests supplementDir (not . isHTTPTest)
4439
4540 hspec $ do
4641 describe "Examples" exampleTests
@@ -84,8 +79,9 @@ main = do
8479 Left e -> panic ("Local.validateExample error: " <> show e)
8580 Right schemaMap -> do
8681 let failures = AlternateSchema.validate
87− (ReferencedSchemas s (_unURISchemaMap schemaMap))
88− Nothing s (_scData sc)
82+ schemaMap
83+ (D4.SchemaWithURI s Nothing)
84+ (_scData sc)
8985 assertResult sc failures
9086
9187quickCheckTests :: Spec
test/Local/Failure.hs+6−7
@@ -1,15 +1,14 @@
1−
21module Local.Failure where
32
43import Protolude
54
65import Data.Aeson
6+import qualified Data.Vector as V
7+import qualified JSONPointer as JP
78import Test.Hspec
8−import qualified Data.Vector as V
9−import qualified JSONPointer as JP
109
1110import JSONSchema.Draft4
12−import qualified JSONSchema.Draft4.Spec as Spec
11+import qualified JSONSchema.Draft4.Spec as Spec
1312import qualified JSONSchema.Validator.Draft4 as VAL
1413
1514spec :: Spec
@@ -31,7 +30,7 @@ itemsArray =
3130 ]
3231 where
3332 failures :: [ValidatorFailure]
34− failures = Spec.specValidate (ReferencedSchemas schema mempty) sw badData
33+ failures = Spec.specValidate mempty sw badData
3534
3635 schema :: Schema
3736 schema = emptySchema
@@ -61,7 +60,7 @@ itemsObject =
6160 ]
6261 where
6362 failures :: [ValidatorFailure]
64− failures = Spec.specValidate (ReferencedSchemas schema mempty) sw badData
63+ failures = Spec.specValidate mempty sw badData
6564
6665 schema :: Schema
6766 schema = emptySchema
@@ -89,7 +88,7 @@ loopRef =
8988 ]
9089 where
9190 failures :: [ValidatorFailure]
92− failures = Spec.specValidate (ReferencedSchemas schema mempty) sw badData
91+ failures = Spec.specValidate mempty sw badData
9392
9493 schema :: Schema
9594 schema = emptySchema
test/Local/Reference.hs+12−13
@@ -1,4 +1,3 @@
1−
21module Local.Reference where
32
43import Protolude
@@ -10,28 +9,28 @@ import JSONSchema.Validator.Reference
109spec :: Spec
1110spec = do
1211 it "updateResolutionScope gives correct results" $ do
13− updateResolutionScope Nothing Nothing
14− `shouldBe` Nothing
12+ updateResolutionScope (BaseURI Nothing) Nothing
13+ `shouldBe` BaseURI Nothing
1514
16− updateResolutionScope Nothing (Just "#")
17− `shouldBe` Nothing
15+ updateResolutionScope (BaseURI Nothing) (Just "#")
16+ `shouldBe` BaseURI Nothing
1817
19− updateResolutionScope Nothing (Just "foo")
20− `shouldBe` Just "foo"
18+ updateResolutionScope (BaseURI Nothing) (Just "foo")
19+ `shouldBe` BaseURI (Just "foo")
2120
2221 -- TODO: Normalize after updateResolutionScope:
23− updateResolutionScope (Just "/foo") (Just "./bar")
24− `shouldBe` Just "/./bar"
22+ updateResolutionScope (BaseURI (Just "/foo")) (Just "./bar")
23+ `shouldBe` BaseURI (Just "/./bar")
2524
2625 it "resolveReference gives correct results" $ do
27− resolveReference (Just "/foo") "bar"
26+ resolveReference (BaseURI (Just "/foo")) "bar"
2827 `shouldBe` (Just "/bar", Nothing)
2928
30− resolveReference (Just "/foo/bar") "/baz"
29+ resolveReference (BaseURI (Just "/foo/bar")) "/baz"
3130 `shouldBe` (Just "/baz", Nothing)
3231
33− resolveReference Nothing "#/bar"
32+ resolveReference (BaseURI Nothing) "#/bar"
3433 `shouldBe` (Nothing, Just "/bar")
3534
36− resolveReference (Just "/foo") "#/bar"
35+ resolveReference (BaseURI (Just "/foo")) "#/bar"
3736 `shouldBe` (Just "/foo", Just "/bar")
test/Local/Validation.hs+5−6
@@ -1,17 +1,16 @@
1−
21module Local.Validation where
32
4−import Protolude hiding (msg)
3+import Protolude
54
65import Data.Aeson
7−import qualified Data.Aeson as AE
6+import qualified Data.Aeson as AE
87import qualified Data.HashMap.Strict as HM
9−import Data.String (String)
8+import Data.String (String)
109import Test.Hspec
1110
11+import qualified AlternateSchema as AS
1212import JSONSchema.Draft4
13−import qualified JSONSchema.Types as JT
14−import qualified AlternateSchema as AS
13+import qualified JSONSchema.Types as JT
1514
1615spec :: Spec
1716spec = do
test/Remote.hs+9−11
@@ -1,19 +1,16 @@
1−
21module Main where
32
43import Protolude
54
6−import Control.Concurrent.Async (withAsync)
7−import qualified Data.List.NonEmpty as NE
5+import Control.Concurrent.Async (withAsync)
6+import qualified Data.List.NonEmpty as NE
87import Network.Wai.Application.Static (defaultFileServerSettings,
98 staticApp)
10−import Network.Wai.Handler.Warp (run)
9+import qualified Network.Wai.Handler.Warp as Warp
1110import Test.Hspec
1211
13−import qualified JSONSchema.Draft4 as D4
14−import JSONSchema.Fetch (ReferencedSchemas(..),
15− URISchemaMap(..))
16−import qualified JSONSchema.Types as JT
12+import qualified JSONSchema.Draft4 as D4
13+import qualified JSONSchema.Types as JT
1714import Shared
1815
1916-- Examples
@@ -48,12 +45,13 @@ main = withAsync serve $ \_ -> do
4845 Left e -> panic ("Remote.validateExample error: " <> show e)
4946 Right schemaMap -> do
5047 let failures = AlternateSchema.validate
51− (ReferencedSchemas s (_unURISchemaMap schemaMap))
52− Nothing s (_scData sc)
48+ schemaMap
49+ (D4.SchemaWithURI s Nothing)
50+ (_scData sc)
5351 assertResult sc failures
5452
5553serve :: IO ()
56−serve = run 1234
54+serve = Warp.run 1234
5755 . staticApp
5856 . defaultFileServerSettings
5957 $ "JSON-Schema-Test-Suite/remotes"
test/Shared.hs+21−22
@@ -1,19 +1,29 @@
1−
21module Shared where
32
43import Protolude
54
6−import Control.Monad (fail)
5+import Control.Monad (fail)
76import Data.Aeson
8−import Data.Aeson.TH
9−import qualified Data.ByteString.Lazy as LBS
10−import Data.Char (toLower)
11−import Data.List (stripPrefix, unlines)
12−import qualified Data.Text as T
13−import qualified System.Directory as SD
14−import System.FilePath ((</>))
7+import Data.Aeson.TH (fieldLabelModifier)
8+import qualified Data.ByteString as BS
9+import Data.Char (toLower)
10+import Data.List (stripPrefix, unlines)
11+import qualified Data.Text as T
12+import qualified System.Directory as SD
13+import System.FilePath ((</>))
1514import Test.Hspec
1615
16+skipTest :: FilePath -> Bool
17+skipTest file = (file == "optional/format.json") -- Optional
18+ || (file == "optional/zeroTerminatedFloats.json")
19+ || (file == "optional/ecmascript-regex.json")
20+
21+
22+isHTTPTest :: FilePath -> Bool
23+isHTTPTest file = (file == "definitions.json")
24+ || (file == "ref.json")
25+ || (file == "refRemote.json")
26+
1727-- Recursively return the contents of a directory
1828-- (or return itself if given a file as an argument).
1929--
@@ -37,17 +47,6 @@ listFilesFullPath path = do
3747 fs <- fmap (path </>) <$> SD.listDirectory path
3848 concat <$> traverse listFilesFullPath fs
3949
40−isHTTPTest :: FilePath -> Bool
41−isHTTPTest file = (file == "definitions.json")
42− || (file == "ref.json")
43− || (file == "refRemote.json")
44−
45−-- | We may never support the @"format"@ keywords, and
46−-- are currently failing the zeroTerminatedFloats test.
47−skipOptional :: FilePath -> Bool
48−skipOptional file = (file == "optional/format.json")
49− || (file == "optional/zeroTerminatedFloats.json")
50−
5150data SchemaTest = SchemaTest
5251 { _stDescription :: Text
5352 , _stSchema :: Value
@@ -86,8 +85,8 @@ readSchemaTests dir filterFunc = do
8685 fileToCases :: FilePath -> IO [SchemaTest]
8786 fileToCases name = do
8887 let fullPath = dir </> name
89− jsonBS <- LBS.readFile fullPath
90− case eitherDecode jsonBS of
88+ jsonBS <- BS.readFile fullPath
89+ case eitherDecodeStrict jsonBS of
9190 Left e -> fail $ "couldn't parse file '" <> fullPath <> "': " <> e
9291 Right schemaTests -> pure $ prependFileName name <$> schemaTests
9392