git.iko.soy/typeable/hjsonschema
on master help sign in
.travis.yml+67−56
since splitsnapshots
unifiedsplit
@@ -1,84 +1,95 @@
1+# This Travis job script has been generated by a script via
2+#
3+# make_travis_yml_2.hs 'hjsonschema.cabal'
4+#
1−# Generated by: https://github.com/hvr/multi-ghc-travis
5+# For more information, see https://github.com/hvr/multi-ghc-travis
2#
6#
3−# Removed `cabal check` because I don't want a description field.
4−
5language: c
7language: c
6sudo: false
8sudo: false
7
9
10+git:
11+ submodules: false # whether to recursively clone submodules
12+
8cache:
13cache:
9 directories:
14 directories:
10− - $HOME/.cabsnap
11 - $HOME/.cabal/packages
15 - $HOME/.cabal/packages
16+ - $HOME/.cabal/store
12
17
13before_cache:
18before_cache:
14 - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log
19 - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log
20+ # remove files that are regenerated by 'cabal update'
15− - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.tar
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
16
26
17matrix:
27matrix:
18 include:
28 include:
19− - env: CABALVER=1.18 GHCVER=7.8.4
29+ - compiler: "ghc-8.0.2"
20− compiler: ": #GHC 7.8.4"
30+ # env: TEST=--disable-tests BENCH=--disable-benchmarks
21− addons: {apt: {packages: [cabal-install-1.18,ghc-7.8.4], sources: [hvr-ghc]}}
31+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.0.2], sources: [hvr-ghc]}}
22− - env: CABALVER=1.22 GHCVER=7.10.2
32+ - compiler: "ghc-8.2.2"
23− compiler: ": #GHC 7.10.2"
33+ # env: TEST=--disable-tests BENCH=--disable-benchmarks
24− addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.2], sources: [hvr-ghc]}}
34+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.2.2], sources: [hvr-ghc]}}
25− - env: CABALVER=1.24 GHCVER=8.0.1
35+ - compiler: "ghc-8.4.1"
26− compiler: ": #GHC 8.0.1"
36+ # env: TEST=--disable-tests BENCH=--disable-benchmarks
27− addons: {apt: {packages: [cabal-install-1.24,ghc-8.0.1], sources: [hvr-ghc]}}
37+ addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.4.1], sources: [hvr-ghc]}}
28
38
29before_install:
39before_install:
40+ - HC=${CC}
41+ - HCPKG=${HC/ghc/ghc-pkg}
30 - unset CC
42 - 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'
32
45
33install:
46install:
34 - cabal --version
47 - cabal --version
35− - echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]"
48+ - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
36− - if [ -f $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz ];
49+ - BENCH=${BENCH---enable-benchmarks}
37− then
50+ - TEST=${TEST---enable-tests}
38− zcat $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz >
51+ - HADDOCK=${HADDOCK-true}
39− $HOME/.cabal/packages/hackage.haskell.org/00-index.tar;
52+ - INSTALLED=${INSTALLED-true}
40− fi
41 - travis_retry cabal update -v
53 - travis_retry cabal update -v
42− - sed -i 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config
54+ - sed -i.bak 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config
43− - cabal install --only-dependencies --enable-tests --enable-benchmarks --dry -v > installplan.txt
55+ - rm -fv cabal.project.local
44− - sed -i -e '1,/^Resolving /d' installplan.txt; cat installplan.txt
56+ - "echo 'packages: .' > cabal.project"
45−
57+ - rm -f cabal.project.freeze
46−# check whether current requested install-plan matches cached package-db snapshot
58+ - cabal new-build -w ${HC} ${TEST} ${BENCH} --dep -j2 all
47− - if diff -u installplan.txt $HOME/.cabsnap/installplan.txt;
59+ - cabal new-build -w ${HC} --disable-tests --disable-benchmarks --dep -j2 all
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
68
60
69# Here starts the actual work to be performed for the package under test;
61# Here starts the actual work to be performed for the package under test;
70# any command which exits with a non-zero exit code causes the build to fail.
62# any command which exits with a non-zero exit code causes the build to fail.
71script:
63script:
72 - if [ -f configure.ac ]; then autoreconf -i; fi
64 - if [ -f configure.ac ]; then autoreconf -i; fi
73− - cabal configure --enable-tests --enable-benchmarks -v2 # -v2 provides useful information for debugging
65+ - rm -rf .ghc.environment.* dist/
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
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
77
89
78−# Check that the resulting source distribution can be built & installed.
90+ # haddock
79−# If there are no other `.tar.gz` files in `dist`, this can be even simpler:
91+ - rm -rf ./dist-newstyle
80−# `cabal install --force-reinstalls dist/*-*.tar.gz`
92+ - if $HADDOCK; then cabal new-haddock -w ${HC} --disable-tests --disable-benchmarks all; else echo "Skipping haddock generation";fi
81− - SRC_TGZ=$(cabal info . | awk '{print $2;exit}').tar.gz &&
82− (cd dist && cabal install --force-reinstalls "$SRC_TGZ")
83
93
94+# REGENDATA ["hjsonschema.cabal"]
84# EOF
95# EOF
JSON-Schema-Test-Suite/.travis.yml+7−2
@@ -1,4 +1,9 @@
1language: python
1language: python
2python: "2.7"
2python: "2.7"
3+node_js: "6"
4+install:
3−install: pip install tox
5+ - pip install tox
6+ - npm install
4−script: tox
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)
2======================
2======================
3
3
4This repository contains a set of JSON objects that implementors of JSON Schema
4This repository contains a set of JSON objects that implementors of JSON Schema
@@ -64,10 +64,18 @@ This suite is being used by:
64
64
65* [jsck](https://github.com/pandastrike/jsck)
65* [jsck](https://github.com/pandastrike/jsck)
66
66
67+### C++ ###
68+
69+* [Modern C++ JSON schema validator](https://github.com/pboettch/json-schema-validator)
70+
67### Dart ###
71### Dart ###
68
72
69* [json_schema](https://github.com/patefacio/json_schema)
73* [json_schema](https://github.com/patefacio/json_schema)
70
74
75+### Elixir ###
76+
77+* [ex_json_schema](https://github.com/jonasschmidt/ex_json_schema)
78+
71### Erlang ###
79### Erlang ###
72
80
73* [jesse](https://github.com/klarna/jesse)
81* [jesse](https://github.com/klarna/jesse)
@@ -84,7 +92,9 @@ This suite is being used by:
84
92
85### Java ###
93### Java ###
86
94
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)
88
98
89### JavaScript ###
99### JavaScript ###
90
100
@@ -102,22 +112,25 @@ This suite is being used by:
102* [z-schema](https://github.com/zaggino/z-schema)
112* [z-schema](https://github.com/zaggino/z-schema)
103* [jsen](https://github.com/bugventure/jsen)
113* [jsen](https://github.com/bugventure/jsen)
104* [ajv](https://github.com/epoberezkin/ajv)
114* [ajv](https://github.com/epoberezkin/ajv)
115+* [djv](https://github.com/korzio/djv)
105
116
106### Node.js ###
117### Node.js ###
107
118
108The JSON Schema Test Suite is also available as an
119The JSON Schema Test Suite is also available as an
109[npm](https://www.npmjs.com/package/json-schema-test-suite) package.
120[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).
121+Node-specific support is maintained on the [node branch](https://github.com/json-schema-org/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)
122+See [NODE-README.md](https://github.com/json-schema-org/JSON-Schema-Test-Suite/blob/node/NODE-README.md)
112for more information.
123for more information.
113
124
114### .NET ###
125### .NET ###
115
126
116* [Newtonsoft.Json.Schema](https://github.com/JamesNK/Newtonsoft.Json.Schema)
127* [Newtonsoft.Json.Schema](https://github.com/JamesNK/Newtonsoft.Json.Schema)
128+* [Manatee.Json](https://github.com/gregsdennis/Manatee.Json)
117
129
118### PHP ###
130### PHP ###
119
131
120* [json-schema](https://github.com/justinrainbow/json-schema)
132* [json-schema](https://github.com/justinrainbow/json-schema)
133+* [json-guard](https://github.com/thephpleague/json-guard)
121
134
122### Python ###
135### Python ###
123
136
@@ -135,6 +148,14 @@ for more information.
135
148
136* [JSONSchema](https://github.com/kylef/JSONSchema.swift)
149* [JSONSchema](https://github.com/kylef/JSONSchema.swift)
137
150
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+
138If you use it as well, please fork and send a pull request adding yourself to
159If you use it as well, please fork and send a pull request adding yourself to
139the list :).
160the list :).
140
161
@@ -144,5 +165,5 @@ Contributing
144If you see something missing or incorrect, a pull request is most welcome!
165If you see something missing or incorrect, a pull request is most welcome!
145
166
146There are some sanity checks in place for testing the test suite. You can run
167There 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
148[Travis CI](https://travis-ci.org/) as well.
169[Travis CI](https://travis-ci.org/) as well.
JSON-Schema-Test-Suite/bin/jsonschema_suite+2−27
@@ -52,33 +52,8 @@ REMOTES = {
52}
52}
53REMOTES_DIR = os.path.join(ROOT_DIR, "remotes")
53REMOTES_DIR = os.path.join(ROOT_DIR, "remotes")
54
54
55+with open(os.path.join(ROOT_DIR, "test-schema.json")) as schema:
55−TESTSUITE_SCHEMA = {
56+ TESTSUITE_SCHEMA = json.load(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−
82
57
83def files(paths):
58def files(paths):
84 for path in paths:
59 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 @@
78 "valid": true
78 "valid": true
79 },
79 },
80 {
80 {
81− "description": "a valid protocol-relative URI",
81+ "description": "an invalid protocol-relative URI Reference",
82 "data": "//foo.bar/?baz=qux#quux",
82 "data": "//foo.bar/?baz=qux#quux",
83− "valid": true
83+ "valid": false
84 },
84 },
85 {
85 {
86 "description": "an invalid URI",
86 "description": "an invalid URI",
JSON-Schema-Test-Suite/tests/draft3/ref.json+33
@@ -140,6 +140,39 @@
140 }
140 }
141 ]
141 ]
142 },
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": "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+ },
143 {
176 {
144 "description": "remote ref, containing refs itself",
177 "description": "remote ref, containing refs itself",
145 "schema": {"$ref": "http://json-schema.org/draft-03/schema#"},
178 "schema": {"$ref": "http://json-schema.org/draft-03/schema#"},
JSON-Schema-Test-Suite/tests/draft3/type.json+15
@@ -18,6 +18,11 @@
18 "data": "foo",
18 "data": "foo",
19 "valid": false
19 "valid": false
20 },
20 },
21+ {
22+ "description": "a string is still not an integer, even if it looks like one",
23+ "data": "1",
24+ "valid": false
25+ },
21 {
26 {
22 "description": "an object is not an integer",
27 "description": "an object is not an integer",
23 "data": {},
28 "data": {},
@@ -59,6 +64,11 @@
59 "data": "foo",
64 "data": "foo",
60 "valid": false
65 "valid": false
61 },
66 },
67+ {
68+ "description": "a string is still not a number, even if it looks like one",
69+ "data": "1",
70+ "valid": false
71+ },
62 {
72 {
63 "description": "an object is not a number",
73 "description": "an object is not a number",
64 "data": {},
74 "data": {},
@@ -100,6 +110,11 @@
100 "data": "foo",
110 "data": "foo",
101 "valid": true
111 "valid": true
102 },
112 },
113+ {
114+ "description": "a string is still a string, even if it looks like a number",
115+ "data": "1",
116+ "valid": true
117+ },
103 {
118 {
104 "description": "an object is not a string",
119 "description": "an object is not a string",
105 "data": {},
120 "data": {},
JSON-Schema-Test-Suite/tests/draft4/additionalItems.json+6−1
@@ -40,7 +40,12 @@
40 },
40 },
41 "tests": [
41 "tests": [
42 {
42 {
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",
44 "data": [ 1, 2, 3 ],
49 "data": [ 1, 2, 3 ],
45 "valid": true
50 "valid": true
46 },
51 },
JSON-Schema-Test-Suite/tests/draft4/items.json+32
@@ -19,6 +19,14 @@
19 "description": "ignores non-arrays",
19 "description": "ignores non-arrays",
20 "data": {"foo" : "bar"},
20 "data": {"foo" : "bar"},
21 "valid": true
21 "valid": true
22+ },
23+ {
24+ "description": "JavaScript pseudo-array is valid",
25+ "data": {
26+ "0": "invalid",
27+ "length": 1
28+ },
29+ "valid": true
22 }
30 }
23 ]
31 ]
24 },
32 },
@@ -40,6 +48,30 @@
40 "description": "wrong types",
48 "description": "wrong types",
41 "data": [ "foo", 1 ],
49 "data": [ "foo", 1 ],
42 "valid": false
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
43 }
75 }
44 ]
76 ]
45 }
77 }
JSON-Schema-Test-Suite/tests/draft4/maximum.json+5
@@ -8,6 +8,11 @@
8 "data": 2.6,
8 "data": 2.6,
9 "valid": true
9 "valid": true
10 },
10 },
11+ {
12+ "description": "boundary point is valid",
13+ "data": 3.0,
14+ "valid": true
15+ },
11 {
16 {
12 "description": "above the maximum is invalid",
17 "description": "above the maximum is invalid",
13 "data": 3.5,
18 "data": 3.5,
JSON-Schema-Test-Suite/tests/draft4/minimum.json+5
@@ -8,6 +8,11 @@
8 "data": 2.6,
8 "data": 2.6,
9 "valid": true
9 "valid": true
10 },
10 },
11+ {
12+ "description": "boundary point is valid",
13+ "data": 1.1,
14+ "valid": true
15+ },
11 {
16 {
12 "description": "below the minimum is invalid",
17 "description": "below the minimum is invalid",
13 "data": 0.6,
18 "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 @@
30 "valid": true
30 "valid": true
31 },
31 },
32 {
32 {
33− "description": "a valid protocol-relative URI",
33+ "description": "an invalid protocol-relative URI Reference",
34 "data": "//foo.bar/?baz=qux#quux",
34 "data": "//foo.bar/?baz=qux#quux",
35− "valid": true
35+ "valid": false
36 },
36 },
37 {
37 {
38 "description": "an invalid URI",
38 "description": "an invalid URI",
JSON-Schema-Test-Suite/tests/draft4/ref.json+139
@@ -140,6 +140,39 @@
140 }
140 }
141 ]
141 ]
142 },
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+ },
143 {
176 {
144 "description": "remote ref, containing refs itself",
177 "description": "remote ref, containing refs itself",
145 "schema": {"$ref": "http://json-schema.org/draft-04/schema#"},
178 "schema": {"$ref": "http://json-schema.org/draft-04/schema#"},
@@ -155,5 +188,111 @@
155 "valid": false
188 "valid": false
156 }
189 }
157 ]
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": "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+ ]
158 }
297 }
159]
298]
JSON-Schema-Test-Suite/tests/draft4/refRemote.json+100−3
@@ -50,7 +50,7 @@
50 ]
50 ]
51 },
51 },
52 {
52 {
53− "description": "change resolution scope",
53+ "description": "base URI change",
54 "schema": {
54 "schema": {
55 "id": "http://localhost:1234/",
55 "id": "http://localhost:1234/",
56 "items": {
56 "items": {
@@ -60,15 +60,112 @@
60 },
60 },
61 "tests": [
61 "tests": [
62 {
62 {
63− "description": "changed scope ref valid",
63+ "description": "base URI change ref valid",
64 "data": [[1]],
64 "data": [[1]],
65 "valid": true
65 "valid": true
66 },
66 },
67 {
67 {
68− "description": "changed scope ref invalid",
68+ "description": "base URI change ref invalid",
69 "data": [["a"]],
69 "data": [["a"]],
70 "valid": false
70 "valid": false
71 }
71 }
72 ]
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+ ]
73 }
170 }
74]
171]
JSON-Schema-Test-Suite/tests/draft4/required.json+5
@@ -18,6 +18,11 @@
18 "description": "non-present required property is invalid",
18 "description": "non-present required property is invalid",
19 "data": {"bar": 1},
19 "data": {"bar": 1},
20 "valid": false
20 "valid": false
21+ },
22+ {
23+ "description": "ignores non-objects",
24+ "data": 12,
25+ "valid": true
21 }
26 }
22 ]
27 ]
23 },
28 },
JSON-Schema-Test-Suite/tests/draft4/type.json+15
@@ -18,6 +18,11 @@
18 "data": "foo",
18 "data": "foo",
19 "valid": false
19 "valid": false
20 },
20 },
21+ {
22+ "description": "a string is still not an integer, even if it looks like one",
23+ "data": "1",
24+ "valid": false
25+ },
21 {
26 {
22 "description": "an object is not an integer",
27 "description": "an object is not an integer",
23 "data": {},
28 "data": {},
@@ -59,6 +64,11 @@
59 "data": "foo",
64 "data": "foo",
60 "valid": false
65 "valid": false
61 },
66 },
67+ {
68+ "description": "a string is still not a number, even if it looks like one",
69+ "data": "1",
70+ "valid": false
71+ },
62 {
72 {
63 "description": "an object is not a number",
73 "description": "an object is not a number",
64 "data": {},
74 "data": {},
@@ -100,6 +110,11 @@
100 "data": "foo",
110 "data": "foo",
101 "valid": true
111 "valid": true
102 },
112 },
113+ {
114+ "description": "a string is still a string, even if it looks like a number",
115+ "data": "1",
116+ "valid": true
117+ },
103 {
118 {
104 "description": "an object is not a string",
119 "description": "an object is not a string",
105 "data": {},
120 "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
2
2
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).
4
4
5−[Hackage](https://hackage.haskell.org/package/hjsonschema) / [GitHub](https://github.com/seagreen/hjsonschema) / [Travis CI](https://travis-ci.org/seagreen/hjsonschema)
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.
6−
7−# Notes
8
6
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.
10
8
11−+ Requires [pcre](http://www.pcre.org/) (`pkgs.pcre` in Nixpkgs).
9+# Links
12
10
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)
14
12
15# Example
13# Example
16
14
17See [here](https://github.com/seagreen/hjsonschema/blob/master/examples/Simple.hs).
15See [here](https://github.com/seagreen/hjsonschema/blob/master/examples/Simple.hs).
18
16
19−# Tests
17+# System dependencies
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
36
18
37−+ Be a correct and fast implementation of the spec.
19++ Requires [pcre](http://www.pcre.org/) (`pkgs.pcre` in Nixpkgs).
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.
52
20
53## Vendoring
21## Vendoring
54
22
55−+ `JSON-Schema-Test-Suite` is vendored from commit # aabcb3427745ade7a0b4d49ff016ad7eda8b898b [here](https://github.com/json-schema-org/JSON-Schema-Test-Suite).
23++ `JSON-Schema-Test-Suite` is vendored from commit # c1b12bf699f29a04b4286711c6e3bbfba66f21e5 [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.
64
24
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+
1+ Report details of `"required"` validator failure.
57+ Report details of `"required"` validator failure.
58++ Bump `directory`.
2
59
3# 1.4.0.0
60# 1.4.0.0
4
61
examples/AlternateSchema.hs+87−60
@@ -5,28 +5,24 @@
5-- to copy this module instead of the 'JSONSchema.Draft4'. While it's
5-- to copy this module instead of the 'JSONSchema.Draft4'. While it's
6-- less convenient to write schemas in Haskell without a record type, you
6-- less convenient to write schemas in Haskell without a record type, you
7-- can get the implementation finished with far fewer lines of code.
7-- can get the implementation finished with far fewer lines of code.
8−
9module AlternateSchema where
8module AlternateSchema where
10
9
11import Protolude
10import Protolude
12
11
13−import Data.Aeson (FromJSON(..), Value(..),
12+import Data.Aeson (FromJSON(..), Value(..), decodeStrict)
14− decode)
15−import qualified Data.Aeson as AE
13+import qualified Data.Aeson as AE
16−import qualified Data.ByteString.Lazy as LBS
14+import qualified Data.HashMap.Strict as HM
17−import qualified Data.HashMap.Strict as HM
18−import Data.Maybe (fromMaybe)
15+import Data.Maybe (fromMaybe)
19−import Data.Profunctor (Profunctor (..))
16+import Data.Profunctor (Profunctor(..))
20−
17+
21−import JSONSchema.Draft4 (ValidatorFailure(..),
18+import JSONSchema.Draft4 (ValidatorFailure(..), metaSchemaBytes)
22− metaSchemaBytes)
23−import JSONSchema.Fetch (ReferencedSchemas(..),
19+import JSONSchema.Fetch (SchemaWithURI(..), URISchemaMap(..))
24− SchemaWithURI(..))
25−import qualified JSONSchema.Fetch as FE
20+import qualified JSONSchema.Fetch as FE
26−import JSONSchema.Types (Schema(..), Spec(..))
21+import JSONSchema.Types (Schema(..), Spec(..))
27−import qualified JSONSchema.Types as JT
22+import qualified JSONSchema.Types as JT
28−import qualified JSONSchema.Validator.Draft4 as D4
23+import qualified JSONSchema.Validator.Draft4 as D4
29−import JSONSchema.Validator.Reference (updateResolutionScope)
24+import JSONSchema.Validator.Reference (BaseURI(..), Scope(..),
25+ updateResolutionScope)
30
26
31--------------------------------------------------
27--------------------------------------------------
32-- * Basic fetching tools
28-- * Basic fetching tools
@@ -46,72 +42,97 @@ draft4FetchInfo = FE.FetchInfo embedded (lookup "id") (lookup "$ref")
46 Just (String t) -> Just t
42 Just (String t) -> Just t
47 _ -> Nothing
43 _ -> Nothing
48
44
45+-- | An implementation of 'JT.embedded'.
49embedded :: Schema -> ([Schema], [Schema])
46embedded :: Schema -> ([Schema], [Schema])
47+embedded s =
50−embedded s = JT.embedded (d4Spec (ReferencedSchemas s mempty) mempty Nothing) s
48+ JT.embedded (d4Spec mempty mempty (Scope s Nothing (BaseURI Nothing))) s
51
49
52--------------------------------------------------
50--------------------------------------------------
53-- * Main API
51-- * Main API
54--------------------------------------------------
52--------------------------------------------------
55
53
56validate
54validate
57− :: ReferencedSchemas Schema
55+ :: URISchemaMap Schema
58− -> Maybe Text
59− -> Schema
56+ -> SchemaWithURI Schema
60 -> Value
57 -> Value
61 -> [ValidatorFailure]
58 -> [ValidatorFailure]
59+validate schemaMap sw =
60+ JT.validate (d4Spec schemaMap visited scope) (_swSchema sw)
61+ where
62+ visited :: D4.VisitedSchemas
62−validate rs = continueValidating rs (D4.VisitedSchemas [(Nothing, Nothing)])
63+ visited = D4.VisitedSchemas [(Nothing, Nothing)]
63
64
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+
64−-- A schema for schemas themselves, using @src/draft4.json@ which is loaded
76+-- | A schema for schemas themselves. Uses @src/draft4.json@ which is loaded
65-- at compile time.
77-- at compile time.
66metaSchema :: Schema
78metaSchema :: Schema
67metaSchema =
79metaSchema =
68 fromMaybe (panic "Schema decode failed (this should never happen)")
80 fromMaybe (panic "Schema decode failed (this should never happen)")
69− . decode
81+ . decodeStrict
70− . LBS.fromStrict
71 $ metaSchemaBytes
82 $ metaSchemaBytes
72
83
73checkSchema :: Schema -> [ValidatorFailure]
84checkSchema :: Schema -> [ValidatorFailure]
74−checkSchema = validate referenced Nothing metaSchema . Object . _unSchema
85+checkSchema = validate schemaMap (SchemaWithURI metaSchema Nothing)
86+ . Object
87+ . _unSchema
75 where
88 where
76− referenced :: ReferencedSchemas Schema
89+ schemaMap :: URISchemaMap Schema
77− referenced = ReferencedSchemas
90+ schemaMap =
78− metaSchema
79− (HM.singleton "http://json-schema.org/draft-04/schema"
91+ URISchemaMap (HM.singleton "http://json-schema.org/draft-04/schema"
80 metaSchema)
92 metaSchema)
81
93
82--------------------------------------------------
94--------------------------------------------------
83-- * Spec
95-- * Spec
84--------------------------------------------------
96--------------------------------------------------
85
97
86−continueValidating
98+validateSubschema
87− :: ReferencedSchemas Schema
99+ :: URISchemaMap Schema
88 -> D4.VisitedSchemas
100 -> D4.VisitedSchemas
89− -> Maybe Text
101+ -> Scope Schema
90 -> Schema
102 -> Schema
91 -> Value
103 -> Value
92 -> [ValidatorFailure]
104 -> [ValidatorFailure]
93−continueValidating referenced visited mURI sc =
105+validateSubschema schemaMap visited scope schema =
94− JT.validate (d4Spec referenced visited newScope) sc
106+ JT.validate (d4Spec schemaMap visited newScope) schema
95 where
107 where
96 schemaId :: Maybe Text
108 schemaId :: Maybe Text
97− schemaId = case HM.lookup "id" (_unSchema sc) of
109+ schemaId = FE._fiId draft4FetchInfo schema
98− Just (String t) -> Just t
99− _ -> Nothing
100
110
101− newScope :: Maybe Text
111+ newScope :: Scope Schema
112+ newScope = scope
102− newScope = updateResolutionScope mURI schemaId
113+ { _currentBaseURI = updateResolutionScope (_currentBaseURI scope)
114+ schemaId
115+ }
103
116
104d4Spec
117d4Spec
105− :: ReferencedSchemas Schema
118+ :: URISchemaMap Schema
106 -> D4.VisitedSchemas
119 -> D4.VisitedSchemas
107− -> Maybe Text
120+ -> Scope Schema
108 -> Spec Schema ValidatorFailure
121 -> Spec Schema ValidatorFailure
109 -- ^ Here we reuses 'ValidatorFailure' from
122 -- ^ Here we reuses 'ValidatorFailure' from
110 -- 'JSONSchema.Draft4.Failure'. If your validators have different
123 -- 'JSONSchema.Draft4.Failure'. If your validators have different
111 -- failure possibilities you'll need to create your own validator
124 -- failure possibilities you'll need to create your own validator
112 -- failure type.
125 -- failure type.
113−d4Spec referenced visited scope =
126+d4Spec schemaMap visited scope =
114− Spec
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)
115 [ dimap f FailureMultipleOf D4.multipleOfValidator
136 [ dimap f FailureMultipleOf D4.multipleOfValidator
116 , dimap f FailureMaximum D4.maximumValidator
137 , dimap f FailureMaximum D4.maximumValidator
117 , dimap f FailureMinimum D4.minimumValidator
138 , dimap f FailureMinimum D4.minimumValidator
@@ -129,6 +150,7 @@ d4Spec referenced visited scope =
129 D4.IRInvalidItems e -> FailureItems e
150 D4.IRInvalidItems e -> FailureItems e
130 D4.IRInvalidAdditional e -> FailureAdditionalItems e)
151 D4.IRInvalidAdditional e -> FailureAdditionalItems e)
131 (D4.itemsRelatedValidator descend)
152 (D4.itemsRelatedValidator descend)
153+ , lmap f D4.definitionsEmbedded
132
154
133 , dimap f FailureMaxProperties D4.maxPropertiesValidator
155 , dimap f FailureMaxProperties D4.maxPropertiesValidator
134 , dimap f FailureMinProperties D4.minPropertiesValidator
156 , dimap f FailureMinProperties D4.minPropertiesValidator
@@ -139,10 +161,6 @@ d4Spec referenced visited scope =
139 FailurePropertiesRelated
161 FailurePropertiesRelated
140 (D4.propertiesRelatedValidator descend)
162 (D4.propertiesRelatedValidator descend)
141
163
142− , dimap
143− f
144− FailureRef
145− (D4.refValidator visited scope (FE.getReference referenced) getRef)
146 , dimap f FailureEnum D4.enumValidator
164 , dimap f FailureEnum D4.enumValidator
147 , dimap f FailureType D4.typeValidator
165 , dimap f FailureType D4.typeValidator
148 , dimap f FailureAllOf (D4.allOfValidator lateral)
166 , dimap f FailureAllOf (D4.allOfValidator lateral)
@@ -152,22 +170,31 @@ d4Spec referenced visited scope =
152 ]
170 ]
153 where
171 where
154 f :: FromJSON a => Schema -> Maybe a
172 f :: FromJSON a => Schema -> Maybe a
173+ f (Schema a) =
155− f (Schema a) = case AE.fromJSON (Object a) of
174+ case AE.fromJSON (Object a) of
156− AE.Error _ -> Nothing
175+ AE.Error _ -> Nothing
157− AE.Success b -> Just b
176+ AE.Success b -> Just b
158−
177+
159− -- 'Maybe Text' is the URI the referenced schema is fetched from,
178+ disableIfRefPresent :: Schema -> Schema
160− -- this probably needs a 'newtype' wrapper.
179+ disableIfRefPresent schema =
161− getRef
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
162 :: D4.VisitedSchemas
189 :: D4.VisitedSchemas
163− -> Maybe Text
190+ -> Scope Schema
164 -> Schema
191 -> Schema
165 -> Value
192 -> Value
166 -> [ValidatorFailure]
193 -> [ValidatorFailure]
167− getRef = continueValidating referenced
194+ valRef vis sc = JT.validate (d4Spec schemaMap vis sc)
168
195
169 descend :: Schema -> Value -> [ValidatorFailure]
196 descend :: Schema -> Value -> [ValidatorFailure]
170− descend = continueValidating referenced mempty scope
197+ descend = validateSubschema schemaMap mempty scope
171
198
172 lateral :: Schema -> Value -> [ValidatorFailure]
199 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−
2module Simple where
1module Simple where
3
2
4import Protolude
3import Protolude
5
4
6−import Data.Aeson (Value(..), decode, toJSON)
5+import Data.Aeson (Value(..), decodeStrict, toJSON)
7−import qualified Data.ByteString.Lazy as LBS
6+import qualified Data.ByteString as BS
8−import qualified Data.List.NonEmpty as NE
7+import qualified Data.List.NonEmpty as NE
9−import Data.Maybe (fromMaybe)
8+import Data.Maybe (fromMaybe)
10
9
11−import qualified JSONSchema.Draft4 as D4
10+import qualified JSONSchema.Draft4 as D4
12
11
13badData :: Value
12badData :: Value
14badData = toJSON [True, True]
13badData = toJSON [True, True]
15
14
16example :: IO ()
15example :: IO ()
17example = do
16example = do
18− bts <- LBS.readFile "./examples/json/unique.json"
17+ bts <- BS.readFile "./examples/json/unique.json"
19− let schema = fromMaybe (panic "Invalid schema JSON.") (decode bts)
18+ let schema = fromMaybe (panic "Invalid schema JSON.") (decodeStrict bts)
20 schemaWithURI = D4.SchemaWithURI
19 schemaWithURI = D4.SchemaWithURI
21 schema
20 schema
22 Nothing -- This would be the URI of the schema
21 Nothing -- This would be the URI of the schema
examples/TwoStep.hs+3−4
@@ -10,15 +10,14 @@
10-- 'fetchHTTPAndValidate' which fetched references over HTTP (though it
10-- 'fetchHTTPAndValidate' which fetched references over HTTP (though it
11-- didn't matter because the last schema didn't actually have any).
11-- didn't matter because the last schema didn't actually have any).
12-- This time we need to get them from the filesystem.
12-- This time we need to get them from the filesystem.
13−
14module TwoStep where
13module TwoStep where
15
14
16import Protolude
15import Protolude
17
16
18−import Data.Aeson (Value (..), toJSON)
17+import Data.Aeson (Value(..), toJSON)
19−import qualified Data.List.NonEmpty as NE
18+import qualified Data.List.NonEmpty as NE
20
19
21−import qualified JSONSchema.Draft4 as D4
20+import qualified JSONSchema.Draft4 as D4
22import qualified JSONSchema.Validator.Draft4 as VAL
21import qualified JSONSchema.Validator.Draft4 as VAL
23
22
24schema :: D4.Schema
23schema :: D4.Schema
hjsonschema.cabal+25−29
@@ -1,5 +1,5 @@
1name: hjsonschema
1name: hjsonschema
2−version: 1.4.0.0
2+version: 1.9.0
3synopsis: JSON Schema library
3synopsis: JSON Schema library
4homepage: https://github.com/seagreen/hjsonschema
4homepage: https://github.com/seagreen/hjsonschema
5license: MIT
5license: MIT
@@ -9,6 +9,8 @@ maintainer: ian@housejeffries.com
9category: Data
9category: Data
10build-type: Simple
10build-type: Simple
11cabal-version: >=1.10
11cabal-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
12extra-source-files:
14extra-source-files:
13 changelog.md
15 changelog.md
14 JSON-Schema-Test-Suite/remotes/*.json
16 JSON-Schema-Test-Suite/remotes/*.json
@@ -32,7 +34,6 @@ library
32 NoImplicitPrelude
34 NoImplicitPrelude
33 OverloadedStrings
35 OverloadedStrings
34 ScopedTypeVariables
36 ScopedTypeVariables
35− TupleSections
36 if impl(ghc >= 8)
37 if impl(ghc >= 8)
37 default-extensions: StrictData
38 default-extensions: StrictData
38 ghc-options:
39 ghc-options:
@@ -57,27 +58,28 @@ library
57 JSONSchema.Validator.Draft4.Object.Properties
58 JSONSchema.Validator.Draft4.Object.Properties
58 , Import
59 , Import
59 build-depends:
60 build-depends:
60− base >= 4.7 && < 4.10
61+ base >= 4.7 && < 5
61 -- 0.11 is for `.:!`:
62 -- 0.11 is for `.:!`:
62− , aeson >= 0.11 && < 1.2
63+ , aeson >= 0.11
63− , bytestring >= 0.10 && < 0.11
64+ , bytestring >= 0.10
64− , containers >= 0.5 && < 0.6
65+ , containers >= 0.5
65− , file-embed >= 0.0.8 && < 0.1
66+ , file-embed >= 0.0.8
66− , filepath >= 1.3 && < 1.5
67+ , filepath >= 1.3
67− , hashable >= 1.2 && < 1.3
68+ , hashable >= 1.2
68− , hjsonpointer >= 1.1 && < 1.2
69+ , hjsonpointer >= 1.1
69 -- 0.4.30 is for parseUrlThrow:
70 -- 0.4.30 is for parseUrlThrow:
70− , http-client >= 0.4.30 && < 0.6
71+ , http-client >= 0.4.30
72+ , http-client-tls >= 0.3
71− , http-types >= 0.8 && < 0.10
73+ , http-types >= 0.8
72− , pcre-heavy >= 1.0 && < 1.1
74+ , pcre-heavy >= 1.0
73− , profunctors >= 5.0 && < 5.3
75+ , profunctors >= 5.0
74− , protolude >= 0.1.10 && < 1.2
76+ , protolude >= 0.1.10
75− , QuickCheck >= 2.8 && < 2.10
77+ , QuickCheck >= 2.8
78+ , safe-exceptions >= 0.1.6
76− , scientific >= 0.3 && < 0.4
79+ , scientific >= 0.3
77− , semigroups >= 0.18 && < 0.19
78− , unordered-containers >= 0.2 && < 0.3
80+ , unordered-containers >= 0.2
79− , text >= 1.1 && < 1.3
81+ , text >= 1.1
80− , vector >= 0.10 && < 1.0
82+ , vector >= 0.10
81
83
82test-suite local
84test-suite local
83 hs-source-dirs:
85 hs-source-dirs:
@@ -112,15 +114,14 @@ test-suite local
112 , hjsonschema
114 , hjsonschema
113 , profunctors
115 , profunctors
114 , protolude
116 , protolude
115− , semigroups
116 , text
117 , text
117 , QuickCheck
118 , QuickCheck
118 , unordered-containers
119 , unordered-containers
119 , vector
120 , vector
120
121
121 -- directory-1.2.5 required for `listDirectory`:
122 -- directory-1.2.5 required for `listDirectory`:
122− , directory >= 1.2.5 && < 1.3
123+ , directory >= 1.2.5
123− , hspec >= 2.2 && < 2.4
124+ , hspec >= 2.2
124
125
125test-suite remote
126test-suite remote
126 hs-source-dirs:
127 hs-source-dirs:
@@ -151,7 +152,6 @@ test-suite remote
151 , hjsonschema
152 , hjsonschema
152 , profunctors
153 , profunctors
153 , protolude
154 , protolude
154− , semigroups
155 , text
155 , text
156 , unordered-containers
156 , unordered-containers
157 , vector
157 , vector
@@ -160,7 +160,3 @@ test-suite remote
160 , hspec
160 , hspec
161 , wai-app-static
161 , wai-app-static
162 , warp
162 , 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}:
1with (import <nixpkgs> {});
2with (import <nixpkgs> {});
2
3
3haskell.lib.buildStackProject {
4haskell.lib.buildStackProject {
4 name = "none";
5 name = "none";
5 inherit ghc;
6 inherit ghc;
6 buildInputs = [
7 buildInputs = [
7− pkgconfig
8 pcre
8 pcre
9
9
10− # for `git:` references in stack.yml:
10+ git # for `git:` references in stack.yml.
11− git
11+ ncurses # for intero
12+ pkgconfig
13+ zlib
12 ];
14 ];
13}
15}
src/Import.hs+15−8
@@ -1,12 +1,19 @@
1
1
2−module Import (module Export) where
2+module Import (module Export, fromJSONEither) where
3
3
4−import Protolude as Export
4+import Protolude as Export
5
5
6−import Data.Aeson as Export
6+import Data.Aeson as Export
7import Data.HashMap.Strict as Export (HashMap)
7import 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)
8+import Data.List.NonEmpty as Export (NonEmpty)
10−import Data.Vector as Export (Vector)
9+import Data.Vector as Export (Vector)
11−import Test.QuickCheck as Export hiding ((.&.), Failure,
10+import Test.QuickCheck as Export hiding (Failure, Result, Success,
12− 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
22 , ValidatorFailure(..)
22 , ValidatorFailure(..)
23
23
24 -- * Fetching tools
24 -- * Fetching tools
25− , ReferencedSchemas(..)
26− , FE.URISchemaMap(..)
25+ , URISchemaMap(..)
27 , referencesViaHTTP
26 , referencesViaHTTP
28 , referencesViaFilesystem
27 , referencesViaFilesystem
29
28
@@ -38,23 +37,19 @@ module JSONSchema.Draft4
38
37
39import Import
38import Import
40
39
41−import Control.Arrow (left)
42−import qualified Data.ByteString as BS
40+import qualified Data.ByteString as BS
43−import Data.FileEmbed (embedFile,
41+import Data.FileEmbed (embedFile, makeRelativeToProject)
44− makeRelativeToProject)
45−import qualified Data.HashMap.Strict as HM
42+import qualified Data.HashMap.Strict as HM
46−import qualified Data.List.NonEmpty as NE
43+import qualified Data.List.NonEmpty as NE
47−import Data.Maybe (fromMaybe)
44+import Data.Maybe (fromMaybe)
48
45
49−import JSONSchema.Draft4.Failure (Invalid(..),
46+import JSONSchema.Draft4.Failure (Invalid(..), SchemaInvalid(..),
50− SchemaInvalid(..),
51 ValidatorFailure(..))
47 ValidatorFailure(..))
52−import JSONSchema.Draft4.Schema (Schema)
48+import JSONSchema.Draft4.Schema (Schema)
53−import qualified JSONSchema.Draft4.Schema as SC
49+import qualified JSONSchema.Draft4.Schema as SC
54−import qualified JSONSchema.Draft4.Spec as Spec
50+import qualified JSONSchema.Draft4.Spec as Spec
55−import JSONSchema.Fetch (ReferencedSchemas(..),
51+import JSONSchema.Fetch (SchemaWithURI(..), URISchemaMap(..))
56− SchemaWithURI(..))
57−import qualified JSONSchema.Fetch as FE
52+import qualified JSONSchema.Fetch as FE
58
53
59data HTTPValidationFailure
54data HTTPValidationFailure
60 = HVRequest FE.HTTPFailure
55 = HVRequest FE.HTTPFailure
@@ -70,11 +65,11 @@ fetchHTTPAndValidate
70 -> IO (Either HTTPValidationFailure ())
65 -> IO (Either HTTPValidationFailure ())
71fetchHTTPAndValidate sw v = do
66fetchHTTPAndValidate sw v = do
72 res <- referencesViaHTTP sw
67 res <- referencesViaHTTP sw
73− pure (g =<< f =<< left HVRequest res)
68+ pure (g =<< f =<< first HVRequest res)
74 where
69 where
75 f :: FE.URISchemaMap Schema
70 f :: FE.URISchemaMap Schema
76 -> Either HTTPValidationFailure (Value -> [ValidatorFailure])
71 -> Either HTTPValidationFailure (Value -> [ValidatorFailure])
77− f references = left HVSchema (checkSchema references sw)
72+ f references = first HVSchema (checkSchema references sw)
78
73
79 g :: (Value -> [ValidatorFailure]) -> Either HTTPValidationFailure ()
74 g :: (Value -> [ValidatorFailure]) -> Either HTTPValidationFailure ()
80 g val = case NE.nonEmpty (val v) of
75 g val = case NE.nonEmpty (val v) of
@@ -100,11 +95,11 @@ fetchFilesystemAndValidate
100 -> IO (Either FilesystemValidationFailure ())
95 -> IO (Either FilesystemValidationFailure ())
101fetchFilesystemAndValidate sw v = do
96fetchFilesystemAndValidate sw v = do
102 res <- referencesViaFilesystem sw
97 res <- referencesViaFilesystem sw
103− pure (g =<< f =<< left FVRead res)
98+ pure (g =<< f =<< first FVRead res)
104 where
99 where
105 f :: FE.URISchemaMap Schema
100 f :: FE.URISchemaMap Schema
106 -> Either FilesystemValidationFailure (Value -> [ValidatorFailure])
101 -> Either FilesystemValidationFailure (Value -> [ValidatorFailure])
107− f references = left FVSchema (checkSchema references sw)
102+ f references = first FVSchema (checkSchema references sw)
108
103
109 g :: (Value -> [ValidatorFailure]) -> Either FilesystemValidationFailure ()
104 g :: (Value -> [ValidatorFailure]) -> Either FilesystemValidationFailure ()
110 g val = case NE.nonEmpty (val v) of
105 g val = case NE.nonEmpty (val v) of
@@ -143,10 +138,7 @@ checkSchema
143checkSchema sm sw =
138checkSchema sm sw =
144 case NE.nonEmpty failures of
139 case NE.nonEmpty failures of
145 Just fs -> Left (SchemaInvalid fs)
140 Just fs -> Left (SchemaInvalid fs)
146− Nothing -> Right (Spec.specValidate
141+ Nothing -> Right (Spec.specValidate sm sw)
147− (ReferencedSchemas (_swSchema sw)
148− (FE._unURISchemaMap sm))
149− sw)
150 where
142 where
151 failures :: [(Maybe Text, NonEmpty ValidatorFailure)]
143 failures :: [(Maybe Text, NonEmpty ValidatorFailure)]
152 failures =
144 failures =
@@ -169,12 +161,11 @@ metaSchemaBytes =
169-- (if so the returned list will be empty).
161-- (if so the returned list will be empty).
170schemaValidity :: Schema -> [ValidatorFailure]
162schemaValidity :: Schema -> [ValidatorFailure]
171schemaValidity =
163schemaValidity =
172− Spec.specValidate referenced (SchemaWithURI metaSchema Nothing) . toJSON
164+ Spec.specValidate schemaMap (SchemaWithURI metaSchema Nothing) . toJSON
173 where
165 where
174− referenced :: ReferencedSchemas Schema
166+ schemaMap :: URISchemaMap Schema
175− referenced = ReferencedSchemas
167+ schemaMap =
176− metaSchema
177− (HM.singleton "http://json-schema.org/draft-04/schema"
168+ URISchemaMap (HM.singleton "http://json-schema.org/draft-04/schema"
178 metaSchema)
169 metaSchema)
179
170
180-- | Check that a set of referenced schemas are valid
171-- | Check that a set of referenced schemas are valid
src/JSONSchema/Draft4/Failure.hs+1−2
@@ -1,9 +1,8 @@
1−
2module JSONSchema.Draft4.Failure where
1module JSONSchema.Draft4.Failure where
3
2
4import Import
3import Import
5
4
6−import JSONSchema.Draft4.Schema (Schema)
5+import JSONSchema.Draft4.Schema (Schema)
7import qualified JSONSchema.Validator.Draft4 as VAL
6import qualified JSONSchema.Validator.Draft4 as VAL
8
7
9-- | Used to report an entire instance being invalidated, as opposed
8-- | Used to report an entire instance being invalidated, as opposed
src/JSONSchema/Draft4/Schema.hs+6−7
@@ -1,14 +1,13 @@
1−
2module JSONSchema.Draft4.Schema where
1module JSONSchema.Draft4.Schema where
3
2
4−import Import hiding (mapMaybe)
3+import Import hiding (mapMaybe)
5
4
6−import qualified Data.HashMap.Strict as HM
5+import qualified Data.HashMap.Strict as HM
7−import Data.List.NonEmpty (NonEmpty)
6+import Data.List.NonEmpty (NonEmpty)
8−import Data.Maybe (fromJust, isJust)
7+import Data.Maybe (fromJust, isJust)
9import Data.Scientific
8import Data.Scientific
10−import qualified Data.Set as Set
9+import qualified Data.Set as Set
11−import qualified Data.Text as T
10+import qualified Data.Text as T
12
11
13import qualified JSONSchema.Validator.Draft4 as D4
12import qualified JSONSchema.Validator.Draft4 as D4
14import JSONSchema.Validator.Utils
13import JSONSchema.Validator.Utils
src/JSONSchema/Draft4/Spec.hs+61−39
@@ -1,53 +1,73 @@
1−
2module JSONSchema.Draft4.Spec where
1module JSONSchema.Draft4.Spec where
3
2
4import Import
3import Import
5
4
6−import Data.Maybe (fromMaybe)
5+import Data.Maybe (fromMaybe)
7−import Data.Profunctor (Profunctor(..))
6+import Data.Profunctor (Profunctor(..))
8
7
9import JSONSchema.Draft4.Failure
8import JSONSchema.Draft4.Failure
10−import JSONSchema.Draft4.Schema (Schema(..))
9+import JSONSchema.Draft4.Schema (Schema(..), emptySchema)
11−import JSONSchema.Fetch (ReferencedSchemas(..),
10+import JSONSchema.Fetch (SchemaWithURI(..), URISchemaMap(..))
12− SchemaWithURI(..))
13−import qualified JSONSchema.Fetch as FE
11+import qualified JSONSchema.Fetch as FE
14−import JSONSchema.Types (Spec(..))
12+import JSONSchema.Types (Spec(..))
15−import qualified JSONSchema.Types as JT
13+import qualified JSONSchema.Types as JT
16import JSONSchema.Validator.Draft4
14import JSONSchema.Validator.Draft4
17−import JSONSchema.Validator.Reference (updateResolutionScope)
15+import JSONSchema.Validator.Reference (BaseURI(..), Scope(..),
16+ updateResolutionScope)
18
17
18+-- | An implementation of 'JT.embedded'.
19embedded :: Schema -> ([Schema], [Schema])
19embedded :: Schema -> ([Schema], [Schema])
20+embedded s =
20−embedded s = JT.embedded (d4Spec (ReferencedSchemas s mempty) mempty Nothing) s
21+ JT.embedded (d4Spec mempty mempty (Scope s Nothing (BaseURI Nothing))) s
21
22
22specValidate
23specValidate
23− :: ReferencedSchemas Schema
24+ :: URISchemaMap Schema
24 -> SchemaWithURI Schema
25 -> SchemaWithURI Schema
25 -> Value
26 -> Value
26 -> [ValidatorFailure]
27 -> [ValidatorFailure]
27−specValidate rs =
28+specValidate schemaMap sw =
29+ JT.validate (d4Spec schemaMap visited scope) (_swSchema sw)
30+ where
31+ visited :: VisitedSchemas
28− continueValidating rs (VisitedSchemas [(Nothing, Nothing)])
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+ }
29
41
30−continueValidating
42+validateSubschema
31− :: ReferencedSchemas Schema
43+ :: URISchemaMap Schema
32 -> VisitedSchemas
44 -> VisitedSchemas
45+ -> Scope Schema
33− -> SchemaWithURI Schema
46+ -> Schema
34 -> Value
47 -> Value
35 -> [ValidatorFailure]
48 -> [ValidatorFailure]
36−continueValidating referenced visited sw =
49+validateSubschema schemaMap visited scope schema =
37− JT.validate (d4Spec referenced visited currentScope)
50+ JT.validate (d4Spec schemaMap visited newScope) schema
38− (_swSchema sw)
39 where
51 where
40− currentScope :: Maybe Text
52+ newScope :: Scope Schema
53+ newScope = scope
41− currentScope = updateResolutionScope
54+ { _currentBaseURI = updateResolutionScope (_currentBaseURI scope)
42− (_swURI sw)
43− (_schemaId (_swSchema sw))
55+ (_schemaId schema)
56+ }
44
57
45d4Spec
58d4Spec
46− :: ReferencedSchemas Schema
59+ :: URISchemaMap Schema
47 -> VisitedSchemas
60 -> VisitedSchemas
48− -> Maybe Text
61+ -> Scope Schema
49 -> Spec Schema ValidatorFailure
62 -> 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)
51 [ dimap (fmap MultipleOf . _schemaMultipleOf) FailureMultipleOf multipleOfValidator
71 [ dimap (fmap MultipleOf . _schemaMultipleOf) FailureMultipleOf multipleOfValidator
52 , dimap
72 , dimap
53 (\s -> Maximum (fromMaybe False (_schemaExclusiveMaximum s)) <$> _schemaMaximum s)
73 (\s -> Maximum (fromMaybe False (_schemaExclusiveMaximum s)) <$> _schemaMaximum s)
@@ -98,10 +118,6 @@ d4Spec referenced visited scope = Spec
98 FailurePropertiesRelated
118 FailurePropertiesRelated
99 (propertiesRelatedValidator descend)
119 (propertiesRelatedValidator descend)
100
120
101− , dimap
102− (\s -> Ref <$> _schemaRef s)
103− FailureRef
104− (refValidator visited scope (FE.getReference referenced) getRef)
105 , dimap (fmap EnumValidator . _schemaEnum) FailureEnum enumValidator
121 , dimap (fmap EnumValidator . _schemaEnum) FailureEnum enumValidator
106 , dimap (fmap TypeContext . _schemaType) FailureType typeValidator
122 , dimap (fmap TypeContext . _schemaType) FailureType typeValidator
107 , dimap (fmap AllOf . _schemaAllOf) FailureAllOf (allOfValidator lateral)
123 , dimap (fmap AllOf . _schemaAllOf) FailureAllOf (allOfValidator lateral)
@@ -110,19 +126,25 @@ d4Spec referenced visited scope = Spec
110 , dimap (fmap NotValidator . _schemaNot) FailureNot (notValidator lateral)
126 , dimap (fmap NotValidator . _schemaNot) FailureNot (notValidator lateral)
111 ]
127 ]
112 where
128 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
114 :: VisitedSchemas
139 :: VisitedSchemas
115− -> Maybe Text
140+ -> Scope Schema
116 -> Schema
141 -> Schema
117 -> Value
142 -> Value
118 -> [ValidatorFailure]
143 -> [ValidatorFailure]
119− getRef newVisited newScope schema =
144+ valRef vis sc = JT.validate (d4Spec schemaMap vis sc)
120− continueValidating referenced newVisited (SchemaWithURI schema newScope)
121
145
122 descend :: Schema -> Value -> [ValidatorFailure]
146 descend :: Schema -> Value -> [ValidatorFailure]
123− descend schema =
147+ descend = validateSubschema schemaMap mempty scope
124− continueValidating referenced mempty (SchemaWithURI schema scope)
125
148
126 lateral :: Schema -> Value -> [ValidatorFailure]
149 lateral :: Schema -> Value -> [ValidatorFailure]
127− lateral schema =
150+ lateral = validateSubschema schemaMap visited scope
128− continueValidating referenced visited (SchemaWithURI schema scope)
src/JSONSchema/Fetch.hs+46−65
@@ -1,18 +1,18 @@
1−
2module JSONSchema.Fetch where
1module JSONSchema.Fetch where
3
2
4import Import
3import Import
5
4
6−import Control.Arrow (left)
7−import Control.Exception (IOException, catch)
5+import qualified Control.Exception.Safe as Safe
8−import Control.Monad (foldM)
6+import Control.Monad (foldM)
9−import qualified Data.ByteString as BS
7+import qualified Data.ByteString as BS
10−import qualified Data.ByteString.Lazy as LBS
8+import qualified Data.ByteString.Lazy as LBS
11−import qualified Data.HashMap.Strict as HM
9+import qualified Data.HashMap.Strict as HM
12−import qualified Data.Text as T
10+import qualified Data.Semigroup as S
11+import qualified Data.Text as T
13−import qualified Network.HTTP.Client as NC
12+import qualified Network.HTTP.Client as NC
14−
13+import qualified Network.HTTP.Client.TLS as NCTLS
14+
15−import JSONSchema.Validator.Reference (resolveReference,
15+import JSONSchema.Validator.Reference (BaseURI(..), resolveReference,
16 updateResolutionScope)
16 updateResolutionScope)
17
17
18--------------------------------------------------
18--------------------------------------------------
@@ -27,49 +27,22 @@ data FetchInfo schema = FetchInfo
27 , _fiRef :: schema -> Maybe Text
27 , _fiRef :: schema -> Maybe Text
28 }
28 }
29
29
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−
55-- | Keys are URIs (without URI fragments).
30-- | Keys are URIs (without URI fragments).
56newtype URISchemaMap schema
31newtype URISchemaMap schema
57 = URISchemaMap { _unURISchemaMap :: HashMap Text schema }
32 = URISchemaMap { _unURISchemaMap :: HashMap Text schema }
58− deriving (Eq, Show)
33+ deriving (Eq, Show, S.Semigroup, Monoid)
59
34
35+-- | A top-level schema along with its location.
60data SchemaWithURI schema = SchemaWithURI
36data SchemaWithURI schema = SchemaWithURI
61 { _swSchema :: !schema
37 { _swSchema :: !schema
62 , _swURI :: !(Maybe Text)
38 , _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.
64 -- It's different than the schema's "id" field, which controls scope
40 -- It's different than the schema's "id" field, which controls scope
65 -- when resolving references contained in the schema.
41 -- when resolving references contained in the schema.
66−
67− -- TODO: Make the no URI fragment requirement unnecessary.
68 } deriving (Eq, Show)
42 } deriving (Eq, Show)
69
43
70−getReference :: ReferencedSchemas schema -> Maybe Text -> Maybe schema
44+getReference :: URISchemaMap schema -> Text -> Maybe schema
71−getReference referenced Nothing = Just (_rsStarting referenced)
45+getReference schemaMap t = HM.lookup t (_unURISchemaMap schemaMap)
72−getReference referenced (Just t) = HM.lookup t (_rsSchemaMap referenced)
73
46
74--------------------------------------------------
47--------------------------------------------------
75-- * Fetch via HTTP
48-- * Fetch via HTTP
@@ -88,9 +61,9 @@ referencesViaHTTP'
88 -> SchemaWithURI schema
61 -> SchemaWithURI schema
89 -> IO (Either HTTPFailure (URISchemaMap schema))
62 -> IO (Either HTTPFailure (URISchemaMap schema))
90referencesViaHTTP' info sw = do
63referencesViaHTTP' info sw = do
91− manager <- NC.newManager NC.defaultManagerSettings
64+ manager <- NC.newManager NCTLS.tlsManagerSettings
92 let f = referencesMethodAgnostic (getURL manager) info sw
65 let f = referencesMethodAgnostic (getURL manager) info sw
93− catch (left HTTPParseFailure <$> f) handler
66+ Safe.catch (first HTTPParseFailure <$> f) handler
94 where
67 where
95 getURL :: NC.Manager -> Text -> IO BS.ByteString
68 getURL :: NC.Manager -> Text -> IO BS.ByteString
96 getURL man url = do
69 getURL man url = do
@@ -116,7 +89,8 @@ referencesViaFilesystem'
116 => FetchInfo schema
89 => FetchInfo schema
117 -> SchemaWithURI schema
90 -> SchemaWithURI schema
118 -> IO (Either FilesystemFailure (URISchemaMap schema))
91 -> 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
120 where
94 where
121 f :: IO (Either Text (URISchemaMap schema))
95 f :: IO (Either Text (URISchemaMap schema))
122 f = referencesMethodAgnostic (BS.readFile . T.unpack) info sw
96 f = referencesMethodAgnostic (BS.readFile . T.unpack) info sw
@@ -155,27 +129,33 @@ getRecursiveReferences fetchRef info referenced sw =
155 f :: Either Text (URISchemaMap schema)
129 f :: Either Text (URISchemaMap schema)
156 -> SchemaWithURI schema
130 -> SchemaWithURI schema
157 -> IO (Either Text (URISchemaMap schema))
131 -> IO (Either Text (URISchemaMap schema))
158− f (Left e) _ = pure (Left e)
132+ f (Left e) _ = pure (Left e)
159− f (Right (URISchemaMap usm)) (SchemaWithURI schema mUri) =
133+ f (Right (URISchemaMap schemaMap)) (SchemaWithURI schema mURI) =
160 case newRef of
134 case newRef of
161− Nothing -> pure (Right (URISchemaMap usm))
135+ Nothing -> pure (Right (URISchemaMap schemaMap))
162 Just uri -> do
136 Just uri -> do
163 bts <- fetchRef uri
137 bts <- fetchRef uri
164 case eitherDecodeStrict bts of
138 case eitherDecodeStrict bts of
165− Left e -> pure . Left . T.pack $ e
139+ Left e -> pure . Left . T.pack $ e
166− Right schm -> getRecursiveReferences
140+ Right s -> getRecursiveReferences
167− fetchRef
141+ fetchRef
168− info
142+ info
169− (URISchemaMap (HM.insert uri schm usm))
143+ (URISchemaMap (HM.insert uri s schemaMap))
170− (SchemaWithURI schm (Just uri))
144+ (SchemaWithURI s (Just uri))
171 where
145 where
172 newRef :: Maybe Text
146 newRef :: Maybe Text
173− newRef
147+ newRef = do
174− | Just (Just uri,_) <- resolveReference mUri <$> _fiRef info schema
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)
175− = case HM.lookup uri usm of
156+ case HM.lookup uri schemaMap of
176− Nothing -> Just uri
157+ Nothing -> Just uri
177− Just _ -> Nothing
158+ Just _ -> Nothing
178− | otherwise = Nothing
179
159
180-- | Return the schema passed in as an argument, as well as every
160-- | Return the schema passed in as an argument, as well as every
181-- subschema contained within it.
161-- subschema contained within it.
@@ -184,11 +164,12 @@ includeSubschemas
184 FetchInfo schema
164 FetchInfo schema
185 -> SchemaWithURI schema
165 -> SchemaWithURI schema
186 -> [SchemaWithURI schema]
166 -> [SchemaWithURI schema]
187−includeSubschemas info (SchemaWithURI schema mUri) =
167+includeSubschemas info (SchemaWithURI schema mURI) =
188− SchemaWithURI schema mUri
168+ SchemaWithURI schema mURI
189 : (includeSubschemas info =<< subSchemas)
169 : (includeSubschemas info =<< subSchemas)
190 where
170 where
191 subSchemas :: [SchemaWithURI schema]
171 subSchemas :: [SchemaWithURI schema]
192 subSchemas =
172 subSchemas =
193− (\a -> SchemaWithURI a (updateResolutionScope mUri (_fiId info schema)))
173+ let newScope = updateResolutionScope (BaseURI mURI) (_fiId info schema)
174+ updateScope s = SchemaWithURI s (_unBaseURI newScope)
194− <$> uncurry (<>) (_fiEmbedded info schema)
175+ in updateScope <$> uncurry (<>) (_fiEmbedded info schema)
src/JSONSchema/Types.hs−1
@@ -1,4 +1,3 @@
1−
2module JSONSchema.Types where
1module JSONSchema.Types where
3
2
4import Import
3import Import
src/JSONSchema/Validator/Draft4.hs+19−19
@@ -1,5 +1,7 @@
1-- | Turn the validation functions into actual 'Validator's.
1-- | 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.
3module JSONSchema.Validator.Draft4
5module JSONSchema.Validator.Draft4
4 ( module JSONSchema.Validator.Draft4
6 ( module JSONSchema.Validator.Draft4
5 , module Export
7 , module Export
@@ -7,18 +9,16 @@ module JSONSchema.Validator.Draft4
7
9
8import Import
10import Import
9
11
10−import qualified Data.HashMap.Strict as HM
12+import qualified Data.HashMap.Strict as HM
11−import qualified Data.List.NonEmpty as NE
13+import qualified Data.List.NonEmpty as NE
12−import Data.Maybe (catMaybes, maybe, maybeToList)
13−import Data.Text (Text)
14
14
15−import JSONSchema.Validator.Draft4.Any as Export
15+import JSONSchema.Validator.Draft4.Any as Export
16−import JSONSchema.Validator.Draft4.Array as Export
16+import JSONSchema.Validator.Draft4.Array as Export
17import JSONSchema.Validator.Draft4.Number as Export
17import JSONSchema.Validator.Draft4.Number as Export
18import JSONSchema.Validator.Draft4.Object as Export
18import JSONSchema.Validator.Draft4.Object as Export
19import JSONSchema.Validator.Draft4.String as Export
19import JSONSchema.Validator.Draft4.String as Export
20−import JSONSchema.Validator.Types (Validator(..))
20+import JSONSchema.Validator.Reference (BaseURI(..), Scope(..))
21−import JSONSchema.Validator.Utils (fromJSONEither)
21+import JSONSchema.Validator.Types (Validator(..))
22
22
23-- | For internal use.
23-- | For internal use.
24--
24--
@@ -75,6 +75,8 @@ minItemsValidator = Validator noEmbedded (run minItemsVal)
75uniqueItemsValidator :: Validator a (Maybe UniqueItems) UniqueItemsInvalid
75uniqueItemsValidator :: Validator a (Maybe UniqueItems) UniqueItemsInvalid
76uniqueItemsValidator = Validator noEmbedded (run uniqueItemsVal)
76uniqueItemsValidator = Validator noEmbedded (run uniqueItemsVal)
77
77
78+-- TODO: Add tests to the language agnostic test suite to
79+-- make sure @"additionalItems"@ subschemas are embedded correctly.
78itemsRelatedValidator
80itemsRelatedValidator
79 :: (schema -> Value -> [err])
81 :: (schema -> Value -> [err])
80 -> Validator schema (ItemsRelated schema) (ItemsRelatedInvalid err)
82 -> Validator schema (ItemsRelated schema) (ItemsRelatedInvalid err)
@@ -145,7 +147,7 @@ propertiesRelatedValidator f =
145 <> HM.elems (fromMaybe mempty (_propPattern a))
147 <> HM.elems (fromMaybe mempty (_propPattern a))
146 <> case _propAdditional a of
148 <> case _propAdditional a of
147 Just (AdditionalPropertiesObject b) -> [b]
149 Just (AdditionalPropertiesObject b) -> [b]
148− _ -> mempty
150+ _ -> mempty
149 ))
151 ))
150 (\a b -> case fromJSONEither b of
152 (\a b -> case fromJSONEither b of
151 Left _ -> mempty
153 Left _ -> mempty
@@ -159,9 +161,6 @@ instance FromJSON schema => FromJSON (Definitions schema) where
159 parseJSON = withObject "Definitions" $ \o ->
161 parseJSON = withObject "Definitions" $ \o ->
160 Definitions <$> o .: "definitions"
162 Definitions <$> o .: "definitions"
161
163
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).
165definitionsEmbedded
164definitionsEmbedded
166 :: Validator
165 :: Validator
167 schema
166 schema
@@ -180,15 +179,16 @@ definitionsEmbedded =
180
179
181refValidator
180refValidator
182 :: (FromJSON schema, ToJSON schema)
181 :: (FromJSON schema, ToJSON schema)
183− => VisitedSchemas
184− -> Maybe Text
182+ => (Text -> Maybe schema)
185− -> (Maybe Text -> Maybe schema)
183+ -> (BaseURI -> schema -> BaseURI)
186− -> (VisitedSchemas -> Maybe Text -> schema -> Value -> [err])
184+ -> (VisitedSchemas -> Scope schema -> schema -> Value -> [err])
185+ -> VisitedSchemas
186+ -> Scope schema
187 -> Validator a (Maybe Ref) (RefInvalid err)
187 -> Validator a (Maybe Ref) (RefInvalid err)
188−refValidator visited scope getRef f =
188+refValidator getRef updateScope f visited scope =
189 Validator
189 Validator
190 noEmbedded
190 noEmbedded
191− (run (refVal visited scope getRef f))
191+ (run (refVal getRef updateScope f visited scope))
192
192
193enumValidator :: Validator a (Maybe EnumValidator) EnumInvalid
193enumValidator :: Validator a (Maybe EnumValidator) EnumInvalid
194enumValidator = Validator noEmbedded (run enumVal)
194enumValidator = Validator noEmbedded (run enumVal)
src/JSONSchema/Validator/Draft4/Any.hs+217−59
@@ -1,20 +1,24 @@
1−
2module JSONSchema.Validator.Draft4.Any where
1module JSONSchema.Validator.Draft4.Any where
3
2
4−import Import
3+import Import hiding ((<>))
5−
4+
5+import Data.Aeson.TH (constructorTagModifier)
6+import Data.Char (toLower)
7+import qualified Data.HashMap.Strict as HM
6−import Data.List.NonEmpty (NonEmpty((:|)))
8+import Data.List.NonEmpty (NonEmpty((:|)))
7−import qualified Data.List.NonEmpty as NE
9+import qualified Data.List.NonEmpty as NE
8−import qualified Data.Scientific as SCI
10+import qualified Data.Scientific as SCI
9−import Data.Semigroup (Semigroup) -- for older GHCs
11+import Data.Semigroup
10−import Data.Set (Set)
12+import Data.Set (Set)
11−import qualified Data.Set as S
13+import qualified Data.Set as Set
14+import Data.Text.Encoding.Error (UnicodeException)
12−import qualified JSONPointer as JP
15+import qualified JSONPointer as JP
13−
16+import Network.HTTP.Types.URI (urlDecode)
14−import qualified JSONSchema.Validator.Utils as UT
17+
15−import JSONSchema.Validator.Reference (URIBaseAndFragment,
18+import JSONSchema.Validator.Reference (BaseURI(..), Scope(..),
16− resolveFragment,
19+ URIAndFragment,
17 resolveReference)
20 resolveReference)
21+import qualified JSONSchema.Validator.Utils as UT
18
22
19--------------------------------------------------
23--------------------------------------------------
20-- * $ref
24-- * $ref
@@ -39,42 +43,156 @@ data RefInvalid err
39 -- Also note that ideally we would enforce in the type system that any
43 -- Also note that ideally we would enforce in the type system that any
40 -- failing references be dealt with before valididation. Then this could
44 -- failing references be dealt with before valididation. Then this could
41 -- be removed entirely.
45 -- be removed entirely.
42− | RefPointerResolution Text
46+ | RefPointerResolution JSONPointerError
43− | RefLoop Text VisitedSchemas URIBaseAndFragment
47+ | RefLoop Text VisitedSchemas URIAndFragment
44 | RefInvalid Text Value (NonEmpty err)
48 | RefInvalid Text Value (NonEmpty err)
45 -- ^ 'Text' is the URI and 'Value' is the linked schema.
49 -- ^ 'Text' is the URI and 'Value' is the linked schema.
46 deriving (Eq, Show)
50 deriving (Eq, Show)
47
51
48newtype VisitedSchemas
52newtype VisitedSchemas
49− = VisitedSchemas { _unVisited :: [URIBaseAndFragment] }
53+ = VisitedSchemas { _unVisited :: [URIAndFragment] }
50 deriving (Eq, Show, Semigroup, Monoid)
54 deriving (Eq, Show, Semigroup, Monoid)
51
55
52refVal
56refVal
53 :: forall err schema. (FromJSON schema, ToJSON schema)
57 :: forall err schema. (FromJSON schema, ToJSON schema)
54− => VisitedSchemas
55− -> Maybe Text
58+ => (Text -> Maybe schema)
56− -> (Maybe Text -> Maybe schema)
59+ -- ^ Look up a schema.
60+ -> (BaseURI -> schema -> BaseURI)
61+ -- ^ Update scope (needed after moving deeper into nested schemas).
57− -> (VisitedSchemas -> Maybe Text -> schema -> Value -> [err])
62+ -> (VisitedSchemas -> Scope schema -> schema -> Value -> [err])
63+ -- ^ Validate data.
64+ -> VisitedSchemas
65+ -> Scope schema
58 -> Ref
66 -> Ref
59 -> Value
67 -> Value
60 -> Maybe (RefInvalid err)
68 -> Maybe (RefInvalid err)
61−refVal visited scope getRef f (Ref reference) x
69+refVal getRef updateScope val visited scope (Ref reference) x
62 | (mURI, mFragment) `elem` _unVisited visited =
70 | (mURI, mFragment) `elem` _unVisited visited =
63 Just (RefLoop reference visited (mURI, mFragment))
71 Just (RefLoop reference visited (mURI, mFragment))
64− | otherwise =
72+ | otherwise = leftToMaybe $ do
65− case getRef mURI of
73+
66− Nothing -> Just (RefResolution reference)
74+ -- Get the referenced document
67− Just schema ->
75+
68− case resolveFragment mFragment schema of
76+ (newScope, doc) <- first RefResolution
69− Nothing -> Just (RefPointerResolution reference)
77+ $ getDocument getRef updateScope scope mURI reference
70− Just s ->
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+
71− let newVisited = (VisitedSchemas [(mURI, mFragment)]
89+ let newVisited = VisitedSchemas [(_documentURI newScope, mFragment)]
72− <> visited)
90+ <> visited
73− errs = f newVisited mURI s x
91+ failures = val newVisited finalScope schema x
74− in RefInvalid reference (toJSON schema)
92+ first (RefInvalid reference (toJSON schema))
93+ . maybeToLeft ()
75− <$> NE.nonEmpty errs
94+ $ NE.nonEmpty failures
76 where
95 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"
78
196
79--------------------------------------------------
197--------------------------------------------------
80-- * enum
198-- * enum
@@ -109,7 +227,10 @@ instance Arbitrary EnumValidator where
109 Just ne -> pure (EnumValidator ne)
227 Just ne -> pure (EnumValidator ne)
110 where
228 where
111 toUnique :: [Value] -> [Value]
229 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
113
234
114data EnumInvalid
235data EnumInvalid
115 = EnumInvalid EnumValidator Value
236 = EnumInvalid EnumValidator Value
@@ -117,9 +238,9 @@ data EnumInvalid
117
238
118enumVal :: EnumValidator -> Value -> Maybe EnumInvalid
239enumVal :: EnumValidator -> Value -> Maybe EnumInvalid
119enumVal a@(EnumValidator vs) x
240enumVal a@(EnumValidator vs) x
120− | not (UT.allUniqueValues' vs) = Nothing
241+ | not (UT.allUniqueValues vs) = Nothing
121− | x `elem` vs = Nothing
242+ | x `elem` vs = Nothing
122− | otherwise = Just $ EnumInvalid a x
243+ | otherwise = Just $ EnumInvalid a x
123
244
124--------------------------------------------------
245--------------------------------------------------
125-- * type
246-- * type
@@ -137,10 +258,25 @@ instance FromJSON TypeContext where
137 TypeContext <$> o .: "type"
258 TypeContext <$> o .: "type"
138
259
139data TypeValidator
260data TypeValidator
140− = TypeValidatorString Text
261+ = TypeValidatorString SchemaType
141− | TypeValidatorArray (Set Text)
262+ | TypeValidatorArray (Set SchemaType)
142 deriving (Eq, Show)
263 deriving (Eq, Show)
143
264
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+
144instance FromJSON TypeValidator where
280instance FromJSON TypeValidator where
145 parseJSON v = fmap TypeValidatorString (parseJSON v)
281 parseJSON v = fmap TypeValidatorString (parseJSON v)
146 <|> fmap TypeValidatorArray (parseJSON v)
282 <|> fmap TypeValidatorArray (parseJSON v)
@@ -150,40 +286,63 @@ instance ToJSON TypeValidator where
150 toJSON (TypeValidatorArray ts) = toJSON ts
286 toJSON (TypeValidatorArray ts) = toJSON ts
151
287
152instance Arbitrary TypeValidator where
288instance Arbitrary TypeValidator where
153− arbitrary = oneof [ TypeValidatorString <$> UT.arbitraryText
289+ arbitrary = oneof [ TypeValidatorString <$> arbitrary
154− , TypeValidatorArray <$> UT.arbitrarySetOfText
290+ , TypeValidatorArray <$> arbitrary
155 ]
291 ]
156
292
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+
157data TypeValidatorInvalid
316data TypeValidatorInvalid
158 = TypeValidatorInvalid TypeValidator Value
317 = TypeValidatorInvalid TypeValidator Value
159 deriving (Eq, Show)
318 deriving (Eq, Show)
160
319
161typeVal :: TypeContext -> Value -> Maybe TypeValidatorInvalid
320typeVal :: TypeContext -> Value -> Maybe TypeValidatorInvalid
162typeVal (TypeContext tv) x
321typeVal (TypeContext tv) x
163− | S.null matches = Just (TypeValidatorInvalid tv x)
322+ | Set.null matches = Just (TypeValidatorInvalid tv x)
164− | otherwise = Nothing
323+ | otherwise = Nothing
165 where
324 where
166 -- There can be more than one match because a 'Value' can be both a
325 -- There can be more than one match because a 'Value' can be both a
167 -- @"number"@ and an @"integer"@.
326 -- @"number"@ and an @"integer"@.
168− matches :: Set Text
327+ matches :: Set SchemaType
169− matches = S.intersection okTypes (setFromTypeValidator tv)
328+ matches = Set.intersection okTypes (setFromTypeValidator tv)
170
329
171− okTypes :: Set Text
330+ okTypes :: Set SchemaType
172 okTypes =
331 okTypes =
173 case x of
332 case x of
174− Null -> S.singleton "null"
333+ Null -> Set.singleton SchemaNull
175− (Array _) -> S.singleton "array"
334+ (Array _) -> Set.singleton SchemaArray
176− (Bool _) -> S.singleton "boolean"
335+ (Bool _) -> Set.singleton SchemaBoolean
177− (Object _) -> S.singleton "object"
336+ (Object _) -> Set.singleton SchemaObject
178− (String _) -> S.singleton "string"
337+ (String _) -> Set.singleton SchemaString
179 (Number y) ->
338 (Number y) ->
180 if SCI.isInteger y
339 if SCI.isInteger y
181− then S.fromList ["number", "integer"]
340+ then Set.fromList [SchemaNumber, SchemaInteger]
182− else S.singleton "number"
341+ else Set.singleton SchemaNumber
183
342
184-- | Internal.
343-- | Internal.
185−setFromTypeValidator :: TypeValidator -> Set Text
344+setFromTypeValidator :: TypeValidator -> Set SchemaType
186−setFromTypeValidator (TypeValidatorString t) = S.singleton t
345+setFromTypeValidator (TypeValidatorString t) = Set.singleton t
187setFromTypeValidator (TypeValidatorArray ts) = ts
346setFromTypeValidator (TypeValidatorArray ts) = ts
188
347
189--------------------------------------------------
348--------------------------------------------------
@@ -240,8 +399,7 @@ anyOfVal
240 -> Value
399 -> Value
241 -> Maybe (AnyOfInvalid err)
400 -> Maybe (AnyOfInvalid err)
242anyOfVal f (AnyOf subSchemas) x
401anyOfVal f (AnyOf subSchemas) x
243− -- Replace with @null@ once we drop GHC 7.8:
402+ | any (null . snd) perhapsFailures = Nothing
244− | any (((==) 0 . length) . snd) perhapsFailures = Nothing
245 | otherwise = AnyOfInvalid <$> NE.nonEmpty failures
403 | otherwise = AnyOfInvalid <$> NE.nonEmpty failures
246 where
404 where
247 perhapsFailures :: [(JP.Index, [err])]
405 perhapsFailures :: [(JP.Index, [err])]
src/JSONSchema/Validator/Draft4/Array.hs+8−7
@@ -1,11 +1,10 @@
1−
2module JSONSchema.Validator.Draft4.Array where
1module JSONSchema.Validator.Draft4.Array where
3
2
4import Import
3import Import
5
4
6−import qualified Data.List.NonEmpty as NE
5+import qualified Data.List.NonEmpty as NE
7−import qualified Data.Vector as V
6+import qualified Data.Vector as V
8−import qualified JSONPointer as JP
7+import qualified JSONPointer as JP
9
8
10import JSONSchema.Validator.Utils (allUniqueValues)
9import JSONSchema.Validator.Utils (allUniqueValues)
11
10
@@ -67,7 +66,7 @@ instance FromJSON UniqueItems where
67 parseJSON = withObject "UniqueItems" $ \o ->
66 parseJSON = withObject "UniqueItems" $ \o ->
68 UniqueItems <$> o .: "uniqueItems"
67 UniqueItems <$> o .: "uniqueItems"
69
68
70−data UniqueItemsInvalid
69+newtype UniqueItemsInvalid
71 = UniqueItemsInvalid (Vector Value)
70 = UniqueItemsInvalid (Vector Value)
72 deriving (Eq, Show)
71 deriving (Eq, Show)
73
72
@@ -174,7 +173,8 @@ itemsVal f a xs =
174 :: schema
173 :: schema
175 -> (JP.Index, Value)
174 -> (JP.Index, Value)
176 -> Maybe (JP.Index, NonEmpty err)
175 -> 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)
178
178
179--------------------------------------------------
179--------------------------------------------------
180-- * additionalItems
180-- * additionalItems
@@ -219,6 +219,7 @@ additionalItemsVal _ (AdditionalBool False) xs =
219 AdditionalItemsBoolInvalid <$> NE.nonEmpty xs
219 AdditionalItemsBoolInvalid <$> NE.nonEmpty xs
220additionalItemsVal f (AdditionalObject subSchema) xs =
220additionalItemsVal f (AdditionalObject subSchema) xs =
221 let res = mapMaybe
221 let res = mapMaybe
222− (\(index,x) -> (index,) <$> NE.nonEmpty (f subSchema x))
222+ (\(index,x) -> (\v -> (index, v))
223+ <$> NE.nonEmpty (f subSchema x))
223 xs
224 xs
224 in AdditionalItemsObjectInvalid <$> NE.nonEmpty res
225 in AdditionalItemsObjectInvalid <$> NE.nonEmpty res
src/JSONSchema/Validator/Draft4/Number.hs+1−2
@@ -1,9 +1,8 @@
1−
2module JSONSchema.Validator.Draft4.Number where
1module JSONSchema.Validator.Draft4.Number where
3
2
4import Import
3import Import
5
4
6−import Data.Fixed (mod')
5+import Data.Fixed (mod')
7import Data.Scientific (Scientific)
6import Data.Scientific (Scientific)
8
7
9--------------------------------------------------
8--------------------------------------------------
src/JSONSchema/Validator/Draft4/Object.hs+6−10
@@ -1,4 +1,3 @@
1−
2module JSONSchema.Validator.Draft4.Object
1module JSONSchema.Validator.Draft4.Object
3 ( module JSONSchema.Validator.Draft4.Object
2 ( module JSONSchema.Validator.Draft4.Object
4 , module JSONSchema.Validator.Draft4.Object.Properties
3 , module JSONSchema.Validator.Draft4.Object.Properties
@@ -6,11 +5,11 @@ module JSONSchema.Validator.Draft4.Object
6
5
7import Import
6import Import
8
7
9−import qualified Data.HashMap.Strict as HM
8+import qualified Data.HashMap.Strict as HM
10−import qualified Data.List.NonEmpty as NE
9+import qualified Data.List.NonEmpty as NE
11−import Data.Set (Set)
10+import Data.Set (Set)
12−import qualified Data.Set as Set
11+import qualified Data.Set as Set
13−import qualified Data.Text as T
12+import qualified Data.Text as T
14
13
15import JSONSchema.Validator.Draft4.Object.Properties
14import JSONSchema.Validator.Draft4.Object.Properties
16import JSONSchema.Validator.Utils
15import JSONSchema.Validator.Utils
@@ -96,9 +95,6 @@ data RequiredInvalid
96
95
97requiredVal :: Required -> HashMap Text Value -> Maybe RequiredInvalid
96requiredVal :: Required -> HashMap Text Value -> Maybe RequiredInvalid
98requiredVal r@(Required ts) x
97requiredVal 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.
102 | Set.null ts = Nothing
98 | Set.null ts = Nothing
103 | Set.null leftovers = Nothing
99 | Set.null leftovers = Nothing
104 | otherwise = Just (RequiredInvalid r leftovers x)
100 | otherwise = Just (RequiredInvalid r leftovers x)
@@ -145,7 +141,7 @@ data DependencyMemberInvalid err
145 | PropertyDepInvalid (Set Text) (HashMap Text Value)
141 | PropertyDepInvalid (Set Text) (HashMap Text Value)
146 deriving (Eq, Show)
142 deriving (Eq, Show)
147
143
148−data DependenciesInvalid err
144+newtype DependenciesInvalid err
149 = DependenciesInvalid (HashMap Text (DependencyMemberInvalid err))
145 = DependenciesInvalid (HashMap Text (DependencyMemberInvalid err))
150 deriving (Eq, Show)
146 deriving (Eq, Show)
151
147
src/JSONSchema/Validator/Draft4/Object/Properties.hs+6−6
@@ -1,17 +1,17 @@
1−
2module JSONSchema.Validator.Draft4.Object.Properties where
1module JSONSchema.Validator.Draft4.Object.Properties where
3
2
4import Import
3import Import
5
4
6−import qualified Data.Hashable as HA
5+import qualified Data.Hashable as HA
7−import qualified Data.HashMap.Strict as HM
6+import qualified Data.HashMap.Strict as HM
8−import qualified Data.List.NonEmpty as NE
7+import qualified Data.List.NonEmpty as NE
9−import Data.Text.Encoding (encodeUtf8)
8+import Data.Text.Encoding (encodeUtf8)
10−import qualified JSONPointer as JP
9+import qualified JSONPointer as JP
11import qualified Text.Regex.PCRE.Heavy as RE
10import qualified Text.Regex.PCRE.Heavy as RE
12
11
13data PropertiesRelated schema = PropertiesRelated
12data PropertiesRelated schema = PropertiesRelated
14 { _propProperties :: Maybe (HashMap Text schema)
13 { _propProperties :: Maybe (HashMap Text schema)
14+ -- ^ 'Maybe' is used to distinguish whether the key is present or not.
15 , _propPattern :: Maybe (HashMap Text schema)
15 , _propPattern :: Maybe (HashMap Text schema)
16 , _propAdditional :: Maybe (AdditionalProperties schema)
16 , _propAdditional :: Maybe (AdditionalProperties schema)
17 } deriving (Eq, Show)
17 } deriving (Eq, Show)
src/JSONSchema/Validator/Draft4/String.hs+2−3
@@ -1,10 +1,9 @@
1−
2module JSONSchema.Validator.Draft4.String where
1module JSONSchema.Validator.Draft4.String where
3
2
4import Import
3import Import
5
4
6−import qualified Data.Text as T
5+import qualified Data.Text as T
7−import Data.Text.Encoding (encodeUtf8)
6+import Data.Text.Encoding (encodeUtf8)
8import qualified Text.Regex.PCRE.Heavy as RE
7import qualified Text.Regex.PCRE.Heavy as RE
9
8
10--------------------------------------------------
9--------------------------------------------------
src/JSONSchema/Validator/Reference.hs+28−36
@@ -3,42 +3,34 @@
3--
3--
4-- And is extended for JSON Schema here:
4-- And is extended for JSON Schema here:
5-- <http://json-schema.org/latest/json-schema-core.html#anchor26>
5-- <http://json-schema.org/latest/json-schema-core.html#anchor26>
6−
7module JSONSchema.Validator.Reference where
6module JSONSchema.Validator.Reference where
8
7
9import Import
8import Import
10
9
11−import qualified Data.Text as T
10+import qualified Data.Text as T
12−import Data.Text.Encoding (decodeUtf8, encodeUtf8)
11+import System.FilePath (dropFileName, (</>))
13−import qualified JSONPointer as JP
12+
14−import Network.HTTP.Types.URI (urlDecode)
13+data Scope schema = Scope
15−import System.FilePath ((</>), dropFileName)
14+ { _topLevelDocument :: schema
15+ , _documentURI :: Maybe Text
16+ , _currentBaseURI :: BaseURI
17+ } deriving (Eq, Show)
16
18
17−-- | TODO: Replace these with actual URI data types.
19+newtype BaseURI
18−type URIBase = Maybe Text
20+ = BaseURI { _unBaseURI :: Maybe Text }
19−type URIBaseAndFragment = (Maybe Text, Maybe Text)
21+ deriving (Eq, Show)
20
22
21−updateResolutionScope :: URIBase -> Maybe Text -> URIBase
23+-- | TODO: no `type`s.
22−updateResolutionScope mScope idKeyword
24+type URIAndFragment = (Maybe Text, Maybe Text)
23− | Just t <- idKeyword = fst . baseAndFragment $ resolveScopeAgainst mScope t
24− | otherwise = mScope
25
25
26−resolveReference :: URIBase -> Text -> URIBaseAndFragment
26+updateResolutionScope :: BaseURI -> Maybe Text -> BaseURI
27−resolveReference mScope t = baseAndFragment $ resolveScopeAgainst mScope t
27+updateResolutionScope base idKeyword =
28+ case idKeyword of
29+ Just t -> BaseURI . fst . baseAndFragment $ resolveScopeAgainst base t
30+ Nothing -> base
28
31
29−resolveFragment
32+resolveReference :: BaseURI -> Text -> URIAndFragment
30− :: (FromJSON schema, ToJSON schema)
33+resolveReference base t = baseAndFragment (resolveScopeAgainst base t)
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'
42
34
43--------------------------------------------------
35--------------------------------------------------
44-- * Helpers
36-- * Helpers
@@ -47,10 +39,10 @@ resolveFragment (Just pointer) schema = do
47isRemoteReference :: Text -> Bool
39isRemoteReference :: Text -> Bool
48isRemoteReference = T.isInfixOf "://"
40isRemoteReference = T.isInfixOf "://"
49
41
50−baseAndFragment :: Text -> URIBaseAndFragment
42+baseAndFragment :: Text -> URIAndFragment
51baseAndFragment = f . T.splitOn "#"
43baseAndFragment = f . T.splitOn "#"
52 where
44 where
53− f :: [Text] -> URIBaseAndFragment
45+ f :: [Text] -> URIAndFragment
54 f [x] = (g x, Nothing)
46 f [x] = (g x, Nothing)
55 f [x,y] = (g x, g y)
47 f [x,y] = (g x, g y)
56 f _ = (Nothing, Nothing)
48 f _ = (Nothing, Nothing)
@@ -58,9 +50,9 @@ baseAndFragment = f . T.splitOn "#"
58 g "" = Nothing
50 g "" = Nothing
59 g x = Just x
51 g x = Just x
60
52
61−resolveScopeAgainst :: Maybe Text -> Text -> Text
53+resolveScopeAgainst :: BaseURI -> Text -> Text
62−resolveScopeAgainst Nothing t = t
54+resolveScopeAgainst (BaseURI Nothing) t = t
63−resolveScopeAgainst (Just scope) t
55+resolveScopeAgainst (BaseURI (Just base)) t
64 | isRemoteReference t = t
56 | isRemoteReference t = t
65 | otherwise = smartAppend
57 | otherwise = smartAppend
66 where
58 where
@@ -69,11 +61,11 @@ resolveScopeAgainst (Just scope) t
69 -- to cut it off before appending.
61 -- to cut it off before appending.
70 smartAppend :: Text
62 smartAppend :: Text
71 smartAppend =
63 smartAppend =
72− case baseAndFragment scope of
64+ case baseAndFragment base of
73− (Just base,_) ->
65+ (Just uri,_) ->
74 case T.unpack t of
66 case T.unpack t of
75 -- We want "/foo" and "#/bar" to combine into
67 -- We want "/foo" and "#/bar" to combine into
76 -- "/foo#/bar" not "/foo/#/bar".
68 -- "/foo#/bar" not "/foo/#/bar".
77 '#':_ -> base <> t
69 '#':_ -> base <> t
78− _ -> T.pack (dropFileName (T.unpack base) </> T.unpack t)
70+ _ -> T.pack (dropFileName (T.unpack uri) </> T.unpack t)
79 _ -> t
71 _ -> t
src/JSONSchema/Validator/Types.hs−1
@@ -1,4 +1,3 @@
1−
2module JSONSchema.Validator.Types where
1module JSONSchema.Validator.Types where
3
2
4import Import
3import Import
src/JSONSchema/Validator/Utils.hs+11−27
@@ -1,16 +1,15 @@
1−
2module JSONSchema.Validator.Utils where
1module JSONSchema.Validator.Utils where
3
2
4import Import
3import Import
5
4
6−import Control.Monad (fail)
5+import Control.Monad (fail)
7import qualified Data.HashMap.Strict as HM
6import qualified Data.HashMap.Strict as HM
8−import qualified Data.List.NonEmpty as NE
7+import qualified Data.List.NonEmpty as NE
9−import Data.Scientific (Scientific, fromFloatDigits)
8+import Data.Scientific (Scientific, fromFloatDigits)
10−import Data.Set (Set)
9+import Data.Set (Set)
11−import qualified Data.Set as S
10+import qualified Data.Set as S
12−import qualified Data.Text as T
11+import qualified Data.Text as T
13−import qualified Data.Vector as V
12+import qualified Data.Vector as V
14
13
15--------------------------------------------------
14--------------------------------------------------
16-- * QuickCheck
15-- * QuickCheck
@@ -83,16 +82,11 @@ instance Arbitrary a => Arbitrary (NonEmpty' a) where
83-- * allUniqueValues
82-- * allUniqueValues
84--------------------------------------------------
83--------------------------------------------------
85
84
86−allUniqueValues :: Vector Value -> Bool
85+allUniqueValues :: (Foldable f, Functor f) => f Value -> Bool
87−allUniqueValues = allUnique . fmap OrdValue . V.toList
86+allUniqueValues = allUnique . fmap OrdValue
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
93
87
94−allUnique :: (Ord a) => [a] -> Bool
88+allUnique :: (Foldable f, Ord a) => f a -> Bool
95−allUnique xs = S.size (S.fromList xs) == length xs
89+allUnique xs = S.size (S.fromList (toList xs)) == length xs
96
90
97-- | OrdValue's Ord instance needs benchmarking, but it allows us to
91-- | OrdValue's Ord instance needs benchmarking, but it allows us to
98-- use our 'allUnique' function instead of O(n^2) nub, so it's probably
92-- use our 'allUnique' function instead of O(n^2) nub, so it's probably
@@ -123,13 +117,3 @@ instance Ord OrdValue where
123
117
124 (OrdValue (Object x)) `compare` (OrdValue (Object y)) =
118 (OrdValue (Object x)) `compare` (OrdValue (Object y)) =
125 HM.toList (OrdValue <$> x) `compare` HM.toList (OrdValue <$> y)
119 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−
2module Main where
1module Main where
3
2
4import Protolude
3import Protolude
5
4
6import Data.Aeson
5import Data.Aeson
7import qualified Data.List.NonEmpty as NE
6import qualified Data.List.NonEmpty as NE
8−import qualified System.Timeout as TO
7+import qualified System.Timeout as TO
9import Test.Hspec
8import Test.Hspec
10−import Test.QuickCheck (property)
9+import Test.QuickCheck (property)
11
10
12−import qualified JSONSchema.Draft4 as D4
11+import qualified JSONSchema.Draft4 as D4
13−import JSONSchema.Fetch (ReferencedSchemas(..),
12+import qualified JSONSchema.Types as JT
14− URISchemaMap(..))
15−import qualified JSONSchema.Types as JT
16import qualified Local.Failure
13import qualified Local.Failure
17−import qualified Local.Validation
18import qualified Local.Reference
14import qualified Local.Reference
15+import qualified Local.Validation
19import Shared
16import Shared
20
17
21-- Examples
18-- Examples
@@ -35,12 +32,10 @@ main = do
35 -- Language agnostic tests
32 -- Language agnostic tests
36 ts <- readSchemaTests
33 ts <- readSchemaTests
37 dir
34 dir
38− (\a -> not (isHTTPTest a || skipOptional a))
35+ (\a -> not (isHTTPTest a || skipTest a))
39
36
40 -- Custom supplements to the language agnostic tests
37 -- Custom supplements to the language agnostic tests
41− supplementTs <- readSchemaTests
38+ supplementTs <- readSchemaTests supplementDir (not . isHTTPTest)
42− supplementDir
43− (\a -> not (isHTTPTest a || skipOptional a))
44
39
45 hspec $ do
40 hspec $ do
46 describe "Examples" exampleTests
41 describe "Examples" exampleTests
@@ -84,8 +79,9 @@ main = do
84 Left e -> panic ("Local.validateExample error: " <> show e)
79 Left e -> panic ("Local.validateExample error: " <> show e)
85 Right schemaMap -> do
80 Right schemaMap -> do
86 let failures = AlternateSchema.validate
81 let failures = AlternateSchema.validate
87− (ReferencedSchemas s (_unURISchemaMap schemaMap))
82+ schemaMap
88− Nothing s (_scData sc)
83+ (D4.SchemaWithURI s Nothing)
84+ (_scData sc)
89 assertResult sc failures
85 assertResult sc failures
90
86
91quickCheckTests :: Spec
87quickCheckTests :: Spec
test/Local/Failure.hs+6−7
@@ -1,15 +1,14 @@
1−
2module Local.Failure where
1module Local.Failure where
3
2
4import Protolude
3import Protolude
5
4
6import Data.Aeson
5import Data.Aeson
6+import qualified Data.Vector as V
7+import qualified JSONPointer as JP
7import Test.Hspec
8import Test.Hspec
8−import qualified Data.Vector as V
9−import qualified JSONPointer as JP
10
9
11import JSONSchema.Draft4
10import JSONSchema.Draft4
12−import qualified JSONSchema.Draft4.Spec as Spec
11+import qualified JSONSchema.Draft4.Spec as Spec
13import qualified JSONSchema.Validator.Draft4 as VAL
12import qualified JSONSchema.Validator.Draft4 as VAL
14
13
15spec :: Spec
14spec :: Spec
@@ -31,7 +30,7 @@ itemsArray =
31 ]
30 ]
32 where
31 where
33 failures :: [ValidatorFailure]
32 failures :: [ValidatorFailure]
34− failures = Spec.specValidate (ReferencedSchemas schema mempty) sw badData
33+ failures = Spec.specValidate mempty sw badData
35
34
36 schema :: Schema
35 schema :: Schema
37 schema = emptySchema
36 schema = emptySchema
@@ -61,7 +60,7 @@ itemsObject =
61 ]
60 ]
62 where
61 where
63 failures :: [ValidatorFailure]
62 failures :: [ValidatorFailure]
64− failures = Spec.specValidate (ReferencedSchemas schema mempty) sw badData
63+ failures = Spec.specValidate mempty sw badData
65
64
66 schema :: Schema
65 schema :: Schema
67 schema = emptySchema
66 schema = emptySchema
@@ -89,7 +88,7 @@ loopRef =
89 ]
88 ]
90 where
89 where
91 failures :: [ValidatorFailure]
90 failures :: [ValidatorFailure]
92− failures = Spec.specValidate (ReferencedSchemas schema mempty) sw badData
91+ failures = Spec.specValidate mempty sw badData
93
92
94 schema :: Schema
93 schema :: Schema
95 schema = emptySchema
94 schema = emptySchema
test/Local/Reference.hs+12−13
@@ -1,4 +1,3 @@
1−
2module Local.Reference where
1module Local.Reference where
3
2
4import Protolude
3import Protolude
@@ -10,28 +9,28 @@ import JSONSchema.Validator.Reference
10spec :: Spec
9spec :: Spec
11spec = do
10spec = do
12 it "updateResolutionScope gives correct results" $ do
11 it "updateResolutionScope gives correct results" $ do
13− updateResolutionScope Nothing Nothing
12+ updateResolutionScope (BaseURI Nothing) Nothing
14− `shouldBe` Nothing
13+ `shouldBe` BaseURI Nothing
15
14
16− updateResolutionScope Nothing (Just "#")
15+ updateResolutionScope (BaseURI Nothing) (Just "#")
17− `shouldBe` Nothing
16+ `shouldBe` BaseURI Nothing
18
17
19− updateResolutionScope Nothing (Just "foo")
18+ updateResolutionScope (BaseURI Nothing) (Just "foo")
20− `shouldBe` Just "foo"
19+ `shouldBe` BaseURI (Just "foo")
21
20
22 -- TODO: Normalize after updateResolutionScope:
21 -- TODO: Normalize after updateResolutionScope:
23− updateResolutionScope (Just "/foo") (Just "./bar")
22+ updateResolutionScope (BaseURI (Just "/foo")) (Just "./bar")
24− `shouldBe` Just "/./bar"
23+ `shouldBe` BaseURI (Just "/./bar")
25
24
26 it "resolveReference gives correct results" $ do
25 it "resolveReference gives correct results" $ do
27− resolveReference (Just "/foo") "bar"
26+ resolveReference (BaseURI (Just "/foo")) "bar"
28 `shouldBe` (Just "/bar", Nothing)
27 `shouldBe` (Just "/bar", Nothing)
29
28
30− resolveReference (Just "/foo/bar") "/baz"
29+ resolveReference (BaseURI (Just "/foo/bar")) "/baz"
31 `shouldBe` (Just "/baz", Nothing)
30 `shouldBe` (Just "/baz", Nothing)
32
31
33− resolveReference Nothing "#/bar"
32+ resolveReference (BaseURI Nothing) "#/bar"
34 `shouldBe` (Nothing, Just "/bar")
33 `shouldBe` (Nothing, Just "/bar")
35
34
36− resolveReference (Just "/foo") "#/bar"
35+ resolveReference (BaseURI (Just "/foo")) "#/bar"
37 `shouldBe` (Just "/foo", Just "/bar")
36 `shouldBe` (Just "/foo", Just "/bar")
test/Local/Validation.hs+5−6
@@ -1,17 +1,16 @@
1−
2module Local.Validation where
1module Local.Validation where
3
2
4−import Protolude hiding (msg)
3+import Protolude
5
4
6import Data.Aeson
5import Data.Aeson
7−import qualified Data.Aeson as AE
6+import qualified Data.Aeson as AE
8import qualified Data.HashMap.Strict as HM
7import qualified Data.HashMap.Strict as HM
9−import Data.String (String)
8+import Data.String (String)
10import Test.Hspec
9import Test.Hspec
11
10
11+import qualified AlternateSchema as AS
12import JSONSchema.Draft4
12import JSONSchema.Draft4
13−import qualified JSONSchema.Types as JT
13+import qualified JSONSchema.Types as JT
14−import qualified AlternateSchema as AS
15
14
16spec :: Spec
15spec :: Spec
17spec = do
16spec = do
test/Remote.hs+9−11
@@ -1,19 +1,16 @@
1−
2module Main where
1module Main where
3
2
4import Protolude
3import Protolude
5
4
6−import Control.Concurrent.Async (withAsync)
5+import Control.Concurrent.Async (withAsync)
7−import qualified Data.List.NonEmpty as NE
6+import qualified Data.List.NonEmpty as NE
8import Network.Wai.Application.Static (defaultFileServerSettings,
7import Network.Wai.Application.Static (defaultFileServerSettings,
9 staticApp)
8 staticApp)
10−import Network.Wai.Handler.Warp (run)
9+import qualified Network.Wai.Handler.Warp as Warp
11import Test.Hspec
10import Test.Hspec
12
11
13−import qualified JSONSchema.Draft4 as D4
12+import qualified JSONSchema.Draft4 as D4
14−import JSONSchema.Fetch (ReferencedSchemas(..),
13+import qualified JSONSchema.Types as JT
15− URISchemaMap(..))
16−import qualified JSONSchema.Types as JT
17import Shared
14import Shared
18
15
19-- Examples
16-- Examples
@@ -48,12 +45,13 @@ main = withAsync serve $ \_ -> do
48 Left e -> panic ("Remote.validateExample error: " <> show e)
45 Left e -> panic ("Remote.validateExample error: " <> show e)
49 Right schemaMap -> do
46 Right schemaMap -> do
50 let failures = AlternateSchema.validate
47 let failures = AlternateSchema.validate
51− (ReferencedSchemas s (_unURISchemaMap schemaMap))
48+ schemaMap
52− Nothing s (_scData sc)
49+ (D4.SchemaWithURI s Nothing)
50+ (_scData sc)
53 assertResult sc failures
51 assertResult sc failures
54
52
55serve :: IO ()
53serve :: IO ()
56−serve = run 1234
54+serve = Warp.run 1234
57 . staticApp
55 . staticApp
58 . defaultFileServerSettings
56 . defaultFileServerSettings
59 $ "JSON-Schema-Test-Suite/remotes"
57 $ "JSON-Schema-Test-Suite/remotes"
test/Shared.hs+21−22
@@ -1,19 +1,29 @@
1−
2module Shared where
1module Shared where
3
2
4import Protolude
3import Protolude
5
4
6−import Control.Monad (fail)
5+import Control.Monad (fail)
7import Data.Aeson
6import Data.Aeson
8−import Data.Aeson.TH
7+import Data.Aeson.TH (fieldLabelModifier)
9−import qualified Data.ByteString.Lazy as LBS
8+import qualified Data.ByteString as BS
10−import Data.Char (toLower)
9+import Data.Char (toLower)
11−import Data.List (stripPrefix, unlines)
10+import Data.List (stripPrefix, unlines)
12−import qualified Data.Text as T
11+import qualified Data.Text as T
13−import qualified System.Directory as SD
12+import qualified System.Directory as SD
14−import System.FilePath ((</>))
13+import System.FilePath ((</>))
15import Test.Hspec
14import Test.Hspec
16
15
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+
17-- Recursively return the contents of a directory
27-- Recursively return the contents of a directory
18-- (or return itself if given a file as an argument).
28-- (or return itself if given a file as an argument).
19--
29--
@@ -37,17 +47,6 @@ listFilesFullPath path = do
37 fs <- fmap (path </>) <$> SD.listDirectory path
47 fs <- fmap (path </>) <$> SD.listDirectory path
38 concat <$> traverse listFilesFullPath fs
48 concat <$> traverse listFilesFullPath fs
39
49
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−
51data SchemaTest = SchemaTest
50data SchemaTest = SchemaTest
52 { _stDescription :: Text
51 { _stDescription :: Text
53 , _stSchema :: Value
52 , _stSchema :: Value
@@ -86,8 +85,8 @@ readSchemaTests dir filterFunc = do
86 fileToCases :: FilePath -> IO [SchemaTest]
85 fileToCases :: FilePath -> IO [SchemaTest]
87 fileToCases name = do
86 fileToCases name = do
88 let fullPath = dir </> name
87 let fullPath = dir </> name
89− jsonBS <- LBS.readFile fullPath
88+ jsonBS <- BS.readFile fullPath
90− case eitherDecode jsonBS of
89+ case eitherDecodeStrict jsonBS of
91 Left e -> fail $ "couldn't parse file '" <> fullPath <> "': " <> e
90 Left e -> fail $ "couldn't parse file '" <> fullPath <> "': " <> e
92 Right schemaTests -> pure $ prependFileName name <$> schemaTests
91 Right schemaTests -> pure $ prependFileName name <$> schemaTests
93
92