Adds openapi v3.0.3 unit test spec, includes test cases, autogenerates model tests with them (#12619)

* Adds draft6 tests and python file reader

* Adds processing of multiple files

* Moves test examples into a different component so component schemas can be booleans

* Excludes boolean schema cases and some others that contain patternProperties

* Adds automatic test generation, template not quite working with indentation

* Turns on allOf tests, some failing

* Adds more generated components and tests

* Adds enum tests

* Turns on all of themissing tests

* Adds exclmax and min exclusion reasons

* Adds items test cases

* Adds maximum

* Adds maxItems

* Adds maxLength

* Adds maxProperties

* Adds minimum

* Adds minItems

* Adds minLength

* Adds minProperties

* Adds multipleOf

* Adds not

* Adds oneOf

* Adds pattern

* Adds patternProperties

* Working on properties examples, partial fix for escaped characters

* Further improves example string escaping

* Fixes properties test cases

* Adds draft6 test samples license

* Adds ref

* Finishes ref

* Adds remoteRef

* Adds required

* Improves required testing

* Fixes build error / javadoc warning

* Fixes uniqueItems bug in python-experimental

* Turns all tests back on

* Fixes 2 failing tests, all python tests pass

* Fixes java npe errors

* Fixes formatting of tests, indentation fixed

* Test fase name fixed to toTestCaseName, docstring added to ObjectWithTypeBooleans

* Fixes typo

* Adds test deletion to samples generation, samples regenerated

* Updates python-exp unit test sample, includes new ref examples
This commit is contained in:
Justin Black 2022-07-01 13:46:02 -07:00 committed by GitHub
parent 4cf58f5886
commit 6158274f65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
302 changed files with 26948 additions and 52 deletions

View File

@ -80,6 +80,7 @@ elif [ "$NODE_INDEX" = "4" ]; then
#mvn --no-snapshot-updates --quiet verify -Psamples.circleci.node4 -Dorg.slf4j.simpleLogger.defaultLogLevel=error
(cd samples/openapi3/client/petstore/python && make test)
(cd samples/openapi3/client/petstore/python-experimental && make test)
(cd samples/openapi3/client/3_0_3_unit_test/python-experimental && make test)
else
echo "Running node $NODE_INDEX to test 'samples.circleci.others' defined in pom.xml ..."

View File

@ -0,0 +1,6 @@
generatorName: python-experimental
outputDir: samples/openapi3/client/3_0_3_unit_test/python-experimental
inputSpec: modules/openapi-generator/src/test/resources/3_0/unit_test_spec/3_0_3_unit_test_spec.yaml
templateDir: modules/openapi-generator/src/main/resources/python-experimental
additionalProperties:
packageName: unit_test_api

View File

@ -55,6 +55,8 @@ else
echo "Please press CTRL+C to stop or the script will continue in 5 seconds."
sleep 5
# delete the 3_0_3 python-experimental tests because they are autogenerated our tooling needs to see differences
rm -rf "${root}/samples/openapi3/client/3_0_3_unit_test/python-experimental/test"
if [ ${#files[@]} -eq 0 ]; then
files=("${root}"/bin/configs/*.yaml)

View File

@ -109,6 +109,7 @@ public class CodegenModel implements IJsonSchemaValidationProperties {
public Map<String, Object> vendorExtensions = new HashMap<>();
private CodegenComposedSchemas composedSchemas;
private boolean hasMultipleTypes = false;
public HashMap<String, SchemaTestCase> testCases = new HashMap<>();
/**
* The type of the value for the additionalProperties keyword in the OAS document.

View File

@ -2696,6 +2696,52 @@ public class DefaultCodegen implements CodegenConfig {
setAddProps(schema, m);
}
protected String toTestCaseName(String specTestCaseName) {
return specTestCaseName;
}
/**
* A method that allows generators to pre-process test example payloads
* This can be useful if one needs to change how values like null in string are represnted
* @param data the test data payload
* @return the updated test data payload
*/
protected Object processTestExampleData(Object data) {
return data;
}
/**
* Processes any test cases if they exist in the components.x-test-examples vendor extensions
* If they exist then cast them to java class instances and return them back in a map
* @param schemaName the component schema name that the test cases are for
* @param vendorExtensions the extensions that may or may not hold the data
*/
private HashMap<String, SchemaTestCase> extractSchemaTestCases(String schemaName, HashMap<String, Object> vendorExtensions) {
String testExamplesKey = "x-schema-test-examples";
// schemaName to a map of test case name to test case
if (vendorExtensions == null || !vendorExtensions.containsKey(testExamplesKey)) {
return null;
}
HashMap<String, SchemaTestCase> schemaTestCases = new HashMap<>();
LinkedHashMap<String, Object> schemaNameToTestCases = (LinkedHashMap<String, Object>) vendorExtensions.get(testExamplesKey);
if (!schemaNameToTestCases.containsKey(schemaName)) {
return null;
}
LinkedHashMap<String, LinkedHashMap<String, Object>> testNameToTesCase = (LinkedHashMap<String, LinkedHashMap<String, Object>>) schemaNameToTestCases.get(schemaName);
for (Entry<String, LinkedHashMap<String, Object>> entry: testNameToTesCase.entrySet()) {
LinkedHashMap<String, Object> testExample = (LinkedHashMap<String, Object>) entry.getValue();
String nameInSnakeCase = toTestCaseName(entry.getKey());
Object data = processTestExampleData(testExample.get("data"));
SchemaTestCase testCase = new SchemaTestCase(
(String) testExample.getOrDefault("description", ""),
new ObjectWithTypeBooleans(data),
(boolean) testExample.get("valid")
);
schemaTestCases.put(nameInSnakeCase, testCase);
}
return schemaTestCases;
}
/**
* Convert OAS Model object to Codegen Model object.
@ -2721,6 +2767,11 @@ public class DefaultCodegen implements CodegenConfig {
CodegenModel m = CodegenModelFactory.newInstance(CodegenModelType.MODEL);
ModelUtils.syncValidationProperties(schema, m);
if (openAPI != null) {
HashMap<String, Object> vendorExtensions = (HashMap<String, Object>) openAPI.getComponents().getExtensions();
HashMap<String, SchemaTestCase> schemaTestCases = extractSchemaTestCases(name, vendorExtensions);
m.testCases = schemaTestCases;
}
if (reservedWords.contains(name)) {
m.name = escapeReservedWord(name);

View File

@ -0,0 +1,62 @@
package org.openapitools.codegen;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;
public class ObjectWithTypeBooleans {
public boolean isUnboundedInteger;
public boolean isNumber;
public boolean isString;
public boolean isMap;
public boolean isArray;
public boolean isBoolean;
public boolean isNull;
public Object value;
/**
* A wrapper class that is used to store payloads to be ingested by schemas
* This class includes the payload value in the value property
* Other booleans: isUnboundedInteger/isNumber/isString/isMap/isArray/isBoolean/isNull
* allow generator templates to decide how to render each payload into code
* based upon what type it is. The booleans isX describe the value in value.
* @param value the input payload that is stored
*/
public ObjectWithTypeBooleans(Object value) {
Object usedValue = null;
if (value instanceof Integer){
this.isUnboundedInteger = true;
this.value = value;
} else if (value instanceof Double || value instanceof Float){
this.isNumber = true;
this.value = value;
} else if (value instanceof String) {
this.isString = true;
this.value = value;
} else if (value instanceof LinkedHashMap) {
LinkedHashMap<String, Object> castValue = (LinkedHashMap<String, Object>) value;
LinkedHashMap<ObjectWithTypeBooleans, ObjectWithTypeBooleans> castMap = new LinkedHashMap<>();
for (Map.Entry entry: castValue.entrySet()) {
ObjectWithTypeBooleans entryKey = new ObjectWithTypeBooleans(entry.getKey());
ObjectWithTypeBooleans entryValue = new ObjectWithTypeBooleans(entry.getValue());
castMap.put(entryKey, entryValue);
}
this.value = castMap;
this.isMap = true;
} else if (value instanceof ArrayList) {
ArrayList<ObjectWithTypeBooleans> castList = new ArrayList<>();
for (Object item: (ArrayList<Object>) value) {
castList.add(new ObjectWithTypeBooleans(item));
}
this.value = castList;
this.isArray = true;
} else if (value instanceof Boolean) {
this.isBoolean = true;
this.value = value;
} else if (value == null) {
this.isNull = true;
this.value = value;
}
}
}

View File

@ -0,0 +1,14 @@
package org.openapitools.codegen;
public class SchemaTestCase {
public String description;
public ObjectWithTypeBooleans data;
// true means the test case should pass, false means it should fail
public boolean valid;
public SchemaTestCase(String description, ObjectWithTypeBooleans data, boolean valid) {
this.description = description;
this.data = data;
this.valid = valid;
}
}

View File

@ -19,6 +19,7 @@ package org.openapitools.codegen.languages;
import com.github.curiousoddman.rgxgen.RgxGen;
import com.github.curiousoddman.rgxgen.config.RgxGenOption;
import com.github.curiousoddman.rgxgen.config.RgxGenProperties;
import com.google.common.base.CaseFormat;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.servers.Server;
@ -848,6 +849,7 @@ public class PythonExperimentalClientCodegen extends AbstractPythonCodegen {
// templates use its presence to handle these badly named variables / keys
if ((isReservedWord(name) || !isValidPythonVarOrClassName(name)) && !name.equals(cp.name)) {
cp.nameInSnakeCase = cp.name;
cp.baseName = (String) processTestExampleData(name);
} else {
cp.nameInSnakeCase = null;
}
@ -1127,7 +1129,8 @@ public class PythonExperimentalClientCodegen extends AbstractPythonCodegen {
} else if ("bool".equals(datatype)) {
return value.substring(0, 1).toUpperCase(Locale.ROOT) + value.substring(1);
} else {
return ensureQuotes(value);
String fixedValue = (String) processTestExampleData(value);
return ensureQuotes(fixedValue);
}
}
@ -1152,6 +1155,67 @@ public class PythonExperimentalClientCodegen extends AbstractPythonCodegen {
model.dataType = getTypeString(schema, "", "", referencedModelNames);
}
protected String toTestCaseName(String specTestCaseName) {
return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, specTestCaseName);
}
protected Object processTestExampleData(Object value) {
if (value instanceof Integer){
return value;
} else if (value instanceof Double || value instanceof Float || value instanceof Boolean){
return value;
} else if (value instanceof String) {
String stringValue = (String) value;
String backslash = "\\";
if (stringValue.contains(backslash)) {
stringValue = stringValue.replace(backslash, "\\\\");
}
String nullChar = "\0";
if (stringValue.contains(nullChar)) {
stringValue = stringValue.replace(nullChar, "\\x00");
}
String doubleQuoteChar = "\"";
if (stringValue.contains(doubleQuoteChar)) {
stringValue = stringValue.replace(doubleQuoteChar, "\\\"");
}
String lineSep = System.lineSeparator();
if (stringValue.contains(lineSep)) {
stringValue = stringValue.replace(lineSep, "\\n");
}
String carriageReturn = "\r";
if (stringValue.contains(carriageReturn)) {
stringValue = stringValue.replace(carriageReturn, "\\r");
}
String tab = "\t";
if (stringValue.contains(tab)) {
stringValue = stringValue.replace(tab, "\\t");
}
String formFeed = "\f";
if (stringValue.contains(formFeed)) {
stringValue = stringValue.replace(formFeed, "\\f");
}
return stringValue;
} else if (value instanceof LinkedHashMap) {
LinkedHashMap<String, Object> fixedValues = new LinkedHashMap();
for (Map.Entry entry: ((LinkedHashMap<String, Object>) value).entrySet()) {
String entryKey = (String) processTestExampleData(entry.getKey());
Object entryValue = processTestExampleData(entry.getValue());
fixedValues.put(entryKey, entryValue);
}
return fixedValues;
} else if (value instanceof ArrayList) {
ArrayList<Object> fixedValues = (ArrayList<Object>) value;
for (int i = 0; i < fixedValues.size(); i++) {
Object item = processTestExampleData(fixedValues.get(i));
fixedValues.set(i, item);
}
return fixedValues;
} else if (value == null) {
return value;
}
return value;
}
/**
* Convert OAS Model object to Codegen Model object
* We have a custom version of this method so we can:
@ -1388,12 +1452,6 @@ public class PythonExperimentalClientCodegen extends AbstractPythonCodegen {
* @return quoted string
*/
private String ensureQuotes(String in) {
Pattern pattern = Pattern.compile("\r\n|\r|\n");
Matcher matcher = pattern.matcher(in);
if (matcher.find()) {
// if a string has a new line in it add triple quotes to make it a python multiline string
return "'''" + in + "'''";
}
String strPattern = "^['\"].*?['\"]$";
if (in.matches(strPattern)) {
return in;

View File

@ -0,0 +1,35 @@
{{#if isMap}}
{
{{#each value}}
{{#with @key}}
{{> model_templates/payload_renderer endChar=':'}}
{{/with}}
{{#with this}}
{{> model_templates/payload_renderer endChar=','}}
{{/with}}
{{/each}}
}{{endChar}}
{{/if}}
{{#if isArray}}
[
{{#each value}}
{{> model_templates/payload_renderer endChar=','}}
{{/each}}
]{{endChar}}
{{/if}}
{{#or isNumber isUnboundedInteger}}
{{value}}{{endChar}}
{{/or}}
{{#if isBoolean}}
{{#if value}}
True{{endChar}}
{{else}}
False{{endChar}}
{{/if}}
{{/if}}
{{#if isNull}}
None{{endChar}}
{{/if}}
{{#if isString}}
"{{{value}}}"{{endChar}}
{{/if}}

View File

@ -39,7 +39,7 @@
{{/or}}
{{/or}}
{{#if nameInSnakeCase}}
locals()['{{baseName}}'] = {{name}}
locals()["{{{baseName}}}"] = {{name}}
del locals()['{{name}}']
{{/if}}
{{/if}}

View File

@ -14,9 +14,9 @@ _SchemaValidator(
{{#if minItems}}
min_items={{minItems}},
{{/if}}
{{#if maxProperties}}
{{#neq maxProperties null }}
max_properties={{maxProperties}},
{{/if}}
{{/neq}}
{{#if minProperties}}
min_properties={{minProperties}},
{{/if}}

View File

@ -8,23 +8,36 @@ import {{packageName}}
{{#each models}}
{{#with model}}
from {{packageName}}.{{modelPackage}}.{{classFilename}} import {{classname}}
from {{packageName}} import configuration
class Test{{classname}}(unittest.TestCase):
"""{{classname}} unit test stubs"""
_configuration = configuration.Configuration()
def setUp(self):
pass
def tearDown(self):
pass
def test_{{classname}}(self):
"""Test {{classname}}"""
# FIXME: construct object with mandatory attributes with example values
# model = {{classname}}() # noqa: E501
pass
{{#each testCases}}
{{#with this }}
def test_{{@key}}_{{#if valid}}passes{{else}}fails{{/if}}(self):
# {{description}}
{{#if valid}}
{{classname}}._from_openapi_data(
{{#with data}}
{{> model_templates/payload_renderer endChar=',' }}
{{/with}}
_configuration=self._configuration
)
{{else}}
with self.assertRaises(({{packageName}}.ApiValueError, {{packageName}}.ApiTypeError)):
{{classname}}._from_openapi_data(
{{#with data}}
{{> model_templates/payload_renderer endChar=','}}
{{/with}}
_configuration=self._configuration
)
{{/if}}
{{/with}}
{{/each}}
{{/with}}
{{/each}}

View File

@ -194,6 +194,31 @@ class ValidatorBase:
path_to_item=validation_metadata.path_to_item
)
@classmethod
def __data_with_boolclass_instead_of_bool(cls, data: typing.Any) -> typing.Any:
"""
In python bool is a subclass of int so 1 == True and 0 == False
This prevents code from being able to see the difference between 1 and True and 0 and False
To fix this swap in BoolClass singletons for True and False so they will differ from integers
"""
if isinstance(data, (list, tuple)):
new_data = []
for item in data:
new_item = cls.__data_with_boolclass_instead_of_bool(item)
new_data.append(new_item)
return tuple(new_data)
elif isinstance(data, (dict, frozendict)):
new_data = {}
for key, value in data.items():
new_value = cls.__data_with_boolclass_instead_of_bool(value)
new_data[key] = new_value
return frozendict(new_data)
elif isinstance(data, bool):
if data:
return BoolClass.TRUE
return BoolClass.FALSE
return data
@classmethod
def __check_tuple_validations(
cls, validations, input_values,
@ -221,10 +246,7 @@ class ValidatorBase:
if (cls.__is_json_validation_enabled('uniqueItems', validation_metadata.configuration) and
'unique_items' in validations and validations['unique_items'] and input_values):
unique_items = []
for item in input_values:
if item not in unique_items:
unique_items.append(item)
unique_items = set(cls.__data_with_boolclass_instead_of_bool(input_values))
if len(input_values) > len(unique_items):
cls.__raise_validation_error_message(
value=input_values,
@ -1865,8 +1887,9 @@ class IntBase(NumberBase):
@classmethod
def _validate_format(cls, arg: typing.Optional[decimal.Decimal], validation_metadata: ValidationMetadata):
if isinstance(arg, decimal.Decimal):
exponent = arg.as_tuple().exponent
if exponent != 0:
denominator = arg.as_integer_ratio()[-1]
if denominator != 1:
raise ApiValueError(
"Invalid value '{}' for type integer at {}".format(arg, validation_metadata.path_to_item)
)

View File

@ -0,0 +1 @@
venv

View File

@ -0,0 +1,19 @@
Copyright (c) 2012 Julian Berman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,149 @@
[
{
"description": "additionalItems as schema",
"schema": {
"items": [{}],
"additionalItems": {"type": "integer"}
},
"tests": [
{
"description": "additional items match schema",
"data": [ null, 2, 3, 4 ],
"valid": true
},
{
"description": "additional items do not match schema",
"data": [ null, 2, 3, "foo" ],
"valid": false
}
]
},
{
"description": "when items is schema, additionalItems does nothing",
"schema": {
"items": {},
"additionalItems": false
},
"tests": [
{
"description": "all items match schema",
"data": [ 1, 2, 3, 4, 5 ],
"valid": true
}
]
},
{
"description": "array of items with no additionalItems permitted",
"schema": {
"items": [{}, {}, {}],
"additionalItems": false
},
"tests": [
{
"description": "empty array",
"data": [ ],
"valid": true
},
{
"description": "fewer number of items present (1)",
"data": [ 1 ],
"valid": true
},
{
"description": "fewer number of items present (2)",
"data": [ 1, 2 ],
"valid": true
},
{
"description": "equal number of items present",
"data": [ 1, 2, 3 ],
"valid": true
},
{
"description": "additional items are not permitted",
"data": [ 1, 2, 3, 4 ],
"valid": false
}
]
},
{
"description": "additionalItems as false without items",
"schema": {"additionalItems": false},
"tests": [
{
"description":
"items defaults to empty schema so everything is valid",
"data": [ 1, 2, 3, 4, 5 ],
"valid": true
},
{
"description": "ignores non-arrays",
"data": {"foo" : "bar"},
"valid": true
}
]
},
{
"description": "additionalItems are allowed by default",
"schema": {"items": [{"type": "integer"}]},
"tests": [
{
"description": "only the first item is validated",
"data": [1, "foo", false],
"valid": true
}
]
},
{
"description": "additionalItems should not look in applicators, valid case",
"schema": {
"allOf": [
{ "items": [ { "type": "integer" } ] }
],
"additionalItems": { "type": "boolean" }
},
"tests": [
{
"description": "items defined in allOf are not examined",
"data": [ 1, null ],
"valid": true
}
]
},
{
"description": "additionalItems should not look in applicators, invalid case",
"schema": {
"allOf": [
{ "items": [ { "type": "integer" }, { "type": "string" } ] }
],
"items": [ {"type": "integer" } ],
"additionalItems": { "type": "boolean" }
},
"tests": [
{
"description": "items defined in allOf are not examined",
"data": [ 1, "hello" ],
"valid": false
}
]
},
{
"description": "items validation adjusts the starting index for additionalItems",
"schema": {
"items": [ { "type": "string" } ],
"additionalItems": { "type": "integer" }
},
"tests": [
{
"description": "valid items",
"data": [ "x", 2, 3 ],
"valid": true
},
{
"description": "wrong type of second item",
"data": [ "x", "y" ],
"valid": false
}
]
}
]

View File

@ -0,0 +1,133 @@
[
{
"description":
"additionalProperties being false does not allow other properties",
"schema": {
"properties": {"foo": {}, "bar": {}},
"patternProperties": { "^v": {} },
"additionalProperties": false
},
"tests": [
{
"description": "no additional properties is valid",
"data": {"foo": 1},
"valid": true
},
{
"description": "an additional property is invalid",
"data": {"foo" : 1, "bar" : 2, "quux" : "boom"},
"valid": false
},
{
"description": "ignores arrays",
"data": [1, 2, 3],
"valid": true
},
{
"description": "ignores strings",
"data": "foobarbaz",
"valid": true
},
{
"description": "ignores other non-objects",
"data": 12,
"valid": true
},
{
"description": "patternProperties are not additional properties",
"data": {"foo":1, "vroom": 2},
"valid": true
}
]
},
{
"description": "non-ASCII pattern with additionalProperties",
"schema": {
"patternProperties": {"^á": {}},
"additionalProperties": false
},
"tests": [
{
"description": "matching the pattern is valid",
"data": {"ármányos": 2},
"valid": true
},
{
"description": "not matching the pattern is invalid",
"data": {"élmény": 2},
"valid": false
}
]
},
{
"description":
"additionalProperties allows a schema which should validate",
"schema": {
"properties": {"foo": {}, "bar": {}},
"additionalProperties": {"type": "boolean"}
},
"tests": [
{
"description": "no additional properties is valid",
"data": {"foo": 1},
"valid": true
},
{
"description": "an additional valid property is valid",
"data": {"foo" : 1, "bar" : 2, "quux" : true},
"valid": true
},
{
"description": "an additional invalid property is invalid",
"data": {"foo" : 1, "bar" : 2, "quux" : 12},
"valid": false
}
]
},
{
"description":
"additionalProperties can exist by itself",
"schema": {
"additionalProperties": {"type": "boolean"}
},
"tests": [
{
"description": "an additional valid property is valid",
"data": {"foo" : true},
"valid": true
},
{
"description": "an additional invalid property is invalid",
"data": {"foo" : 1},
"valid": false
}
]
},
{
"description": "additionalProperties are allowed by default",
"schema": {"properties": {"foo": {}, "bar": {}}},
"tests": [
{
"description": "additional properties are allowed",
"data": {"foo": 1, "bar": 2, "quux": true},
"valid": true
}
]
},
{
"description": "additionalProperties should not look in applicators",
"schema": {
"allOf": [
{"properties": {"foo": {}}}
],
"additionalProperties": {"type": "boolean"}
},
"tests": [
{
"description": "properties defined in allOf are not examined",
"data": {"foo": 1, "bar": true},
"valid": false
}
]
}
]

View File

@ -0,0 +1,294 @@
[
{
"description": "allOf",
"schema": {
"allOf": [
{
"properties": {
"bar": {"type": "integer"}
},
"required": ["bar"]
},
{
"properties": {
"foo": {"type": "string"}
},
"required": ["foo"]
}
]
},
"tests": [
{
"description": "allOf",
"data": {"foo": "baz", "bar": 2},
"valid": true
},
{
"description": "mismatch second",
"data": {"foo": "baz"},
"valid": false
},
{
"description": "mismatch first",
"data": {"bar": 2},
"valid": false
},
{
"description": "wrong type",
"data": {"foo": "baz", "bar": "quux"},
"valid": false
}
]
},
{
"description": "allOf with base schema",
"schema": {
"properties": {"bar": {"type": "integer"}},
"required": ["bar"],
"allOf" : [
{
"properties": {
"foo": {"type": "string"}
},
"required": ["foo"]
},
{
"properties": {
"baz": {"type": "null"}
},
"required": ["baz"]
}
]
},
"tests": [
{
"description": "valid",
"data": {"foo": "quux", "bar": 2, "baz": null},
"valid": true
},
{
"description": "mismatch base schema",
"data": {"foo": "quux", "baz": null},
"valid": false
},
{
"description": "mismatch first allOf",
"data": {"bar": 2, "baz": null},
"valid": false
},
{
"description": "mismatch second allOf",
"data": {"foo": "quux", "bar": 2},
"valid": false
},
{
"description": "mismatch both",
"data": {"bar": 2},
"valid": false
}
]
},
{
"description": "allOf simple types",
"schema": {
"allOf": [
{"maximum": 30},
{"minimum": 20}
]
},
"tests": [
{
"description": "valid",
"data": 25,
"valid": true
},
{
"description": "mismatch one",
"data": 35,
"valid": false
}
]
},
{
"description": "allOf with boolean schemas, all true",
"schema": {"allOf": [true, true]},
"tests": [
{
"description": "any value is valid",
"data": "foo",
"valid": true
}
]
},
{
"description": "allOf with boolean schemas, some false",
"schema": {"allOf": [true, false]},
"tests": [
{
"description": "any value is invalid",
"data": "foo",
"valid": false
}
]
},
{
"description": "allOf with boolean schemas, all false",
"schema": {"allOf": [false, false]},
"tests": [
{
"description": "any value is invalid",
"data": "foo",
"valid": false
}
]
},
{
"description": "allOf with one empty schema",
"schema": {
"allOf": [
{}
]
},
"tests": [
{
"description": "any data is valid",
"data": 1,
"valid": true
}
]
},
{
"description": "allOf with two empty schemas",
"schema": {
"allOf": [
{},
{}
]
},
"tests": [
{
"description": "any data is valid",
"data": 1,
"valid": true
}
]
},
{
"description": "allOf with the first empty schema",
"schema": {
"allOf": [
{},
{ "type": "number" }
]
},
"tests": [
{
"description": "number is valid",
"data": 1,
"valid": true
},
{
"description": "string is invalid",
"data": "foo",
"valid": false
}
]
},
{
"description": "allOf with the last empty schema",
"schema": {
"allOf": [
{ "type": "number" },
{}
]
},
"tests": [
{
"description": "number is valid",
"data": 1,
"valid": true
},
{
"description": "string is invalid",
"data": "foo",
"valid": false
}
]
},
{
"description": "nested allOf, to check validation semantics",
"schema": {
"allOf": [
{
"allOf": [
{
"type": "null"
}
]
}
]
},
"tests": [
{
"description": "null is valid",
"data": null,
"valid": true
},
{
"description": "anything non-null is invalid",
"data": 123,
"valid": false
}
]
},
{
"description": "allOf combined with anyOf, oneOf",
"schema": {
"allOf": [ { "multipleOf": 2 } ],
"anyOf": [ { "multipleOf": 3 } ],
"oneOf": [ { "multipleOf": 5 } ]
},
"tests": [
{
"description": "allOf: false, anyOf: false, oneOf: false",
"data": 1,
"valid": false
},
{
"description": "allOf: false, anyOf: false, oneOf: true",
"data": 5,
"valid": false
},
{
"description": "allOf: false, anyOf: true, oneOf: false",
"data": 3,
"valid": false
},
{
"description": "allOf: false, anyOf: true, oneOf: true",
"data": 15,
"valid": false
},
{
"description": "allOf: true, anyOf: false, oneOf: false",
"data": 2,
"valid": false
},
{
"description": "allOf: true, anyOf: false, oneOf: true",
"data": 10,
"valid": false
},
{
"description": "allOf: true, anyOf: true, oneOf: false",
"data": 6,
"valid": false
},
{
"description": "allOf: true, anyOf: true, oneOf: true",
"data": 30,
"valid": true
}
]
}
]

View File

@ -0,0 +1,215 @@
[
{
"description": "anyOf",
"schema": {
"anyOf": [
{
"type": "integer"
},
{
"minimum": 2
}
]
},
"tests": [
{
"description": "first anyOf valid",
"data": 1,
"valid": true
},
{
"description": "second anyOf valid",
"data": 2.5,
"valid": true
},
{
"description": "both anyOf valid",
"data": 3,
"valid": true
},
{
"description": "neither anyOf valid",
"data": 1.5,
"valid": false
}
]
},
{
"description": "anyOf with base schema",
"schema": {
"type": "string",
"anyOf" : [
{
"maxLength": 2
},
{
"minLength": 4
}
]
},
"tests": [
{
"description": "mismatch base schema",
"data": 3,
"valid": false
},
{
"description": "one anyOf valid",
"data": "foobar",
"valid": true
},
{
"description": "both anyOf invalid",
"data": "foo",
"valid": false
}
]
},
{
"description": "anyOf with boolean schemas, all true",
"schema": {"anyOf": [true, true]},
"tests": [
{
"description": "any value is valid",
"data": "foo",
"valid": true
}
]
},
{
"description": "anyOf with boolean schemas, some true",
"schema": {"anyOf": [true, false]},
"tests": [
{
"description": "any value is valid",
"data": "foo",
"valid": true
}
]
},
{
"description": "anyOf with boolean schemas, all false",
"schema": {"anyOf": [false, false]},
"tests": [
{
"description": "any value is invalid",
"data": "foo",
"valid": false
}
]
},
{
"description": "anyOf complex types",
"schema": {
"anyOf": [
{
"properties": {
"bar": {"type": "integer"}
},
"required": ["bar"]
},
{
"properties": {
"foo": {"type": "string"}
},
"required": ["foo"]
}
]
},
"tests": [
{
"description": "first anyOf valid (complex)",
"data": {"bar": 2},
"valid": true
},
{
"description": "second anyOf valid (complex)",
"data": {"foo": "baz"},
"valid": true
},
{
"description": "both anyOf valid (complex)",
"data": {"foo": "baz", "bar": 2},
"valid": true
},
{
"description": "neither anyOf valid (complex)",
"data": {"foo": 2, "bar": "quux"},
"valid": false
}
]
},
{
"description": "anyOf with one empty schema",
"schema": {
"anyOf": [
{ "type": "number" },
{}
]
},
"tests": [
{
"description": "string is valid",
"data": "foo",
"valid": true
},
{
"description": "number is valid",
"data": 123,
"valid": true
}
]
},
{
"description": "nested anyOf, to check validation semantics",
"schema": {
"anyOf": [
{
"anyOf": [
{
"type": "null"
}
]
}
]
},
"tests": [
{
"description": "null is valid",
"data": null,
"valid": true
},
{
"description": "anything non-null is invalid",
"data": 123,
"valid": false
}
]
},
{
"description": "nested anyOf, to check validation semantics",
"schema": {
"anyOf": [
{
"anyOf": [
{
"type": "null"
}
]
}
]
},
"tests": [
{
"description": "null is valid",
"data": null,
"valid": true
},
{
"description": "anything non-null is invalid",
"data": 123,
"valid": false
}
]
}
]

View File

@ -0,0 +1,104 @@
[
{
"description": "boolean schema 'true'",
"schema": true,
"tests": [
{
"description": "number is valid",
"data": 1,
"valid": true
},
{
"description": "string is valid",
"data": "foo",
"valid": true
},
{
"description": "boolean true is valid",
"data": true,
"valid": true
},
{
"description": "boolean false is valid",
"data": false,
"valid": true
},
{
"description": "null is valid",
"data": null,
"valid": true
},
{
"description": "object is valid",
"data": {"foo": "bar"},
"valid": true
},
{
"description": "empty object is valid",
"data": {},
"valid": true
},
{
"description": "array is valid",
"data": ["foo"],
"valid": true
},
{
"description": "empty array is valid",
"data": [],
"valid": true
}
]
},
{
"description": "boolean schema 'false'",
"schema": false,
"tests": [
{
"description": "number is invalid",
"data": 1,
"valid": false
},
{
"description": "string is invalid",
"data": "foo",
"valid": false
},
{
"description": "boolean true is invalid",
"data": true,
"valid": false
},
{
"description": "boolean false is invalid",
"data": false,
"valid": false
},
{
"description": "null is invalid",
"data": null,
"valid": false
},
{
"description": "object is invalid",
"data": {"foo": "bar"},
"valid": false
},
{
"description": "empty object is invalid",
"data": {},
"valid": false
},
{
"description": "array is invalid",
"data": ["foo"],
"valid": false
},
{
"description": "empty array is invalid",
"data": [],
"valid": false
}
]
}
]

View File

@ -0,0 +1,342 @@
[
{
"description": "const validation",
"schema": {"const": 2},
"tests": [
{
"description": "same value is valid",
"data": 2,
"valid": true
},
{
"description": "another value is invalid",
"data": 5,
"valid": false
},
{
"description": "another type is invalid",
"data": "a",
"valid": false
}
]
},
{
"description": "const with object",
"schema": {"const": {"foo": "bar", "baz": "bax"}},
"tests": [
{
"description": "same object is valid",
"data": {"foo": "bar", "baz": "bax"},
"valid": true
},
{
"description": "same object with different property order is valid",
"data": {"baz": "bax", "foo": "bar"},
"valid": true
},
{
"description": "another object is invalid",
"data": {"foo": "bar"},
"valid": false
},
{
"description": "another type is invalid",
"data": [1, 2],
"valid": false
}
]
},
{
"description": "const with array",
"schema": {"const": [{ "foo": "bar" }]},
"tests": [
{
"description": "same array is valid",
"data": [{"foo": "bar"}],
"valid": true
},
{
"description": "another array item is invalid",
"data": [2],
"valid": false
},
{
"description": "array with additional items is invalid",
"data": [1, 2, 3],
"valid": false
}
]
},
{
"description": "const with null",
"schema": {"const": null},
"tests": [
{
"description": "null is valid",
"data": null,
"valid": true
},
{
"description": "not null is invalid",
"data": 0,
"valid": false
}
]
},
{
"description": "const with false does not match 0",
"schema": {"const": false},
"tests": [
{
"description": "false is valid",
"data": false,
"valid": true
},
{
"description": "integer zero is invalid",
"data": 0,
"valid": false
},
{
"description": "float zero is invalid",
"data": 0.0,
"valid": false
}
]
},
{
"description": "const with true does not match 1",
"schema": {"const": true},
"tests": [
{
"description": "true is valid",
"data": true,
"valid": true
},
{
"description": "integer one is invalid",
"data": 1,
"valid": false
},
{
"description": "float one is invalid",
"data": 1.0,
"valid": false
}
]
},
{
"description": "const with [false] does not match [0]",
"schema": {"const": [false]},
"tests": [
{
"description": "[false] is valid",
"data": [false],
"valid": true
},
{
"description": "[0] is invalid",
"data": [0],
"valid": false
},
{
"description": "[0.0] is invalid",
"data": [0.0],
"valid": false
}
]
},
{
"description": "const with [true] does not match [1]",
"schema": {"const": [true]},
"tests": [
{
"description": "[true] is valid",
"data": [true],
"valid": true
},
{
"description": "[1] is invalid",
"data": [1],
"valid": false
},
{
"description": "[1.0] is invalid",
"data": [1.0],
"valid": false
}
]
},
{
"description": "const with {\"a\": false} does not match {\"a\": 0}",
"schema": {"const": {"a": false}},
"tests": [
{
"description": "{\"a\": false} is valid",
"data": {"a": false},
"valid": true
},
{
"description": "{\"a\": 0} is invalid",
"data": {"a": 0},
"valid": false
},
{
"description": "{\"a\": 0.0} is invalid",
"data": {"a": 0.0},
"valid": false
}
]
},
{
"description": "const with {\"a\": true} does not match {\"a\": 1}",
"schema": {"const": {"a": true}},
"tests": [
{
"description": "{\"a\": true} is valid",
"data": {"a": true},
"valid": true
},
{
"description": "{\"a\": 1} is invalid",
"data": {"a": 1},
"valid": false
},
{
"description": "{\"a\": 1.0} is invalid",
"data": {"a": 1.0},
"valid": false
}
]
},
{
"description": "const with 0 does not match other zero-like types",
"schema": {"const": 0},
"tests": [
{
"description": "false is invalid",
"data": false,
"valid": false
},
{
"description": "integer zero is valid",
"data": 0,
"valid": true
},
{
"description": "float zero is valid",
"data": 0.0,
"valid": true
},
{
"description": "empty object is invalid",
"data": {},
"valid": false
},
{
"description": "empty array is invalid",
"data": [],
"valid": false
},
{
"description": "empty string is invalid",
"data": "",
"valid": false
}
]
},
{
"description": "const with 1 does not match true",
"schema": {"const": 1},
"tests": [
{
"description": "true is invalid",
"data": true,
"valid": false
},
{
"description": "integer one is valid",
"data": 1,
"valid": true
},
{
"description": "float one is valid",
"data": 1.0,
"valid": true
}
]
},
{
"description": "const with -2.0 matches integer and float types",
"schema": {"const": -2.0},
"tests": [
{
"description": "integer -2 is valid",
"data": -2,
"valid": true
},
{
"description": "integer 2 is invalid",
"data": 2,
"valid": false
},
{
"description": "float -2.0 is valid",
"data": -2.0,
"valid": true
},
{
"description": "float 2.0 is invalid",
"data": 2.0,
"valid": false
},
{
"description": "float -2.00001 is invalid",
"data": -2.00001,
"valid": false
}
]
},
{
"description": "float and integers are equal up to 64-bit representation limits",
"schema": {"const": 9007199254740992},
"tests": [
{
"description": "integer is valid",
"data": 9007199254740992,
"valid": true
},
{
"description": "integer minus one is invalid",
"data": 9007199254740991,
"valid": false
},
{
"description": "float is valid",
"data": 9007199254740992.0,
"valid": true
},
{
"description": "float minus one is invalid",
"data": 9007199254740991.0,
"valid": false
}
]
},
{
"description": "nul characters in strings",
"schema": { "const": "hello\u0000there" },
"tests": [
{
"description": "match string with nul",
"data": "hello\u0000there",
"valid": true
},
{
"description": "do not match string lacking nul",
"data": "hellothere",
"valid": false
}
]
}
]

View File

@ -0,0 +1,129 @@
[
{
"description": "contains keyword validation",
"schema": {
"contains": {"minimum": 5}
},
"tests": [
{
"description": "array with item matching schema (5) is valid",
"data": [3, 4, 5],
"valid": true
},
{
"description": "array with item matching schema (6) is valid",
"data": [3, 4, 6],
"valid": true
},
{
"description": "array with two items matching schema (5, 6) is valid",
"data": [3, 4, 5, 6],
"valid": true
},
{
"description": "array without items matching schema is invalid",
"data": [2, 3, 4],
"valid": false
},
{
"description": "empty array is invalid",
"data": [],
"valid": false
},
{
"description": "not array is valid",
"data": {},
"valid": true
}
]
},
{
"description": "contains keyword with const keyword",
"schema": {
"contains": { "const": 5 }
},
"tests": [
{
"description": "array with item 5 is valid",
"data": [3, 4, 5],
"valid": true
},
{
"description": "array with two items 5 is valid",
"data": [3, 4, 5, 5],
"valid": true
},
{
"description": "array without item 5 is invalid",
"data": [1, 2, 3, 4],
"valid": false
}
]
},
{
"description": "contains keyword with boolean schema true",
"schema": {"contains": true},
"tests": [
{
"description": "any non-empty array is valid",
"data": ["foo"],
"valid": true
},
{
"description": "empty array is invalid",
"data": [],
"valid": false
}
]
},
{
"description": "contains keyword with boolean schema false",
"schema": {"contains": false},
"tests": [
{
"description": "any non-empty array is invalid",
"data": ["foo"],
"valid": false
},
{
"description": "empty array is invalid",
"data": [],
"valid": false
},
{
"description": "non-arrays are valid",
"data": "contains does not apply to strings",
"valid": true
}
]
},
{
"description": "items + contains",
"schema": {
"items": { "multipleOf": 2 },
"contains": { "multipleOf": 3 }
},
"tests": [
{
"description": "matches items, does not match contains",
"data": [ 2, 4, 8 ],
"valid": false
},
{
"description": "does not match items, matches contains",
"data": [ 3, 6, 9 ],
"valid": false
},
{
"description": "matches both items and contains",
"data": [ 6, 12 ],
"valid": true
},
{
"description": "matches neither items nor contains",
"data": [ 1, 5 ],
"valid": false
}
]
}
]

View File

@ -0,0 +1,79 @@
[
{
"description": "invalid type for default",
"schema": {
"properties": {
"foo": {
"type": "integer",
"default": []
}
}
},
"tests": [
{
"description": "valid when property is specified",
"data": {"foo": 13},
"valid": true
},
{
"description": "still valid when the invalid default is used",
"data": {},
"valid": true
}
]
},
{
"description": "invalid string value for default",
"schema": {
"properties": {
"bar": {
"type": "string",
"minLength": 4,
"default": "bad"
}
}
},
"tests": [
{
"description": "valid when property is specified",
"data": {"bar": "good"},
"valid": true
},
{
"description": "still valid when the invalid default is used",
"data": {},
"valid": true
}
]
},
{
"description": "the default keyword does not do anything if the property is missing",
"schema": {
"type": "object",
"properties": {
"alpha": {
"type": "number",
"maximum": 3,
"default": 5
}
}
},
"tests": [
{
"description": "an explicit property value is checked against maximum (passing)",
"data": { "alpha": 1 },
"valid": true
},
{
"description": "an explicit property value is checked against maximum (failing)",
"data": { "alpha": 5 },
"valid": false
},
{
"description": "missing properties are not filled in with the default",
"data": {},
"valid": true
}
]
}
]

View File

@ -0,0 +1,26 @@
[
{
"description": "validate definition against metaschema",
"schema": {"$ref": "http://json-schema.org/draft-06/schema#"},
"tests": [
{
"description": "valid definition schema",
"data": {
"definitions": {
"foo": {"type": "integer"}
}
},
"valid": true
},
{
"description": "invalid definition schema",
"data": {
"definitions": {
"foo": {"type": 1}
}
},
"valid": false
}
]
}
]

View File

@ -0,0 +1,248 @@
[
{
"description": "dependencies",
"schema": {
"dependencies": {"bar": ["foo"]}
},
"tests": [
{
"description": "neither",
"data": {},
"valid": true
},
{
"description": "nondependant",
"data": {"foo": 1},
"valid": true
},
{
"description": "with dependency",
"data": {"foo": 1, "bar": 2},
"valid": true
},
{
"description": "missing dependency",
"data": {"bar": 2},
"valid": false
},
{
"description": "ignores arrays",
"data": ["bar"],
"valid": true
},
{
"description": "ignores strings",
"data": "foobar",
"valid": true
},
{
"description": "ignores other non-objects",
"data": 12,
"valid": true
}
]
},
{
"description": "dependencies with empty array",
"schema": {
"dependencies": {"bar": []}
},
"tests": [
{
"description": "empty object",
"data": {},
"valid": true
},
{
"description": "object with one property",
"data": {"bar": 2},
"valid": true
},
{
"description": "non-object is valid",
"data": 1,
"valid": true
}
]
},
{
"description": "multiple dependencies",
"schema": {
"dependencies": {"quux": ["foo", "bar"]}
},
"tests": [
{
"description": "neither",
"data": {},
"valid": true
},
{
"description": "nondependants",
"data": {"foo": 1, "bar": 2},
"valid": true
},
{
"description": "with dependencies",
"data": {"foo": 1, "bar": 2, "quux": 3},
"valid": true
},
{
"description": "missing dependency",
"data": {"foo": 1, "quux": 2},
"valid": false
},
{
"description": "missing other dependency",
"data": {"bar": 1, "quux": 2},
"valid": false
},
{
"description": "missing both dependencies",
"data": {"quux": 1},
"valid": false
}
]
},
{
"description": "multiple dependencies subschema",
"schema": {
"dependencies": {
"bar": {
"properties": {
"foo": {"type": "integer"},
"bar": {"type": "integer"}
}
}
}
},
"tests": [
{
"description": "valid",
"data": {"foo": 1, "bar": 2},
"valid": true
},
{
"description": "no dependency",
"data": {"foo": "quux"},
"valid": true
},
{
"description": "wrong type",
"data": {"foo": "quux", "bar": 2},
"valid": false
},
{
"description": "wrong type other",
"data": {"foo": 2, "bar": "quux"},
"valid": false
},
{
"description": "wrong type both",
"data": {"foo": "quux", "bar": "quux"},
"valid": false
}
]
},
{
"description": "dependencies with boolean subschemas",
"schema": {
"dependencies": {
"foo": true,
"bar": false
}
},
"tests": [
{
"description": "object with property having schema true is valid",
"data": {"foo": 1},
"valid": true
},
{
"description": "object with property having schema false is invalid",
"data": {"bar": 2},
"valid": false
},
{
"description": "object with both properties is invalid",
"data": {"foo": 1, "bar": 2},
"valid": false
},
{
"description": "empty object is valid",
"data": {},
"valid": true
}
]
},
{
"description": "dependencies with escaped characters",
"schema": {
"dependencies": {
"foo\nbar": ["foo\rbar"],
"foo\tbar": {
"minProperties": 4
},
"foo'bar": {"required": ["foo\"bar"]},
"foo\"bar": ["foo'bar"]
}
},
"tests": [
{
"description": "valid object 1",
"data": {
"foo\nbar": 1,
"foo\rbar": 2
},
"valid": true
},
{
"description": "valid object 2",
"data": {
"foo\tbar": 1,
"a": 2,
"b": 3,
"c": 4
},
"valid": true
},
{
"description": "valid object 3",
"data": {
"foo'bar": 1,
"foo\"bar": 2
},
"valid": true
},
{
"description": "invalid object 1",
"data": {
"foo\nbar": 1,
"foo": 2
},
"valid": false
},
{
"description": "invalid object 2",
"data": {
"foo\tbar": 1,
"a": 2
},
"valid": false
},
{
"description": "invalid object 3",
"data": {
"foo'bar": 1
},
"valid": false
},
{
"description": "invalid object 4",
"data": {
"foo\"bar": 2
},
"valid": false
}
]
}
]

View File

@ -0,0 +1,236 @@
[
{
"description": "simple enum validation",
"schema": {"enum": [1, 2, 3]},
"tests": [
{
"description": "one of the enum is valid",
"data": 1,
"valid": true
},
{
"description": "something else is invalid",
"data": 4,
"valid": false
}
]
},
{
"description": "heterogeneous enum validation",
"schema": {"enum": [6, "foo", [], true, {"foo": 12}]},
"tests": [
{
"description": "one of the enum is valid",
"data": [],
"valid": true
},
{
"description": "something else is invalid",
"data": null,
"valid": false
},
{
"description": "objects are deep compared",
"data": {"foo": false},
"valid": false
},
{
"description": "valid object matches",
"data": {"foo": 12},
"valid": true
},
{
"description": "extra properties in object is invalid",
"data": {"foo": 12, "boo": 42},
"valid": false
}
]
},
{
"description": "heterogeneous enum-with-null validation",
"schema": { "enum": [6, null] },
"tests": [
{
"description": "null is valid",
"data": null,
"valid": true
},
{
"description": "number is valid",
"data": 6,
"valid": true
},
{
"description": "something else is invalid",
"data": "test",
"valid": false
}
]
},
{
"description": "enums in properties",
"schema": {
"type":"object",
"properties": {
"foo": {"enum":["foo"]},
"bar": {"enum":["bar"]}
},
"required": ["bar"]
},
"tests": [
{
"description": "both properties are valid",
"data": {"foo":"foo", "bar":"bar"},
"valid": true
},
{
"description": "wrong foo value",
"data": {"foo":"foot", "bar":"bar"},
"valid": false
},
{
"description": "wrong bar value",
"data": {"foo":"foo", "bar":"bart"},
"valid": false
},
{
"description": "missing optional property is valid",
"data": {"bar":"bar"},
"valid": true
},
{
"description": "missing required property is invalid",
"data": {"foo":"foo"},
"valid": false
},
{
"description": "missing all properties is invalid",
"data": {},
"valid": false
}
]
},
{
"description": "enum with escaped characters",
"schema": {
"enum": ["foo\nbar", "foo\rbar"]
},
"tests": [
{
"description": "member 1 is valid",
"data": "foo\nbar",
"valid": true
},
{
"description": "member 2 is valid",
"data": "foo\rbar",
"valid": true
},
{
"description": "another string is invalid",
"data": "abc",
"valid": false
}
]
},
{
"description": "enum with false does not match 0",
"schema": {"enum": [false]},
"tests": [
{
"description": "false is valid",
"data": false,
"valid": true
},
{
"description": "integer zero is invalid",
"data": 0,
"valid": false
},
{
"description": "float zero is invalid",
"data": 0.0,
"valid": false
}
]
},
{
"description": "enum with true does not match 1",
"schema": {"enum": [true]},
"tests": [
{
"description": "true is valid",
"data": true,
"valid": true
},
{
"description": "integer one is invalid",
"data": 1,
"valid": false
},
{
"description": "float one is invalid",
"data": 1.0,
"valid": false
}
]
},
{
"description": "enum with 0 does not match false",
"schema": {"enum": [0]},
"tests": [
{
"description": "false is invalid",
"data": false,
"valid": false
},
{
"description": "integer zero is valid",
"data": 0,
"valid": true
},
{
"description": "float zero is valid",
"data": 0.0,
"valid": true
}
]
},
{
"description": "enum with 1 does not match true",
"schema": {"enum": [1]},
"tests": [
{
"description": "true is invalid",
"data": true,
"valid": false
},
{
"description": "integer one is valid",
"data": 1,
"valid": true
},
{
"description": "float one is valid",
"data": 1.0,
"valid": true
}
]
},
{
"description": "nul characters in strings",
"schema": { "enum": [ "hello\u0000there" ] },
"tests": [
{
"description": "match string with nul",
"data": "hello\u0000there",
"valid": true
},
{
"description": "do not match string lacking nul",
"data": "hellothere",
"valid": false
}
]
}
]

View File

@ -0,0 +1,30 @@
[
{
"description": "exclusiveMaximum validation",
"schema": {
"exclusiveMaximum": 3.0
},
"tests": [
{
"description": "below the exclusiveMaximum is valid",
"data": 2.2,
"valid": true
},
{
"description": "boundary point is invalid",
"data": 3.0,
"valid": false
},
{
"description": "above the exclusiveMaximum is invalid",
"data": 3.5,
"valid": false
},
{
"description": "ignores non-numbers",
"data": "x",
"valid": true
}
]
}
]

View File

@ -0,0 +1,30 @@
[
{
"description": "exclusiveMinimum validation",
"schema": {
"exclusiveMinimum": 1.1
},
"tests": [
{
"description": "above the exclusiveMinimum is valid",
"data": 1.2,
"valid": true
},
{
"description": "boundary point is invalid",
"data": 1.1,
"valid": false
},
{
"description": "below the exclusiveMinimum is invalid",
"data": 0.6,
"valid": false
},
{
"description": "ignores non-numbers",
"data": "x",
"valid": true
}
]
}
]

View File

@ -0,0 +1,326 @@
[
{
"description": "email format",
"schema": { "format": "email" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
},
{
"description": "ipv4 format",
"schema": { "format": "ipv4" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
},
{
"description": "ipv6 format",
"schema": { "format": "ipv6" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
},
{
"description": "hostname format",
"schema": { "format": "hostname" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
},
{
"description": "date-time format",
"schema": { "format": "date-time" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
},
{
"description": "json-pointer format",
"schema": { "format": "json-pointer" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
},
{
"description": "uri format",
"schema": { "format": "uri" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
},
{
"description": "uri-reference format",
"schema": { "format": "uri-reference" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
},
{
"description": "uri-template format",
"schema": { "format": "uri-template" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
}
]

View File

@ -0,0 +1,53 @@
[
{
"description": "id inside an enum is not a real identifier",
"comment": "the implementation must not be confused by an id buried in the enum",
"schema": {
"definitions": {
"id_in_enum": {
"enum": [
{
"$id": "https://localhost:1234/id/my_identifier.json",
"type": "null"
}
]
},
"real_id_in_schema": {
"$id": "https://localhost:1234/id/my_identifier.json",
"type": "string"
},
"zzz_id_in_const": {
"const": {
"$id": "https://localhost:1234/id/my_identifier.json",
"type": "null"
}
}
},
"anyOf": [
{ "$ref": "#/definitions/id_in_enum" },
{ "$ref": "https://localhost:1234/id/my_identifier.json" }
]
},
"tests": [
{
"description": "exact match to enum, and type matches",
"data": {
"$id": "https://localhost:1234/id/my_identifier.json",
"type": "null"
},
"valid": true
},
{
"description": "match $ref to id",
"data": "a string to match #/definitions/id_in_enum",
"valid": true
},
{
"description": "no match on enum or $ref to id",
"data": 1,
"valid": false
}
]
}
]

View File

@ -0,0 +1,36 @@
[
{
"description": "evaluating the same schema location against the same data location twice is not a sign of an infinite loop",
"schema": {
"definitions": {
"int": { "type": "integer" }
},
"allOf": [
{
"properties": {
"foo": {
"$ref": "#/definitions/int"
}
}
},
{
"additionalProperties": {
"$ref": "#/definitions/int"
}
}
]
},
"tests": [
{
"description": "passing case",
"data": { "foo": 1 },
"valid": true
},
{
"description": "failing case",
"data": { "foo": "a string" },
"valid": false
}
]
}
]

View File

@ -0,0 +1,250 @@
[
{
"description": "a schema given for items",
"schema": {
"items": {"type": "integer"}
},
"tests": [
{
"description": "valid items",
"data": [ 1, 2, 3 ],
"valid": true
},
{
"description": "wrong type of items",
"data": [1, "x"],
"valid": false
},
{
"description": "ignores non-arrays",
"data": {"foo" : "bar"},
"valid": true
},
{
"description": "JavaScript pseudo-array is valid",
"data": {
"0": "invalid",
"length": 1
},
"valid": true
}
]
},
{
"description": "an array of schemas for items",
"schema": {
"items": [
{"type": "integer"},
{"type": "string"}
]
},
"tests": [
{
"description": "correct types",
"data": [ 1, "foo" ],
"valid": true
},
{
"description": "wrong types",
"data": [ "foo", 1 ],
"valid": false
},
{
"description": "incomplete array of items",
"data": [ 1 ],
"valid": true
},
{
"description": "array with additional items",
"data": [ 1, "foo", true ],
"valid": true
},
{
"description": "empty array",
"data": [ ],
"valid": true
},
{
"description": "JavaScript pseudo-array is valid",
"data": {
"0": "invalid",
"1": "valid",
"length": 2
},
"valid": true
}
]
},
{
"description": "items with boolean schema (true)",
"schema": {"items": true},
"tests": [
{
"description": "any array is valid",
"data": [ 1, "foo", true ],
"valid": true
},
{
"description": "empty array is valid",
"data": [],
"valid": true
}
]
},
{
"description": "items with boolean schema (false)",
"schema": {"items": false},
"tests": [
{
"description": "any non-empty array is invalid",
"data": [ 1, "foo", true ],
"valid": false
},
{
"description": "empty array is valid",
"data": [],
"valid": true
}
]
},
{
"description": "items with boolean schemas",
"schema": {
"items": [true, false]
},
"tests": [
{
"description": "array with one item is valid",
"data": [ 1 ],
"valid": true
},
{
"description": "array with two items is invalid",
"data": [ 1, "foo" ],
"valid": false
},
{
"description": "empty array is valid",
"data": [],
"valid": true
}
]
},
{
"description": "items and subitems",
"schema": {
"definitions": {
"item": {
"type": "array",
"additionalItems": false,
"items": [
{ "$ref": "#/definitions/sub-item" },
{ "$ref": "#/definitions/sub-item" }
]
},
"sub-item": {
"type": "object",
"required": ["foo"]
}
},
"type": "array",
"additionalItems": false,
"items": [
{ "$ref": "#/definitions/item" },
{ "$ref": "#/definitions/item" },
{ "$ref": "#/definitions/item" }
]
},
"tests": [
{
"description": "valid items",
"data": [
[ {"foo": null}, {"foo": null} ],
[ {"foo": null}, {"foo": null} ],
[ {"foo": null}, {"foo": null} ]
],
"valid": true
},
{
"description": "too many items",
"data": [
[ {"foo": null}, {"foo": null} ],
[ {"foo": null}, {"foo": null} ],
[ {"foo": null}, {"foo": null} ],
[ {"foo": null}, {"foo": null} ]
],
"valid": false
},
{
"description": "too many sub-items",
"data": [
[ {"foo": null}, {"foo": null}, {"foo": null} ],
[ {"foo": null}, {"foo": null} ],
[ {"foo": null}, {"foo": null} ]
],
"valid": false
},
{
"description": "wrong item",
"data": [
{"foo": null},
[ {"foo": null}, {"foo": null} ],
[ {"foo": null}, {"foo": null} ]
],
"valid": false
},
{
"description": "wrong sub-item",
"data": [
[ {}, {"foo": null} ],
[ {"foo": null}, {"foo": null} ],
[ {"foo": null}, {"foo": null} ]
],
"valid": false
},
{
"description": "fewer items is valid",
"data": [
[ {"foo": null} ],
[ {"foo": null} ]
],
"valid": true
}
]
},
{
"description": "nested items",
"schema": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "number"
}
}
}
}
},
"tests": [
{
"description": "valid nested array",
"data": [[[[1]], [[2],[3]]], [[[4], [5], [6]]]],
"valid": true
},
{
"description": "nested array with invalid type",
"data": [[[["1"]], [[2],[3]]], [[[4], [5], [6]]]],
"valid": false
},
{
"description": "not deep enough",
"data": [[[1], [2],[3]], [[4], [5], [6]]],
"valid": false
}
]
}
]

View File

@ -0,0 +1,28 @@
[
{
"description": "maxItems validation",
"schema": {"maxItems": 2},
"tests": [
{
"description": "shorter is valid",
"data": [1],
"valid": true
},
{
"description": "exact length is valid",
"data": [1, 2],
"valid": true
},
{
"description": "too long is invalid",
"data": [1, 2, 3],
"valid": false
},
{
"description": "ignores non-arrays",
"data": "foobar",
"valid": true
}
]
}
]

View File

@ -0,0 +1,33 @@
[
{
"description": "maxLength validation",
"schema": {"maxLength": 2},
"tests": [
{
"description": "shorter is valid",
"data": "f",
"valid": true
},
{
"description": "exact length is valid",
"data": "fo",
"valid": true
},
{
"description": "too long is invalid",
"data": "foo",
"valid": false
},
{
"description": "ignores non-strings",
"data": 100,
"valid": true
},
{
"description": "two supplementary Unicode code points is long enough",
"data": "\uD83D\uDCA9\uD83D\uDCA9",
"valid": true
}
]
}
]

View File

@ -0,0 +1,54 @@
[
{
"description": "maxProperties validation",
"schema": {"maxProperties": 2},
"tests": [
{
"description": "shorter is valid",
"data": {"foo": 1},
"valid": true
},
{
"description": "exact length is valid",
"data": {"foo": 1, "bar": 2},
"valid": true
},
{
"description": "too long is invalid",
"data": {"foo": 1, "bar": 2, "baz": 3},
"valid": false
},
{
"description": "ignores arrays",
"data": [1, 2, 3],
"valid": true
},
{
"description": "ignores strings",
"data": "foobar",
"valid": true
},
{
"description": "ignores other non-objects",
"data": 12,
"valid": true
}
]
},
{
"description": "maxProperties = 0 means the object is empty",
"schema": { "maxProperties": 0 },
"tests": [
{
"description": "no properties is valid",
"data": {},
"valid": true
},
{
"description": "one property is invalid",
"data": { "foo": 1 },
"valid": false
}
]
}
]

View File

@ -0,0 +1,54 @@
[
{
"description": "maximum validation",
"schema": {"maximum": 3.0},
"tests": [
{
"description": "below the maximum is valid",
"data": 2.6,
"valid": true
},
{
"description": "boundary point is valid",
"data": 3.0,
"valid": true
},
{
"description": "above the maximum is invalid",
"data": 3.5,
"valid": false
},
{
"description": "ignores non-numbers",
"data": "x",
"valid": true
}
]
},
{
"description": "maximum validation with unsigned integer",
"schema": {"maximum": 300},
"tests": [
{
"description": "below the maximum is invalid",
"data": 299.97,
"valid": true
},
{
"description": "boundary point integer is valid",
"data": 300,
"valid": true
},
{
"description": "boundary point float is valid",
"data": 300.00,
"valid": true
},
{
"description": "above the maximum is invalid",
"data": 300.5,
"valid": false
}
]
}
]

View File

@ -0,0 +1,28 @@
[
{
"description": "minItems validation",
"schema": {"minItems": 1},
"tests": [
{
"description": "longer is valid",
"data": [1, 2],
"valid": true
},
{
"description": "exact length is valid",
"data": [1],
"valid": true
},
{
"description": "too short is invalid",
"data": [],
"valid": false
},
{
"description": "ignores non-arrays",
"data": "",
"valid": true
}
]
}
]

View File

@ -0,0 +1,33 @@
[
{
"description": "minLength validation",
"schema": {"minLength": 2},
"tests": [
{
"description": "longer is valid",
"data": "foo",
"valid": true
},
{
"description": "exact length is valid",
"data": "fo",
"valid": true
},
{
"description": "too short is invalid",
"data": "f",
"valid": false
},
{
"description": "ignores non-strings",
"data": 1,
"valid": true
},
{
"description": "one supplementary Unicode code point is not long enough",
"data": "\uD83D\uDCA9",
"valid": false
}
]
}
]

View File

@ -0,0 +1,38 @@
[
{
"description": "minProperties validation",
"schema": {"minProperties": 1},
"tests": [
{
"description": "longer is valid",
"data": {"foo": 1, "bar": 2},
"valid": true
},
{
"description": "exact length is valid",
"data": {"foo": 1},
"valid": true
},
{
"description": "too short is invalid",
"data": {},
"valid": false
},
{
"description": "ignores arrays",
"data": [],
"valid": true
},
{
"description": "ignores strings",
"data": "",
"valid": true
},
{
"description": "ignores other non-objects",
"data": 12,
"valid": true
}
]
}
]

View File

@ -0,0 +1,69 @@
[
{
"description": "minimum validation",
"schema": {"minimum": 1.1},
"tests": [
{
"description": "above the minimum is valid",
"data": 2.6,
"valid": true
},
{
"description": "boundary point is valid",
"data": 1.1,
"valid": true
},
{
"description": "below the minimum is invalid",
"data": 0.6,
"valid": false
},
{
"description": "ignores non-numbers",
"data": "x",
"valid": true
}
]
},
{
"description": "minimum validation with signed integer",
"schema": {"minimum": -2},
"tests": [
{
"description": "negative above the minimum is valid",
"data": -1,
"valid": true
},
{
"description": "positive above the minimum is valid",
"data": 0,
"valid": true
},
{
"description": "boundary point is valid",
"data": -2,
"valid": true
},
{
"description": "boundary point with float is valid",
"data": -2.0,
"valid": true
},
{
"description": "float below the minimum is invalid",
"data": -2.0001,
"valid": false
},
{
"description": "int below the minimum is invalid",
"data": -3,
"valid": false
},
{
"description": "ignores non-numbers",
"data": "x",
"valid": true
}
]
}
]

View File

@ -0,0 +1,71 @@
[
{
"description": "by int",
"schema": {"multipleOf": 2},
"tests": [
{
"description": "int by int",
"data": 10,
"valid": true
},
{
"description": "int by int fail",
"data": 7,
"valid": false
},
{
"description": "ignores non-numbers",
"data": "foo",
"valid": true
}
]
},
{
"description": "by number",
"schema": {"multipleOf": 1.5},
"tests": [
{
"description": "zero is multiple of anything",
"data": 0,
"valid": true
},
{
"description": "4.5 is multiple of 1.5",
"data": 4.5,
"valid": true
},
{
"description": "35 is not multiple of 1.5",
"data": 35,
"valid": false
}
]
},
{
"description": "by small number",
"schema": {"multipleOf": 0.0001},
"tests": [
{
"description": "0.0075 is multiple of 0.0001",
"data": 0.0075,
"valid": true
},
{
"description": "0.00751 is not multiple of 0.0001",
"data": 0.00751,
"valid": false
}
]
},
{
"description": "invalid instance should not raise error when float division = inf",
"schema": {"type": "integer", "multipleOf": 0.123456789},
"tests": [
{
"description": "always invalid, but naive implementations may raise an overflow error",
"data": 1e308,
"valid": false
}
]
}
]

View File

@ -0,0 +1,117 @@
[
{
"description": "not",
"schema": {
"not": {"type": "integer"}
},
"tests": [
{
"description": "allowed",
"data": "foo",
"valid": true
},
{
"description": "disallowed",
"data": 1,
"valid": false
}
]
},
{
"description": "not multiple types",
"schema": {
"not": {"type": ["integer", "boolean"]}
},
"tests": [
{
"description": "valid",
"data": "foo",
"valid": true
},
{
"description": "mismatch",
"data": 1,
"valid": false
},
{
"description": "other mismatch",
"data": true,
"valid": false
}
]
},
{
"description": "not more complex schema",
"schema": {
"not": {
"type": "object",
"properties": {
"foo": {
"type": "string"
}
}
}
},
"tests": [
{
"description": "match",
"data": 1,
"valid": true
},
{
"description": "other match",
"data": {"foo": 1},
"valid": true
},
{
"description": "mismatch",
"data": {"foo": "bar"},
"valid": false
}
]
},
{
"description": "forbidden property",
"schema": {
"properties": {
"foo": {
"not": {}
}
}
},
"tests": [
{
"description": "property present",
"data": {"foo": 1, "bar": 2},
"valid": false
},
{
"description": "property absent",
"data": {"bar": 1, "baz": 2},
"valid": true
}
]
},
{
"description": "not with boolean schema true",
"schema": {"not": true},
"tests": [
{
"description": "any value is invalid",
"data": "foo",
"valid": false
}
]
},
{
"description": "not with boolean schema false",
"schema": {"not": false},
"tests": [
{
"description": "any value is valid",
"data": "foo",
"valid": true
}
]
}
]

View File

@ -0,0 +1,274 @@
[
{
"description": "oneOf",
"schema": {
"oneOf": [
{
"type": "integer"
},
{
"minimum": 2
}
]
},
"tests": [
{
"description": "first oneOf valid",
"data": 1,
"valid": true
},
{
"description": "second oneOf valid",
"data": 2.5,
"valid": true
},
{
"description": "both oneOf valid",
"data": 3,
"valid": false
},
{
"description": "neither oneOf valid",
"data": 1.5,
"valid": false
}
]
},
{
"description": "oneOf with base schema",
"schema": {
"type": "string",
"oneOf" : [
{
"minLength": 2
},
{
"maxLength": 4
}
]
},
"tests": [
{
"description": "mismatch base schema",
"data": 3,
"valid": false
},
{
"description": "one oneOf valid",
"data": "foobar",
"valid": true
},
{
"description": "both oneOf valid",
"data": "foo",
"valid": false
}
]
},
{
"description": "oneOf with boolean schemas, all true",
"schema": {"oneOf": [true, true, true]},
"tests": [
{
"description": "any value is invalid",
"data": "foo",
"valid": false
}
]
},
{
"description": "oneOf with boolean schemas, one true",
"schema": {"oneOf": [true, false, false]},
"tests": [
{
"description": "any value is valid",
"data": "foo",
"valid": true
}
]
},
{
"description": "oneOf with boolean schemas, more than one true",
"schema": {"oneOf": [true, true, false]},
"tests": [
{
"description": "any value is invalid",
"data": "foo",
"valid": false
}
]
},
{
"description": "oneOf with boolean schemas, all false",
"schema": {"oneOf": [false, false, false]},
"tests": [
{
"description": "any value is invalid",
"data": "foo",
"valid": false
}
]
},
{
"description": "oneOf complex types",
"schema": {
"oneOf": [
{
"properties": {
"bar": {"type": "integer"}
},
"required": ["bar"]
},
{
"properties": {
"foo": {"type": "string"}
},
"required": ["foo"]
}
]
},
"tests": [
{
"description": "first oneOf valid (complex)",
"data": {"bar": 2},
"valid": true
},
{
"description": "second oneOf valid (complex)",
"data": {"foo": "baz"},
"valid": true
},
{
"description": "both oneOf valid (complex)",
"data": {"foo": "baz", "bar": 2},
"valid": false
},
{
"description": "neither oneOf valid (complex)",
"data": {"foo": 2, "bar": "quux"},
"valid": false
}
]
},
{
"description": "oneOf with empty schema",
"schema": {
"oneOf": [
{ "type": "number" },
{}
]
},
"tests": [
{
"description": "one valid - valid",
"data": "foo",
"valid": true
},
{
"description": "both valid - invalid",
"data": 123,
"valid": false
}
]
},
{
"description": "oneOf with required",
"schema": {
"type": "object",
"oneOf": [
{ "required": ["foo", "bar"] },
{ "required": ["foo", "baz"] }
]
},
"tests": [
{
"description": "both invalid - invalid",
"data": {"bar": 2},
"valid": false
},
{
"description": "first valid - valid",
"data": {"foo": 1, "bar": 2},
"valid": true
},
{
"description": "second valid - valid",
"data": {"foo": 1, "baz": 3},
"valid": true
},
{
"description": "both valid - invalid",
"data": {"foo": 1, "bar": 2, "baz" : 3},
"valid": false
}
]
},
{
"description": "oneOf with missing optional property",
"schema": {
"oneOf": [
{
"properties": {
"bar": true,
"baz": true
},
"required": ["bar"]
},
{
"properties": {
"foo": true
},
"required": ["foo"]
}
]
},
"tests": [
{
"description": "first oneOf valid",
"data": {"bar": 8},
"valid": true
},
{
"description": "second oneOf valid",
"data": {"foo": "foo"},
"valid": true
},
{
"description": "both oneOf valid",
"data": {"foo": "foo", "bar": 8},
"valid": false
},
{
"description": "neither oneOf valid",
"data": {"baz": "quux"},
"valid": false
}
]
},
{
"description": "nested oneOf, to check validation semantics",
"schema": {
"oneOf": [
{
"oneOf": [
{
"type": "null"
}
]
}
]
},
"tests": [
{
"description": "null is valid",
"data": null,
"valid": true
},
{
"description": "anything non-null is invalid",
"data": 123,
"valid": false
}
]
}
]

View File

@ -0,0 +1,93 @@
[
{
"description": "integer",
"schema": { "type": "integer" },
"tests": [
{
"description": "a bignum is an integer",
"data": 12345678910111213141516171819202122232425262728293031,
"valid": true
},
{
"description": "a negative bignum is an integer",
"data": -12345678910111213141516171819202122232425262728293031,
"valid": true
}
]
},
{
"description": "number",
"schema": { "type": "number" },
"tests": [
{
"description": "a bignum is a number",
"data": 98249283749234923498293171823948729348710298301928331,
"valid": true
},
{
"description": "a negative bignum is a number",
"data": -98249283749234923498293171823948729348710298301928331,
"valid": true
}
]
},
{
"description": "string",
"schema": { "type": "string" },
"tests": [
{
"description": "a bignum is not a string",
"data": 98249283749234923498293171823948729348710298301928331,
"valid": false
}
]
},
{
"description": "integer comparison",
"schema": { "maximum": 18446744073709551615 },
"tests": [
{
"description": "comparison works for high numbers",
"data": 18446744073709551600,
"valid": true
}
]
},
{
"description": "float comparison with high precision",
"schema": {
"exclusiveMaximum": 972783798187987123879878123.18878137
},
"tests": [
{
"description": "comparison works for high numbers",
"data": 972783798187987123879878123.188781371,
"valid": false
}
]
},
{
"description": "integer comparison",
"schema": { "minimum": -18446744073709551615 },
"tests": [
{
"description": "comparison works for very negative numbers",
"data": -18446744073709551600,
"valid": true
}
]
},
{
"description": "float comparison with high precision on negative numbers",
"schema": {
"exclusiveMinimum": -972783798187987123879878123.18878137
},
"tests": [
{
"description": "comparison works for very negative numbers",
"data": -972783798187987123879878123.188781371,
"valid": false
}
]
}
]

View File

@ -0,0 +1,552 @@
[
{
"description": "ECMA 262 regex $ does not match trailing newline",
"schema": {
"type": "string",
"pattern": "^abc$"
},
"tests": [
{
"description": "matches in Python, but should not in jsonschema",
"data": "abc\\n",
"valid": false
},
{
"description": "should match",
"data": "abc",
"valid": true
}
]
},
{
"description": "ECMA 262 regex converts \\t to horizontal tab",
"schema": {
"type": "string",
"pattern": "^\\t$"
},
"tests": [
{
"description": "does not match",
"data": "\\t",
"valid": false
},
{
"description": "matches",
"data": "\u0009",
"valid": true
}
]
},
{
"description": "ECMA 262 regex escapes control codes with \\c and upper letter",
"schema": {
"type": "string",
"pattern": "^\\cC$"
},
"tests": [
{
"description": "does not match",
"data": "\\cC",
"valid": false
},
{
"description": "matches",
"data": "\u0003",
"valid": true
}
]
},
{
"description": "ECMA 262 regex escapes control codes with \\c and lower letter",
"schema": {
"type": "string",
"pattern": "^\\cc$"
},
"tests": [
{
"description": "does not match",
"data": "\\cc",
"valid": false
},
{
"description": "matches",
"data": "\u0003",
"valid": true
}
]
},
{
"description": "ECMA 262 \\d matches ascii digits only",
"schema": {
"type": "string",
"pattern": "^\\d$"
},
"tests": [
{
"description": "ASCII zero matches",
"data": "0",
"valid": true
},
{
"description": "NKO DIGIT ZERO does not match (unlike e.g. Python)",
"data": "߀",
"valid": false
},
{
"description": "NKO DIGIT ZERO (as \\u escape) does not match",
"data": "\u07c0",
"valid": false
}
]
},
{
"description": "ECMA 262 \\D matches everything but ascii digits",
"schema": {
"type": "string",
"pattern": "^\\D$"
},
"tests": [
{
"description": "ASCII zero does not match",
"data": "0",
"valid": false
},
{
"description": "NKO DIGIT ZERO matches (unlike e.g. Python)",
"data": "߀",
"valid": true
},
{
"description": "NKO DIGIT ZERO (as \\u escape) matches",
"data": "\u07c0",
"valid": true
}
]
},
{
"description": "ECMA 262 \\w matches ascii letters only",
"schema": {
"type": "string",
"pattern": "^\\w$"
},
"tests": [
{
"description": "ASCII 'a' matches",
"data": "a",
"valid": true
},
{
"description": "latin-1 e-acute does not match (unlike e.g. Python)",
"data": "é",
"valid": false
}
]
},
{
"description": "ECMA 262 \\W matches everything but ascii letters",
"schema": {
"type": "string",
"pattern": "^\\W$"
},
"tests": [
{
"description": "ASCII 'a' does not match",
"data": "a",
"valid": false
},
{
"description": "latin-1 e-acute matches (unlike e.g. Python)",
"data": "é",
"valid": true
}
]
},
{
"description": "ECMA 262 \\s matches whitespace",
"schema": {
"type": "string",
"pattern": "^\\s$"
},
"tests": [
{
"description": "ASCII space matches",
"data": " ",
"valid": true
},
{
"description": "Character tabulation matches",
"data": "\t",
"valid": true
},
{
"description": "Line tabulation matches",
"data": "\u000b",
"valid": true
},
{
"description": "Form feed matches",
"data": "\u000c",
"valid": true
},
{
"description": "latin-1 non-breaking-space matches",
"data": "\u00a0",
"valid": true
},
{
"description": "zero-width whitespace matches",
"data": "\ufeff",
"valid": true
},
{
"description": "line feed matches (line terminator)",
"data": "\u000a",
"valid": true
},
{
"description": "paragraph separator matches (line terminator)",
"data": "\u2029",
"valid": true
},
{
"description": "EM SPACE matches (Space_Separator)",
"data": "\u2003",
"valid": true
},
{
"description": "Non-whitespace control does not match",
"data": "\u0001",
"valid": false
},
{
"description": "Non-whitespace does not match",
"data": "\u2013",
"valid": false
}
]
},
{
"description": "ECMA 262 \\S matches everything but whitespace",
"schema": {
"type": "string",
"pattern": "^\\S$"
},
"tests": [
{
"description": "ASCII space does not match",
"data": " ",
"valid": false
},
{
"description": "Character tabulation does not match",
"data": "\t",
"valid": false
},
{
"description": "Line tabulation does not match",
"data": "\u000b",
"valid": false
},
{
"description": "Form feed does not match",
"data": "\u000c",
"valid": false
},
{
"description": "latin-1 non-breaking-space does not match",
"data": "\u00a0",
"valid": false
},
{
"description": "zero-width whitespace does not match",
"data": "\ufeff",
"valid": false
},
{
"description": "line feed does not match (line terminator)",
"data": "\u000a",
"valid": false
},
{
"description": "paragraph separator does not match (line terminator)",
"data": "\u2029",
"valid": false
},
{
"description": "EM SPACE does not match (Space_Separator)",
"data": "\u2003",
"valid": false
},
{
"description": "Non-whitespace control matches",
"data": "\u0001",
"valid": true
},
{
"description": "Non-whitespace matches",
"data": "\u2013",
"valid": true
}
]
},
{
"description": "unicode semantics should be used for all pattern matching",
"schema": { "pattern": "\\p{Letter}cole" },
"tests": [
{
"description": "ascii character in json string",
"data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.",
"valid": true
},
{
"description": "literal unicode character in json string",
"data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.",
"valid": true
},
{
"description": "unicode character in hex format in string",
"data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.",
"valid": true
},
{
"description": "unicode matching is case-sensitive",
"data": "LES HIVERS DE MON ENFANCE ÉTAIENT DES SAISONS LONGUES, LONGUES. NOUS VIVIONS EN TROIS LIEUX: L'ÉCOLE, L'ÉGLISE ET LA PATINOIRE; MAIS LA VRAIE VIE ÉTAIT SUR LA PATINOIRE.",
"valid": false
}
]
},
{
"description": "\\w in patterns matches [A-Za-z0-9_], not unicode letters",
"schema": { "pattern": "\\wcole" },
"tests": [
{
"description": "ascii character in json string",
"data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.",
"valid": true
},
{
"description": "literal unicode character in json string",
"data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.",
"valid": false
},
{
"description": "unicode character in hex format in string",
"data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.",
"valid": false
},
{
"description": "unicode matching is case-sensitive",
"data": "LES HIVERS DE MON ENFANCE ÉTAIENT DES SAISONS LONGUES, LONGUES. NOUS VIVIONS EN TROIS LIEUX: L'ÉCOLE, L'ÉGLISE ET LA PATINOIRE; MAIS LA VRAIE VIE ÉTAIT SUR LA PATINOIRE.",
"valid": false
}
]
},
{
"description": "unicode characters do not match ascii ranges",
"schema": { "pattern": "[a-z]cole" },
"tests": [
{
"description": "literal unicode character in json string",
"data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.",
"valid": false
},
{
"description": "unicode character in hex format in string",
"data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.",
"valid": false
},
{
"description": "ascii characters match",
"data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.",
"valid": true
}
]
},
{
"description": "\\d in pattern matches [0-9], not unicode digits",
"schema": { "pattern": "^\\d+$" },
"tests": [
{
"description": "ascii digits",
"data": "42",
"valid": true
},
{
"description": "ascii non-digits",
"data": "-%#",
"valid": false
},
{
"description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)",
"data": "৪২",
"valid": false
}
]
},
{
"description": "unicode digits are more than 0 through 9",
"schema": { "pattern": "^\\p{digit}+$" },
"tests": [
{
"description": "ascii digits",
"data": "42",
"valid": true
},
{
"description": "ascii non-digits",
"data": "-%#",
"valid": false
},
{
"description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)",
"data": "৪২",
"valid": true
}
]
},
{
"description": "unicode semantics should be used for all patternProperties matching",
"schema": {
"type": "object",
"patternProperties": {
"\\p{Letter}cole": true
},
"additionalProperties": false
},
"tests": [
{
"description": "ascii character in json string",
"data": { "l'ecole": "pas de vraie vie" },
"valid": true
},
{
"description": "literal unicode character in json string",
"data": { "l'école": "pas de vraie vie" },
"valid": true
},
{
"description": "unicode character in hex format in string",
"data": { "l'\u00e9cole": "pas de vraie vie" },
"valid": true
},
{
"description": "unicode matching is case-sensitive",
"data": { "L'ÉCOLE": "PAS DE VRAIE VIE" },
"valid": false
}
]
},
{
"description": "\\w in patternProperties matches [A-Za-z0-9_], not unicode letters",
"schema": {
"type": "object",
"patternProperties": {
"\\wcole": true
},
"additionalProperties": false
},
"tests": [
{
"description": "ascii character in json string",
"data": { "l'ecole": "pas de vraie vie" },
"valid": true
},
{
"description": "literal unicode character in json string",
"data": { "l'école": "pas de vraie vie" },
"valid": false
},
{
"description": "unicode character in hex format in string",
"data": { "l'\u00e9cole": "pas de vraie vie" },
"valid": false
},
{
"description": "unicode matching is case-sensitive",
"data": { "L'ÉCOLE": "PAS DE VRAIE VIE" },
"valid": false
}
]
},
{
"description": "unicode characters do not match ascii ranges",
"schema": {
"type": "object",
"patternProperties": {
"[a-z]cole": true
},
"additionalProperties": false
},
"tests": [
{
"description": "literal unicode character in json string",
"data": { "l'école": "pas de vraie vie" },
"valid": false
},
{
"description": "unicode character in hex format in string",
"data": { "l'\u00e9cole": "pas de vraie vie" },
"valid": false
},
{
"description": "ascii characters match",
"data": { "l'ecole": "pas de vraie vie" },
"valid": true
}
]
},
{
"description": "\\d in patternProperties matches [0-9], not unicode digits",
"schema": {
"type": "object",
"patternProperties": {
"^\\d+$": true
},
"additionalProperties": false
},
"tests": [
{
"description": "ascii digits",
"data": { "42": "life, the universe, and everything" },
"valid": true
},
{
"description": "ascii non-digits",
"data": { "-%#": "spending the year dead for tax reasons" },
"valid": false
},
{
"description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)",
"data": { "৪২": "khajit has wares if you have coin" },
"valid": false
}
]
},
{
"description": "unicode digits are more than 0 through 9",
"schema": {
"type": "object",
"patternProperties": {
"^\\p{digit}+$": true
},
"additionalProperties": false
},
"tests": [
{
"description": "ascii digits",
"data": { "42": "life, the universe, and everything" },
"valid": true
},
{
"description": "ascii non-digits",
"data": { "-%#": "spending the year dead for tax reasons" },
"valid": false
},
{
"description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)",
"data": { "৪২": "khajit has wares if you have coin" },
"valid": true
}
]
}
]

View File

@ -0,0 +1,13 @@
[
{
"description": "all integers are multiples of 0.5, if overflow is handled",
"schema": {"type": "integer", "multipleOf": 0.5},
"tests": [
{
"description": "valid if optional overflow handling is implemented",
"data": 1e308,
"valid": true
}
]
}
]

View File

@ -0,0 +1,133 @@
[
{
"description": "validation of date-time strings",
"schema": { "format": "date-time" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
},
{
"description": "a valid date-time string",
"data": "1963-06-19T08:30:06.283185Z",
"valid": true
},
{
"description": "a valid date-time string without second fraction",
"data": "1963-06-19T08:30:06Z",
"valid": true
},
{
"description": "a valid date-time string with plus offset",
"data": "1937-01-01T12:00:27.87+00:20",
"valid": true
},
{
"description": "a valid date-time string with minus offset",
"data": "1990-12-31T15:59:50.123-08:00",
"valid": true
},
{
"description": "a valid date-time with a leap second, UTC",
"data": "1998-12-31T23:59:60Z",
"valid": true
},
{
"description": "a valid date-time with a leap second, with minus offset",
"data": "1998-12-31T15:59:60.123-08:00",
"valid": true
},
{
"description": "an invalid date-time past leap second, UTC",
"data": "1998-12-31T23:59:61Z",
"valid": false
},
{
"description": "an invalid date-time with leap second on a wrong minute, UTC",
"data": "1998-12-31T23:58:60Z",
"valid": false
},
{
"description": "an invalid date-time with leap second on a wrong hour, UTC",
"data": "1998-12-31T22:59:60Z",
"valid": false
},
{
"description": "an invalid day in date-time string",
"data": "1990-02-31T15:59:59.123-08:00",
"valid": false
},
{
"description": "an invalid offset in date-time string",
"data": "1990-12-31T15:59:59-24:00",
"valid": false
},
{
"description": "an invalid closing Z after time-zone offset",
"data": "1963-06-19T08:30:06.28123+01:00Z",
"valid": false
},
{
"description": "an invalid date-time string",
"data": "06/19/1963 08:30:06 PST",
"valid": false
},
{
"description": "case-insensitive T and Z",
"data": "1963-06-19t08:30:06.283185z",
"valid": true
},
{
"description": "only RFC3339 not all of ISO 8601 are valid",
"data": "2013-350T01:01:01",
"valid": false
},
{
"description": "invalid non-padded month dates",
"data": "1963-6-19T08:30:06.283185Z",
"valid": false
},
{
"description": "invalid non-padded day dates",
"data": "1963-06-1T08:30:06.283185Z",
"valid": false
},
{
"description": "non-ascii digits should be rejected in the date portion",
"data": "1963-06-1T00:00:00Z",
"valid": false
},
{
"description": "non-ascii digits should be rejected in the time portion",
"data": "1963-06-11T0:00:00Z",
"valid": false
}
]
}
]

View File

@ -0,0 +1,83 @@
[
{
"description": "validation of e-mail addresses",
"schema": { "format": "email" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
},
{
"description": "a valid e-mail address",
"data": "joe.bloggs@example.com",
"valid": true
},
{
"description": "an invalid e-mail address",
"data": "2962",
"valid": false
},
{
"description": "tilde in local part is valid",
"data": "te~st@example.com",
"valid": true
},
{
"description": "tilde before local part is valid",
"data": "~test@example.com",
"valid": true
},
{
"description": "tilde after local part is valid",
"data": "test~@example.com",
"valid": true
},
{
"description": "dot before local part is not valid",
"data": ".test@example.com",
"valid": false
},
{
"description": "dot after local part is not valid",
"data": "test.@example.com",
"valid": false
},
{
"description": "two separated dots inside local part are valid",
"data": "te.s.t@example.com",
"valid": true
},
{
"description": "two subsequent dots inside local part are not valid",
"data": "te..st@example.com",
"valid": false
}
]
}
]

View File

@ -0,0 +1,98 @@
[
{
"description": "validation of host names",
"schema": { "format": "hostname" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
},
{
"description": "a valid host name",
"data": "www.example.com",
"valid": true
},
{
"description": "a valid punycoded IDN hostname",
"data": "xn--4gbwdl.xn--wgbh1c",
"valid": true
},
{
"description": "a host name starting with an illegal character",
"data": "-a-host-name-that-starts-with--",
"valid": false
},
{
"description": "a host name containing illegal characters",
"data": "not_a_valid_host_name",
"valid": false
},
{
"description": "a host name with a component too long",
"data": "a-vvvvvvvvvvvvvvvveeeeeeeeeeeeeeeerrrrrrrrrrrrrrrryyyyyyyyyyyyyyyy-long-host-name-component",
"valid": false
},
{
"description": "starts with hyphen",
"data": "-hostname",
"valid": false
},
{
"description": "ends with hyphen",
"data": "hostname-",
"valid": false
},
{
"description": "starts with underscore",
"data": "_hostname",
"valid": false
},
{
"description": "ends with underscore",
"data": "hostname_",
"valid": false
},
{
"description": "contains underscore",
"data": "host_name",
"valid": false
},
{
"description": "maximum label length",
"data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.com",
"valid": true
},
{
"description": "exceeds maximum label length",
"data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl.com",
"valid": false
}
]
}
]

View File

@ -0,0 +1,84 @@
[
{
"description": "validation of IP addresses",
"schema": { "format": "ipv4" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
},
{
"description": "a valid IP address",
"data": "192.168.0.1",
"valid": true
},
{
"description": "an IP address with too many components",
"data": "127.0.0.0.1",
"valid": false
},
{
"description": "an IP address with out-of-range values",
"data": "256.256.256.256",
"valid": false
},
{
"description": "an IP address without 4 components",
"data": "127.0",
"valid": false
},
{
"description": "an IP address as an integer",
"data": "0x7f000001",
"valid": false
},
{
"description": "an IP address as an integer (decimal)",
"data": "2130706433",
"valid": false
},
{
"description": "leading zeroes should be rejected, as they are treated as octals",
"comment": "see https://sick.codes/universal-netmask-npm-package-used-by-270000-projects-vulnerable-to-octal-input-data-server-side-request-forgery-remote-file-inclusion-local-file-inclusion-and-more-cve-2021-28918/",
"data": "087.10.0.1",
"valid": false
},
{
"description": "value without leading zero is valid",
"data": "87.10.0.1",
"valid": true
},
{
"description": "non-ascii digits should be rejected",
"data": "1২7.0.0.1",
"valid": false
}
]
}
]

View File

@ -0,0 +1,208 @@
[
{
"description": "validation of IPv6 addresses",
"schema": { "format": "ipv6" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
},
{
"description": "a valid IPv6 address",
"data": "::1",
"valid": true
},
{
"description": "an IPv6 address with out-of-range values",
"data": "12345::",
"valid": false
},
{
"description": "trailing 4 hex symbols is valid",
"data": "::abef",
"valid": true
},
{
"description": "trailing 5 hex symbols is invalid",
"data": "::abcef",
"valid": false
},
{
"description": "an IPv6 address with too many components",
"data": "1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1",
"valid": false
},
{
"description": "an IPv6 address containing illegal characters",
"data": "::laptop",
"valid": false
},
{
"description": "no digits is valid",
"data": "::",
"valid": true
},
{
"description": "leading colons is valid",
"data": "::42:ff:1",
"valid": true
},
{
"description": "trailing colons is valid",
"data": "d6::",
"valid": true
},
{
"description": "missing leading octet is invalid",
"data": ":2:3:4:5:6:7:8",
"valid": false
},
{
"description": "missing trailing octet is invalid",
"data": "1:2:3:4:5:6:7:",
"valid": false
},
{
"description": "missing leading octet with omitted octets later",
"data": ":2:3:4::8",
"valid": false
},
{
"description": "single set of double colons in the middle is valid",
"data": "1:d6::42",
"valid": true
},
{
"description": "two sets of double colons is invalid",
"data": "1::d6::42",
"valid": false
},
{
"description": "mixed format with the ipv4 section as decimal octets",
"data": "1::d6:192.168.0.1",
"valid": true
},
{
"description": "mixed format with double colons between the sections",
"data": "1:2::192.168.0.1",
"valid": true
},
{
"description": "mixed format with ipv4 section with octet out of range",
"data": "1::2:192.168.256.1",
"valid": false
},
{
"description": "mixed format with ipv4 section with a hex octet",
"data": "1::2:192.168.ff.1",
"valid": false
},
{
"description": "mixed format with leading double colons (ipv4-mapped ipv6 address)",
"data": "::ffff:192.168.0.1",
"valid": true
},
{
"description": "triple colons is invalid",
"data": "1:2:3:4:5:::8",
"valid": false
},
{
"description": "8 octets",
"data": "1:2:3:4:5:6:7:8",
"valid": true
},
{
"description": "insufficient octets without double colons",
"data": "1:2:3:4:5:6:7",
"valid": false
},
{
"description": "no colons is invalid",
"data": "1",
"valid": false
},
{
"description": "ipv4 is not ipv6",
"data": "127.0.0.1",
"valid": false
},
{
"description": "ipv4 segment must have 4 octets",
"data": "1:2:3:4:1.2.3",
"valid": false
},
{
"description": "leading whitespace is invalid",
"data": " ::1",
"valid": false
},
{
"description": "trailing whitespace is invalid",
"data": "::1 ",
"valid": false
},
{
"description": "netmask is not a part of ipv6 address",
"data": "fe80::/64",
"valid": false
},
{
"description": "zone id is not a part of ipv6 address",
"data": "fe80::a%eth1",
"valid": false
},
{
"description": "a long valid ipv6",
"data": "1000:1000:1000:1000:1000:1000:255.255.255.255",
"valid": true
},
{
"description": "a long invalid ipv6, below length limit, first",
"data": "100:100:100:100:100:100:255.255.255.255.255",
"valid": false
},
{
"description": "a long invalid ipv6, below length limit, second",
"data": "100:100:100:100:100:100:100:255.255.255.255",
"valid": false
},
{
"description": "non-ascii digits should be rejected",
"data": "1:2:3:4:5:6:7:",
"valid": false
},
{
"description": "non-ascii digits should be rejected in the ipv4 portion also",
"data": "1:2::192.16.0.1",
"valid": false
}
]
}
]

View File

@ -0,0 +1,198 @@
[
{
"description": "validation of JSON-pointers (JSON String Representation)",
"schema": { "format": "json-pointer" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
},
{
"description": "a valid JSON-pointer",
"data": "/foo/bar~0/baz~1/%a",
"valid": true
},
{
"description": "not a valid JSON-pointer (~ not escaped)",
"data": "/foo/bar~",
"valid": false
},
{
"description": "valid JSON-pointer with empty segment",
"data": "/foo//bar",
"valid": true
},
{
"description": "valid JSON-pointer with the last empty segment",
"data": "/foo/bar/",
"valid": true
},
{
"description": "valid JSON-pointer as stated in RFC 6901 #1",
"data": "",
"valid": true
},
{
"description": "valid JSON-pointer as stated in RFC 6901 #2",
"data": "/foo",
"valid": true
},
{
"description": "valid JSON-pointer as stated in RFC 6901 #3",
"data": "/foo/0",
"valid": true
},
{
"description": "valid JSON-pointer as stated in RFC 6901 #4",
"data": "/",
"valid": true
},
{
"description": "valid JSON-pointer as stated in RFC 6901 #5",
"data": "/a~1b",
"valid": true
},
{
"description": "valid JSON-pointer as stated in RFC 6901 #6",
"data": "/c%d",
"valid": true
},
{
"description": "valid JSON-pointer as stated in RFC 6901 #7",
"data": "/e^f",
"valid": true
},
{
"description": "valid JSON-pointer as stated in RFC 6901 #8",
"data": "/g|h",
"valid": true
},
{
"description": "valid JSON-pointer as stated in RFC 6901 #9",
"data": "/i\\j",
"valid": true
},
{
"description": "valid JSON-pointer as stated in RFC 6901 #10",
"data": "/k\"l",
"valid": true
},
{
"description": "valid JSON-pointer as stated in RFC 6901 #11",
"data": "/ ",
"valid": true
},
{
"description": "valid JSON-pointer as stated in RFC 6901 #12",
"data": "/m~0n",
"valid": true
},
{
"description": "valid JSON-pointer used adding to the last array position",
"data": "/foo/-",
"valid": true
},
{
"description": "valid JSON-pointer (- used as object member name)",
"data": "/foo/-/bar",
"valid": true
},
{
"description": "valid JSON-pointer (multiple escaped characters)",
"data": "/~1~0~0~1~1",
"valid": true
},
{
"description": "valid JSON-pointer (escaped with fraction part) #1",
"data": "/~1.1",
"valid": true
},
{
"description": "valid JSON-pointer (escaped with fraction part) #2",
"data": "/~0.1",
"valid": true
},
{
"description": "not a valid JSON-pointer (URI Fragment Identifier) #1",
"data": "#",
"valid": false
},
{
"description": "not a valid JSON-pointer (URI Fragment Identifier) #2",
"data": "#/",
"valid": false
},
{
"description": "not a valid JSON-pointer (URI Fragment Identifier) #3",
"data": "#a",
"valid": false
},
{
"description": "not a valid JSON-pointer (some escaped, but not all) #1",
"data": "/~0~",
"valid": false
},
{
"description": "not a valid JSON-pointer (some escaped, but not all) #2",
"data": "/~0/~",
"valid": false
},
{
"description": "not a valid JSON-pointer (wrong escape character) #1",
"data": "/~2",
"valid": false
},
{
"description": "not a valid JSON-pointer (wrong escape character) #2",
"data": "/~-1",
"valid": false
},
{
"description": "not a valid JSON-pointer (multiple characters not escaped)",
"data": "/~~",
"valid": false
},
{
"description": "not a valid JSON-pointer (isn't empty nor starts with /) #1",
"data": "a",
"valid": false
},
{
"description": "not a valid JSON-pointer (isn't empty nor starts with /) #2",
"data": "0",
"valid": false
},
{
"description": "not a valid JSON-pointer (isn't empty nor starts with /) #3",
"data": "a/a",
"valid": false
}
]
}
]

View File

@ -0,0 +1,43 @@
[
{
"description": "unknown format",
"schema": { "format": "unknown" },
"tests": [
{
"description": "unknown formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "unknown formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "unknown formats ignore objects",
"data": {},
"valid": true
},
{
"description": "unknown formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "unknown formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "unknown formats ignore nulls",
"data": null,
"valid": true
},
{
"description": "unknown formats ignore strings",
"data": "string",
"valid": true
}
]
}
]

View File

@ -0,0 +1,73 @@
[
{
"description": "validation of URI References",
"schema": { "format": "uri-reference" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
},
{
"description": "a valid URI",
"data": "http://foo.bar/?baz=qux#quux",
"valid": true
},
{
"description": "a valid protocol-relative URI Reference",
"data": "//foo.bar/?baz=qux#quux",
"valid": true
},
{
"description": "a valid relative URI Reference",
"data": "/abc",
"valid": true
},
{
"description": "an invalid URI Reference",
"data": "\\\\WINDOWS\\fileshare",
"valid": false
},
{
"description": "a valid URI Reference",
"data": "abc",
"valid": true
},
{
"description": "a valid URI fragment",
"data": "#fragment",
"valid": true
},
{
"description": "an invalid URI fragment",
"data": "#frag\\ment",
"valid": false
}
]
}
]

View File

@ -0,0 +1,58 @@
[
{
"description": "format: uri-template",
"schema": { "format": "uri-template" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
},
{
"description": "a valid uri-template",
"data": "http://example.com/dictionary/{term:1}/{term}",
"valid": true
},
{
"description": "an invalid uri-template",
"data": "http://example.com/dictionary/{term:1}/{term",
"valid": false
},
{
"description": "a valid uri-template without variables",
"data": "http://example.com/dictionary",
"valid": true
},
{
"description": "a valid relative uri-template",
"data": "dictionary/{term:1}/{term}",
"valid": true
}
]
}
]

View File

@ -0,0 +1,108 @@
[
{
"description": "validation of URIs",
"schema": { "format": "uri" },
"tests": [
{
"description": "a valid URL with anchor tag",
"data": "http://foo.bar/?baz=qux#quux",
"valid": true
},
{
"description": "a valid URL with anchor tag and parentheses",
"data": "http://foo.com/blah_(wikipedia)_blah#cite-1",
"valid": true
},
{
"description": "a valid URL with URL-encoded stuff",
"data": "http://foo.bar/?q=Test%20URL-encoded%20stuff",
"valid": true
},
{
"description": "a valid puny-coded URL ",
"data": "http://xn--nw2a.xn--j6w193g/",
"valid": true
},
{
"description": "a valid URL with many special characters",
"data": "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com",
"valid": true
},
{
"description": "a valid URL based on IPv4",
"data": "http://223.255.255.254",
"valid": true
},
{
"description": "a valid URL with ftp scheme",
"data": "ftp://ftp.is.co.za/rfc/rfc1808.txt",
"valid": true
},
{
"description": "a valid URL for a simple text file",
"data": "http://www.ietf.org/rfc/rfc2396.txt",
"valid": true
},
{
"description": "a valid URL ",
"data": "ldap://[2001:db8::7]/c=GB?objectClass?one",
"valid": true
},
{
"description": "a valid mailto URI",
"data": "mailto:John.Doe@example.com",
"valid": true
},
{
"description": "a valid newsgroup URI",
"data": "news:comp.infosystems.www.servers.unix",
"valid": true
},
{
"description": "a valid tel URI",
"data": "tel:+1-816-555-1212",
"valid": true
},
{
"description": "a valid URN",
"data": "urn:oasis:names:specification:docbook:dtd:xml:4.1.2",
"valid": true
},
{
"description": "an invalid protocol-relative URI Reference",
"data": "//foo.bar/?baz=qux#quux",
"valid": false
},
{
"description": "an invalid relative URI Reference",
"data": "/abc",
"valid": false
},
{
"description": "an invalid URI",
"data": "\\\\WINDOWS\\fileshare",
"valid": false
},
{
"description": "an invalid URI though valid URI reference",
"data": "abc",
"valid": false
},
{
"description": "an invalid URI with spaces",
"data": "http:// shouldfail.com",
"valid": false
},
{
"description": "an invalid URI with spaces and missing scheme",
"data": ":// should fail",
"valid": false
},
{
"description": "an invalid URI with comma in scheme",
"data": "bar,baz:foo",
"valid": false
}
]
}
]

View File

@ -0,0 +1,465 @@
[
{
"description": "$dynamicRef without $dynamicAnchor works like $ref",
"schema": {
"properties": {
"foo": {"$dynamicRef": "#"}
},
"additionalProperties": false
},
"tests": [
{
"description": "match",
"data": {"foo": false},
"valid": true
},
{
"description": "recursive match",
"data": {"foo": {"foo": false}},
"valid": true
},
{
"description": "mismatch",
"data": {"bar": false},
"valid": false
},
{
"description": "recursive mismatch (but $dynamicRef is ignored)",
"data": {"foo": {"bar": false}},
"valid": true
}
]
},
{
"description": "prefixItems: an array of schemas for items",
"schema": {
"prefixItems": [
{"type": "integer"},
{"type": "string"}
]
},
"tests": [
{
"description": "correct types",
"data": [ 1, "foo" ],
"valid": true
},
{
"description": "wrong types",
"data": [ "foo", 1 ],
"valid": true
},
{
"description": "incomplete array of items",
"data": [ 1 ],
"valid": true
},
{
"description": "array with additional items",
"data": [ 1, "foo", true ],
"valid": true
},
{
"description": "empty array",
"data": [ ],
"valid": true
},
{
"description": "JavaScript pseudo-array is valid",
"data": {
"0": "invalid",
"1": "valid",
"length": 2
},
"valid": true
}
]
},
{
"description": "dependentSchemas: single dependency",
"schema": {
"dependentSchemas": {
"bar": {
"properties": {
"foo": {"type": "integer"},
"bar": {"type": "integer"}
}
}
}
},
"tests": [
{
"description": "valid",
"data": {"foo": 1, "bar": 2},
"valid": true
},
{
"description": "no dependency",
"data": {"foo": "quux"},
"valid": true
},
{
"description": "wrong type",
"data": {"foo": "quux", "bar": 2},
"valid": true
},
{
"description": "wrong type other",
"data": {"foo": 2, "bar": "quux"},
"valid": true
},
{
"description": "wrong type both",
"data": {"foo": "quux", "bar": "quux"},
"valid": true
}
]
},
{
"description": "dependentRequired: single dependency",
"schema": {"dependentRequired": {"bar": ["foo"]}},
"tests": [
{
"description": "neither",
"data": {},
"valid": true
},
{
"description": "nondependant",
"data": {"foo": 1},
"valid": true
},
{
"description": "with dependency",
"data": {"foo": 1, "bar": 2},
"valid": true
},
{
"description": "missing dependency",
"data": {"bar": 2},
"valid": true
},
{
"description": "ignores arrays",
"data": ["bar"],
"valid": true
},
{
"description": "ignores strings",
"data": "foobar",
"valid": true
},
{
"description": "ignores other non-objects",
"data": 12,
"valid": true
}
]
},
{
"description": "unevaluatedItems false",
"schema": {
"type": "array",
"unevaluatedItems": false
},
"tests": [
{
"description": "with no unevaluated items",
"data": [],
"valid": true
},
{
"description": "with unevaluated items",
"data": ["foo"],
"valid": true
}
]
},
{
"description": "unevaluatedProperties schema",
"schema": {
"type": "object",
"unevaluatedProperties": {
"type": "string",
"minLength": 3
}
},
"tests": [
{
"description": "with no unevaluated properties",
"data": {},
"valid": true
},
{
"description": "with valid unevaluated properties",
"data": {
"foo": "foo"
},
"valid": true
},
{
"description": "with invalid unevaluated properties",
"data": {
"foo": "fo"
},
"valid": true
}
]
},
{
"description": "maxContains with contains",
"schema": {
"contains": {"const": 1},
"maxContains": 1
},
"tests": [
{
"description": "empty data",
"data": [ ],
"valid": false
},
{
"description": "all elements match, valid maxContains",
"data": [ 1 ],
"valid": true
},
{
"description": "all elements match, invalid maxContains",
"data": [ 1, 1 ],
"valid": true
},
{
"description": "some elements match, valid maxContains",
"data": [ 1, 2 ],
"valid": true
},
{
"description": "some elements match, invalid maxContains",
"data": [ 1, 2, 1 ],
"valid": true
}
]
},
{
"description": "minContains=2 with contains",
"schema": {
"contains": {"const": 1},
"minContains": 2
},
"tests": [
{
"description": "empty data",
"data": [ ],
"valid": false
},
{
"description": "all elements match, invalid minContains",
"data": [ 1 ],
"valid": true
},
{
"description": "some elements match, invalid minContains",
"data": [ 1, 2 ],
"valid": true
},
{
"description": "all elements match, valid minContains (exactly as needed)",
"data": [ 1, 1 ],
"valid": true
},
{
"description": "all elements match, valid minContains (more than needed)",
"data": [ 1, 1, 1 ],
"valid": true
},
{
"description": "some elements match, valid minContains",
"data": [ 1, 2, 1 ],
"valid": true
}
]
},
{
"description": "minContains = 0",
"schema": {
"contains": {"const": 1},
"minContains": 0
},
"tests": [
{
"description": "empty array is valid with minContains=0",
"data": [ ],
"valid": false
},
{
"description": "minContains = 0 would make contains always pass",
"data": [ 2 ],
"valid": false
}
]
},
{
"description": "if with boolean schema true",
"schema": { "if": true, "then": { "const": "then" }, "else": { "const": "else" } },
"tests": [
{
"description": "boolean schema true in if (invalid when supported)",
"data": "then",
"valid": true
},
{
"description": "boolean schema true in if (valid when supported)",
"data": "else",
"valid": true
}
]
},
{
"description": "if with boolean schema false",
"schema": { "if": false, "then": { "const": "then" }, "else": { "const": "else" } },
"tests": [
{
"description": "boolean schema false in if (invalid when supported)",
"data": "then",
"valid": true
},
{
"description": "boolean schema false in if (valid when supported)",
"data": "else",
"valid": true
}
]
},
{
"description": "$recursiveRef without $recursiveAnchor works like $ref",
"schema": {
"properties": {
"foo": { "$recursiveRef": "#" }
},
"additionalProperties": false
},
"tests": [
{
"description": "match",
"data": {"foo": false},
"valid": true
},
{
"description": "recursive match",
"data": { "foo": { "foo": false } },
"valid": true
},
{
"description": "mismatch",
"data": { "bar": false },
"valid": false
},
{
"description": "recursive mismatch",
"data": { "foo": { "bar": false } },
"valid": true
}
]
},
{
"description": "$recursiveRef without using nesting",
"schema": {
"$id": "http://localhost:4242",
"definitions": {
"myobject": {
"$id": "myobject.json",
"$recursiveAnchor": true,
"anyOf": [
{ "type": "string" },
{
"type": "object",
"additionalProperties": { "$recursiveRef": "#" }
}
]
}
},
"anyOf": [
{ "type": "integer" },
{ "$ref": "#/definitions/myobject" }
]
},
"tests": [
{
"description": "integer matches at the outer level",
"data": 1,
"valid": true
},
{
"description": "single level match",
"data": { "foo": "hi" },
"valid": true
},
{
"description": "integer does not match as a property value",
"data": { "foo": 1 },
"valid": true
},
{
"description": "two levels, additionalProperties always matches, 1",
"data": { "foo": { "bar": "hi" } },
"valid": true
},
{
"description": "two levels, additionalProperties always matches, 2",
"data": { "foo": { "bar": 1 } },
"valid": true
}
]
},
{
"description": "$recursiveRef with nesting",
"schema": {
"$id": "http://localhost:4242",
"$recursiveAnchor": true,
"definitions": {
"myobject": {
"$id": "myobject.json",
"$recursiveAnchor": true,
"anyOf": [
{ "type": "string" },
{
"type": "object",
"additionalProperties": { "$recursiveRef": "#" }
}
]
}
},
"anyOf": [
{ "type": "integer" },
{ "$ref": "#/definitions/myobject" }
]
},
"tests": [
{
"description": "integer matches at the outer level",
"data": 1,
"valid": true
},
{
"description": "single level match",
"data": { "foo": "hi" },
"valid": true
},
{
"description": "integer now matches as a property value",
"data": { "foo": 1 },
"valid": true
},
{
"description": "two levels, properties match with inner definition",
"data": { "foo": { "bar": "hi" } },
"valid": true
},
{
"description": "two levels, properties match with $recursiveRef",
"data": { "foo": { "bar": 1 } },
"valid": true
}
]
}
]

View File

@ -0,0 +1,82 @@
[
{
"description": "Proper UTF-16 surrogate pair handling: pattern",
"comment": "Optional because .Net doesn't correctly handle 32-bit Unicode characters",
"schema": { "pattern": "^🐲*$" },
"tests": [
{
"description": "matches empty",
"data": "",
"valid": true
},
{
"description": "matches single",
"data": "🐲",
"valid": true
},
{
"description": "matches two",
"data": "🐲🐲",
"valid": true
},
{
"description": "doesn't match one",
"data": "🐉",
"valid": false
},
{
"description": "doesn't match two",
"data": "🐉🐉",
"valid": false
},
{
"description": "doesn't match one ASCII",
"data": "D",
"valid": false
},
{
"description": "doesn't match two ASCII",
"data": "DD",
"valid": false
}
]
},
{
"description": "Proper UTF-16 surrogate pair handling: patternProperties",
"comment": "Optional because .Net doesn't correctly handle 32-bit Unicode characters",
"schema": {
"patternProperties": {
"^🐲*$": {
"type": "integer"
}
}
},
"tests": [
{
"description": "matches empty",
"data": { "": 1 },
"valid": true
},
{
"description": "matches single",
"data": { "🐲": 1 },
"valid": true
},
{
"description": "matches two",
"data": { "🐲🐲": 1 },
"valid": true
},
{
"description": "doesn't match one",
"data": { "🐲": "hello" },
"valid": false
},
{
"description": "doesn't match two",
"data": { "🐲🐲": "hello" },
"valid": false
}
]
}
]

View File

@ -0,0 +1,59 @@
[
{
"description": "pattern validation",
"schema": {"pattern": "^a*$"},
"tests": [
{
"description": "a matching pattern is valid",
"data": "aaa",
"valid": true
},
{
"description": "a non-matching pattern is invalid",
"data": "abc",
"valid": false
},
{
"description": "ignores booleans",
"data": true,
"valid": true
},
{
"description": "ignores integers",
"data": 123,
"valid": true
},
{
"description": "ignores floats",
"data": 1.0,
"valid": true
},
{
"description": "ignores objects",
"data": {},
"valid": true
},
{
"description": "ignores arrays",
"data": [],
"valid": true
},
{
"description": "ignores null",
"data": null,
"valid": true
}
]
},
{
"description": "pattern is not anchored",
"schema": {"pattern": "a+"},
"tests": [
{
"description": "matches a substring",
"data": "xxaayy",
"valid": true
}
]
}
]

View File

@ -0,0 +1,156 @@
[
{
"description":
"patternProperties validates properties matching a regex",
"schema": {
"patternProperties": {
"f.*o": {"type": "integer"}
}
},
"tests": [
{
"description": "a single valid match is valid",
"data": {"foo": 1},
"valid": true
},
{
"description": "multiple valid matches is valid",
"data": {"foo": 1, "foooooo" : 2},
"valid": true
},
{
"description": "a single invalid match is invalid",
"data": {"foo": "bar", "fooooo": 2},
"valid": false
},
{
"description": "multiple invalid matches is invalid",
"data": {"foo": "bar", "foooooo" : "baz"},
"valid": false
},
{
"description": "ignores arrays",
"data": ["foo"],
"valid": true
},
{
"description": "ignores strings",
"data": "foo",
"valid": true
},
{
"description": "ignores other non-objects",
"data": 12,
"valid": true
}
]
},
{
"description": "multiple simultaneous patternProperties are validated",
"schema": {
"patternProperties": {
"a*": {"type": "integer"},
"aaa*": {"maximum": 20}
}
},
"tests": [
{
"description": "a single valid match is valid",
"data": {"a": 21},
"valid": true
},
{
"description": "a simultaneous match is valid",
"data": {"aaaa": 18},
"valid": true
},
{
"description": "multiple matches is valid",
"data": {"a": 21, "aaaa": 18},
"valid": true
},
{
"description": "an invalid due to one is invalid",
"data": {"a": "bar"},
"valid": false
},
{
"description": "an invalid due to the other is invalid",
"data": {"aaaa": 31},
"valid": false
},
{
"description": "an invalid due to both is invalid",
"data": {"aaa": "foo", "aaaa": 31},
"valid": false
}
]
},
{
"description": "regexes are not anchored by default and are case sensitive",
"schema": {
"patternProperties": {
"[0-9]{2,}": { "type": "boolean" },
"X_": { "type": "string" }
}
},
"tests": [
{
"description": "non recognized members are ignored",
"data": { "answer 1": "42" },
"valid": true
},
{
"description": "recognized members are accounted for",
"data": { "a31b": null },
"valid": false
},
{
"description": "regexes are case sensitive",
"data": { "a_x_3": 3 },
"valid": true
},
{
"description": "regexes are case sensitive, 2",
"data": { "a_X_3": 3 },
"valid": false
}
]
},
{
"description": "patternProperties with boolean schemas",
"schema": {
"patternProperties": {
"f.*": true,
"b.*": false
}
},
"tests": [
{
"description": "object with property matching schema true is valid",
"data": {"foo": 1},
"valid": true
},
{
"description": "object with property matching schema false is invalid",
"data": {"bar": 2},
"valid": false
},
{
"description": "object with both properties is invalid",
"data": {"foo": 1, "bar": 2},
"valid": false
},
{
"description": "object with a property matching both true and false is invalid",
"data": {"foobar":1},
"valid": false
},
{
"description": "empty object is valid",
"data": {},
"valid": true
}
]
}
]

View File

@ -0,0 +1,167 @@
[
{
"description": "object properties validation",
"schema": {
"properties": {
"foo": {"type": "integer"},
"bar": {"type": "string"}
}
},
"tests": [
{
"description": "both properties present and valid is valid",
"data": {"foo": 1, "bar": "baz"},
"valid": true
},
{
"description": "one property invalid is invalid",
"data": {"foo": 1, "bar": {}},
"valid": false
},
{
"description": "both properties invalid is invalid",
"data": {"foo": [], "bar": {}},
"valid": false
},
{
"description": "doesn't invalidate other properties",
"data": {"quux": []},
"valid": true
},
{
"description": "ignores arrays",
"data": [],
"valid": true
},
{
"description": "ignores other non-objects",
"data": 12,
"valid": true
}
]
},
{
"description":
"properties, patternProperties, additionalProperties interaction",
"schema": {
"properties": {
"foo": {"type": "array", "maxItems": 3},
"bar": {"type": "array"}
},
"patternProperties": {"f.o": {"minItems": 2}},
"additionalProperties": {"type": "integer"}
},
"tests": [
{
"description": "property validates property",
"data": {"foo": [1, 2]},
"valid": true
},
{
"description": "property invalidates property",
"data": {"foo": [1, 2, 3, 4]},
"valid": false
},
{
"description": "patternProperty invalidates property",
"data": {"foo": []},
"valid": false
},
{
"description": "patternProperty validates nonproperty",
"data": {"fxo": [1, 2]},
"valid": true
},
{
"description": "patternProperty invalidates nonproperty",
"data": {"fxo": []},
"valid": false
},
{
"description": "additionalProperty ignores property",
"data": {"bar": []},
"valid": true
},
{
"description": "additionalProperty validates others",
"data": {"quux": 3},
"valid": true
},
{
"description": "additionalProperty invalidates others",
"data": {"quux": "foo"},
"valid": false
}
]
},
{
"description": "properties with boolean schema",
"schema": {
"properties": {
"foo": true,
"bar": false
}
},
"tests": [
{
"description": "no property present is valid",
"data": {},
"valid": true
},
{
"description": "only 'true' property present is valid",
"data": {"foo": 1},
"valid": true
},
{
"description": "only 'false' property present is invalid",
"data": {"bar": 2},
"valid": false
},
{
"description": "both properties present is invalid",
"data": {"foo": 1, "bar": 2},
"valid": false
}
]
},
{
"description": "properties with escaped characters",
"schema": {
"properties": {
"foo\nbar": {"type": "number"},
"foo\"bar": {"type": "number"},
"foo\\bar": {"type": "number"},
"foo\rbar": {"type": "number"},
"foo\tbar": {"type": "number"},
"foo\fbar": {"type": "number"}
}
},
"tests": [
{
"description": "object with all numbers is valid",
"data": {
"foo\nbar": 1,
"foo\"bar": 1,
"foo\\bar": 1,
"foo\rbar": 1,
"foo\tbar": 1,
"foo\fbar": 1
},
"valid": true
},
{
"description": "object with strings is invalid",
"data": {
"foo\nbar": "1",
"foo\"bar": "1",
"foo\\bar": "1",
"foo\rbar": "1",
"foo\tbar": "1",
"foo\fbar": "1"
},
"valid": false
}
]
}
]

View File

@ -0,0 +1,107 @@
[
{
"description": "propertyNames validation",
"schema": {
"propertyNames": {"maxLength": 3}
},
"tests": [
{
"description": "all property names valid",
"data": {
"f": {},
"foo": {}
},
"valid": true
},
{
"description": "some property names invalid",
"data": {
"foo": {},
"foobar": {}
},
"valid": false
},
{
"description": "object without properties is valid",
"data": {},
"valid": true
},
{
"description": "ignores arrays",
"data": [1, 2, 3, 4],
"valid": true
},
{
"description": "ignores strings",
"data": "foobar",
"valid": true
},
{
"description": "ignores other non-objects",
"data": 12,
"valid": true
}
]
},
{
"description": "propertyNames validation with pattern",
"schema": {
"propertyNames": { "pattern": "^a+$" }
},
"tests": [
{
"description": "matching property names valid",
"data": {
"a": {},
"aa": {},
"aaa": {}
},
"valid": true
},
{
"description": "non-matching property name is invalid",
"data": {
"aaA": {}
},
"valid": false
},
{
"description": "object without properties is valid",
"data": {},
"valid": true
}
]
},
{
"description": "propertyNames with boolean schema true",
"schema": {"propertyNames": true},
"tests": [
{
"description": "object with any properties is valid",
"data": {"foo": 1},
"valid": true
},
{
"description": "empty object is valid",
"data": {},
"valid": true
}
]
},
{
"description": "propertyNames with boolean schema false",
"schema": {"propertyNames": false},
"tests": [
{
"description": "object with any properties is invalid",
"data": {"foo": 1},
"valid": false
},
{
"description": "empty object is valid",
"data": {},
"valid": true
}
]
}
]

View File

@ -0,0 +1,612 @@
[
{
"description": "root pointer ref",
"schema": {
"properties": {
"foo": {"$ref": "#"}
},
"additionalProperties": false
},
"tests": [
{
"description": "match",
"data": {"foo": false},
"valid": true
},
{
"description": "recursive match",
"data": {"foo": {"foo": false}},
"valid": true
},
{
"description": "mismatch",
"data": {"bar": false},
"valid": false
},
{
"description": "recursive mismatch",
"data": {"foo": {"bar": false}},
"valid": false
}
]
},
{
"description": "relative pointer ref to object",
"schema": {
"properties": {
"foo": {"type": "integer"},
"bar": {"$ref": "#/properties/foo"}
}
},
"tests": [
{
"description": "match",
"data": {"bar": 3},
"valid": true
},
{
"description": "mismatch",
"data": {"bar": true},
"valid": false
}
]
},
{
"description": "relative pointer ref to array",
"schema": {
"items": [
{"type": "integer"},
{"$ref": "#/items/0"}
]
},
"tests": [
{
"description": "match array",
"data": [1, 2],
"valid": true
},
{
"description": "mismatch array",
"data": [1, "foo"],
"valid": false
}
]
},
{
"description": "escaped pointer ref",
"schema": {
"definitions": {
"tilde~field": {"type": "integer"},
"slash/field": {"type": "integer"},
"percent%field": {"type": "integer"}
},
"properties": {
"tilde": {"$ref": "#/definitions/tilde~0field"},
"slash": {"$ref": "#/definitions/slash~1field"},
"percent": {"$ref": "#/definitions/percent%25field"}
}
},
"tests": [
{
"description": "slash invalid",
"data": {"slash": "aoeu"},
"valid": false
},
{
"description": "tilde invalid",
"data": {"tilde": "aoeu"},
"valid": false
},
{
"description": "percent invalid",
"data": {"percent": "aoeu"},
"valid": false
},
{
"description": "slash valid",
"data": {"slash": 123},
"valid": true
},
{
"description": "tilde valid",
"data": {"tilde": 123},
"valid": true
},
{
"description": "percent valid",
"data": {"percent": 123},
"valid": true
}
]
},
{
"description": "nested refs",
"schema": {
"definitions": {
"a": {"type": "integer"},
"b": {"$ref": "#/definitions/a"},
"c": {"$ref": "#/definitions/b"}
},
"allOf": [{ "$ref": "#/definitions/c" }]
},
"tests": [
{
"description": "nested ref valid",
"data": 5,
"valid": true
},
{
"description": "nested ref invalid",
"data": "a",
"valid": false
}
]
},
{
"description": "ref overrides any sibling keywords",
"schema": {
"definitions": {
"reffed": {
"type": "array"
}
},
"properties": {
"foo": {
"$ref": "#/definitions/reffed",
"maxItems": 2
}
}
},
"tests": [
{
"description": "ref valid",
"data": { "foo": [] },
"valid": true
},
{
"description": "ref valid, maxItems ignored",
"data": { "foo": [ 1, 2, 3] },
"valid": true
},
{
"description": "ref invalid",
"data": { "foo": "string" },
"valid": false
}
]
},
{
"description": "$ref prevents a sibling $id from changing the base uri",
"schema": {
"$id": "http://localhost:1234/sibling_id/base/",
"definitions": {
"foo": {
"$id": "http://localhost:1234/sibling_id/foo.json",
"type": "string"
},
"base_foo": {
"$comment": "this canonical uri is http://localhost:1234/sibling_id/base/foo.json",
"$id": "foo.json",
"type": "number"
}
},
"allOf": [
{
"$comment": "$ref resolves to http://localhost:1234/sibling_id/base/foo.json, not http://localhost:1234/sibling_id/foo.json",
"$id": "http://localhost:1234/sibling_id/",
"$ref": "foo.json"
}
]
},
"tests": [
{
"description": "$ref resolves to /definitions/base_foo, data does not validate",
"data": "a",
"valid": false
},
{
"description": "$ref resolves to /definitions/base_foo, data validates",
"data": 1,
"valid": true
}
]
},
{
"description": "remote ref, containing refs itself",
"schema": {"$ref": "http://json-schema.org/draft-06/schema#"},
"tests": [
{
"description": "remote ref valid",
"data": {"minLength": 1},
"valid": true
},
{
"description": "remote ref invalid",
"data": {"minLength": -1},
"valid": false
}
]
},
{
"description": "property named $ref that is not a reference",
"schema": {
"properties": {
"$ref": {"type": "string"}
}
},
"tests": [
{
"description": "property named $ref valid",
"data": {"$ref": "a"},
"valid": true
},
{
"description": "property named $ref invalid",
"data": {"$ref": 2},
"valid": false
}
]
},
{
"description": "property named $ref, containing an actual $ref",
"schema": {
"properties": {
"$ref": {"$ref": "#/definitions/is-string"}
},
"definitions": {
"is-string": {
"type": "string"
}
}
},
"tests": [
{
"description": "property named $ref valid",
"data": {"$ref": "a"},
"valid": true
},
{
"description": "property named $ref invalid",
"data": {"$ref": 2},
"valid": false
}
]
},
{
"description": "$ref to boolean schema true",
"schema": {
"allOf": [{ "$ref": "#/definitions/bool" }],
"definitions": {
"bool": true
}
},
"tests": [
{
"description": "any value is valid",
"data": "foo",
"valid": true
}
]
},
{
"description": "$ref to boolean schema false",
"schema": {
"allOf": [{ "$ref": "#/definitions/bool" }],
"definitions": {
"bool": false
}
},
"tests": [
{
"description": "any value is invalid",
"data": "foo",
"valid": false
}
]
},
{
"description": "Recursive references between schemas",
"schema": {
"$id": "http://localhost:1234/tree",
"description": "tree of nodes",
"type": "object",
"properties": {
"meta": {"type": "string"},
"nodes": {
"type": "array",
"items": {"$ref": "node"}
}
},
"required": ["meta", "nodes"],
"definitions": {
"node": {
"$id": "http://localhost:1234/node",
"description": "node",
"type": "object",
"properties": {
"value": {"type": "number"},
"subtree": {"$ref": "tree"}
},
"required": ["value"]
}
}
},
"tests": [
{
"description": "valid tree",
"data": {
"meta": "root",
"nodes": [
{
"value": 1,
"subtree": {
"meta": "child",
"nodes": [
{"value": 1.1},
{"value": 1.2}
]
}
},
{
"value": 2,
"subtree": {
"meta": "child",
"nodes": [
{"value": 2.1},
{"value": 2.2}
]
}
}
]
},
"valid": true
},
{
"description": "invalid tree",
"data": {
"meta": "root",
"nodes": [
{
"value": 1,
"subtree": {
"meta": "child",
"nodes": [
{"value": "string is invalid"},
{"value": 1.2}
]
}
},
{
"value": 2,
"subtree": {
"meta": "child",
"nodes": [
{"value": 2.1},
{"value": 2.2}
]
}
}
]
},
"valid": false
}
]
},
{
"description": "refs with quote",
"schema": {
"properties": {
"foo\"bar": {"$ref": "#/definitions/foo%22bar"}
},
"definitions": {
"foo\"bar": {"type": "number"}
}
},
"tests": [
{
"description": "object with numbers is valid",
"data": {
"foo\"bar": 1
},
"valid": true
},
{
"description": "object with strings is invalid",
"data": {
"foo\"bar": "1"
},
"valid": false
}
]
},
{
"description": "Location-independent identifier",
"schema": {
"allOf": [{
"$ref": "#foo"
}],
"definitions": {
"A": {
"$id": "#foo",
"type": "integer"
}
}
},
"tests": [
{
"data": 1,
"description": "match",
"valid": true
},
{
"data": "a",
"description": "mismatch",
"valid": false
}
]
},
{
"description": "Location-independent identifier with base URI change in subschema",
"schema": {
"$id": "http://localhost:1234/root",
"allOf": [{
"$ref": "http://localhost:1234/nested.json#foo"
}],
"definitions": {
"A": {
"$id": "nested.json",
"definitions": {
"B": {
"$id": "#foo",
"type": "integer"
}
}
}
}
},
"tests": [
{
"data": 1,
"description": "match",
"valid": true
},
{
"data": "a",
"description": "mismatch",
"valid": false
}
]
},
{
"description": "naive replacement of $ref with its destination is not correct",
"schema": {
"definitions": {
"a_string": { "type": "string" }
},
"enum": [
{ "$ref": "#/definitions/a_string" }
]
},
"tests": [
{
"description": "do not evaluate the $ref inside the enum, matching any string",
"data": "this is a string",
"valid": false
},
{
"description": "do not evaluate the $ref inside the enum, definition exact match",
"data": { "type": "string" },
"valid": false
},
{
"description": "match the enum exactly",
"data": { "$ref": "#/definitions/a_string" },
"valid": true
}
]
},
{
"description": "refs with relative uris and defs",
"schema": {
"$id": "http://example.com/schema-relative-uri-defs1.json",
"properties": {
"foo": {
"$id": "schema-relative-uri-defs2.json",
"definitions": {
"inner": {
"properties": {
"bar": { "type": "string" }
}
}
},
"allOf": [ { "$ref": "#/definitions/inner" } ]
}
},
"allOf": [ { "$ref": "schema-relative-uri-defs2.json" } ]
},
"tests": [
{
"description": "invalid on inner field",
"data": {
"foo": {
"bar": 1
},
"bar": "a"
},
"valid": false
},
{
"description": "invalid on outer field",
"data": {
"foo": {
"bar": "a"
},
"bar": 1
},
"valid": false
},
{
"description": "valid on both fields",
"data": {
"foo": {
"bar": "a"
},
"bar": "a"
},
"valid": true
}
]
},
{
"description": "relative refs with absolute uris and defs",
"schema": {
"$id": "http://example.com/schema-refs-absolute-uris-defs1.json",
"properties": {
"foo": {
"$id": "http://example.com/schema-refs-absolute-uris-defs2.json",
"definitions": {
"inner": {
"properties": {
"bar": { "type": "string" }
}
}
},
"allOf": [ { "$ref": "#/definitions/inner" } ]
}
},
"allOf": [ { "$ref": "schema-refs-absolute-uris-defs2.json" } ]
},
"tests": [
{
"description": "invalid on inner field",
"data": {
"foo": {
"bar": 1
},
"bar": "a"
},
"valid": false
},
{
"description": "invalid on outer field",
"data": {
"foo": {
"bar": "a"
},
"bar": 1
},
"valid": false
},
{
"description": "valid on both fields",
"data": {
"foo": {
"bar": "a"
},
"bar": "a"
},
"valid": true
}
]
}
]

View File

@ -0,0 +1,196 @@
[
{
"description": "remote ref",
"schema": {"$ref": "http://localhost:1234/integer.json"},
"tests": [
{
"description": "remote ref valid",
"data": 1,
"valid": true
},
{
"description": "remote ref invalid",
"data": "a",
"valid": false
}
]
},
{
"description": "fragment within remote ref",
"schema": {"$ref": "http://localhost:1234/subSchemas.json#/integer"},
"tests": [
{
"description": "remote fragment valid",
"data": 1,
"valid": true
},
{
"description": "remote fragment invalid",
"data": "a",
"valid": false
}
]
},
{
"description": "ref within remote ref",
"schema": {
"$ref": "http://localhost:1234/subSchemas.json#/refToInteger"
},
"tests": [
{
"description": "ref within ref valid",
"data": 1,
"valid": true
},
{
"description": "ref within ref invalid",
"data": "a",
"valid": false
}
]
},
{
"description": "base URI change",
"schema": {
"$id": "http://localhost:1234/",
"items": {
"$id": "baseUriChange/",
"items": {"$ref": "folderInteger.json"}
}
},
"tests": [
{
"description": "base URI change ref valid",
"data": [[1]],
"valid": true
},
{
"description": "base URI change ref invalid",
"data": [["a"]],
"valid": false
}
]
},
{
"description": "base URI change - change folder",
"schema": {
"$id": "http://localhost:1234/scope_change_defs1.json",
"type" : "object",
"properties": {
"list": {"$ref": "#/definitions/baz"}
},
"definitions": {
"baz": {
"$id": "baseUriChangeFolder/",
"type": "array",
"items": {"$ref": "folderInteger.json"}
}
}
},
"tests": [
{
"description": "number is valid",
"data": {"list": [1]},
"valid": true
},
{
"description": "string is invalid",
"data": {"list": ["a"]},
"valid": false
}
]
},
{
"description": "base URI change - change folder in subschema",
"schema": {
"$id": "http://localhost:1234/scope_change_defs2.json",
"type" : "object",
"properties": {
"list": {"$ref": "#/definitions/baz/definitions/bar"}
},
"definitions": {
"baz": {
"$id": "baseUriChangeFolderInSubschema/",
"definitions": {
"bar": {
"type": "array",
"items": {"$ref": "folderInteger.json"}
}
}
}
}
},
"tests": [
{
"description": "number is valid",
"data": {"list": [1]},
"valid": true
},
{
"description": "string is invalid",
"data": {"list": ["a"]},
"valid": false
}
]
},
{
"description": "root ref in remote ref",
"schema": {
"$id": "http://localhost:1234/object",
"type": "object",
"properties": {
"name": {"$ref": "name.json#/definitions/orNull"}
}
},
"tests": [
{
"description": "string is valid",
"data": {
"name": "foo"
},
"valid": true
},
{
"description": "null is valid",
"data": {
"name": null
},
"valid": true
},
{
"description": "object is invalid",
"data": {
"name": {
"name": null
}
},
"valid": false
}
]
},
{
"description": "remote ref with ref to definitions",
"schema": {
"$id": "http://localhost:1234/schema-remote-ref-ref-defs1.json",
"allOf": [
{ "$ref": "ref-and-definitions.json" }
]
},
"tests": [
{
"description": "invalid",
"data": {
"bar": 1
},
"valid": false
},
{
"description": "valid",
"data": {
"bar": "a"
},
"valid": true
}
]
}
]

View File

@ -0,0 +1,105 @@
[
{
"description": "required validation",
"schema": {
"properties": {
"foo": {},
"bar": {}
},
"required": ["foo"]
},
"tests": [
{
"description": "present required property is valid",
"data": {"foo": 1},
"valid": true
},
{
"description": "non-present required property is invalid",
"data": {"bar": 1},
"valid": false
},
{
"description": "ignores arrays",
"data": [],
"valid": true
},
{
"description": "ignores strings",
"data": "",
"valid": true
},
{
"description": "ignores other non-objects",
"data": 12,
"valid": true
}
]
},
{
"description": "required default validation",
"schema": {
"properties": {
"foo": {}
}
},
"tests": [
{
"description": "not required by default",
"data": {},
"valid": true
}
]
},
{
"description": "required with empty array",
"schema": {
"properties": {
"foo": {}
},
"required": []
},
"tests": [
{
"description": "property not required",
"data": {},
"valid": true
}
]
},
{
"description": "required with escaped characters",
"schema": {
"required": [
"foo\nbar",
"foo\"bar",
"foo\\bar",
"foo\rbar",
"foo\tbar",
"foo\fbar"
]
},
"tests": [
{
"description": "object with all properties present is valid",
"data": {
"foo\nbar": 1,
"foo\"bar": 1,
"foo\\bar": 1,
"foo\rbar": 1,
"foo\tbar": 1,
"foo\fbar": 1
},
"valid": true
},
{
"description": "object with some properties missing is invalid",
"data": {
"foo\nbar": "1",
"foo\"bar": "1"
},
"valid": false
}
]
}
]

View File

@ -0,0 +1,474 @@
[
{
"description": "integer type matches integers",
"schema": {"type": "integer"},
"tests": [
{
"description": "an integer is an integer",
"data": 1,
"valid": true
},
{
"description": "a float with zero fractional part is an integer",
"data": 1.0,
"valid": true
},
{
"description": "a float is not an integer",
"data": 1.1,
"valid": false
},
{
"description": "a string is not an integer",
"data": "foo",
"valid": false
},
{
"description": "a string is still not an integer, even if it looks like one",
"data": "1",
"valid": false
},
{
"description": "an object is not an integer",
"data": {},
"valid": false
},
{
"description": "an array is not an integer",
"data": [],
"valid": false
},
{
"description": "a boolean is not an integer",
"data": true,
"valid": false
},
{
"description": "null is not an integer",
"data": null,
"valid": false
}
]
},
{
"description": "number type matches numbers",
"schema": {"type": "number"},
"tests": [
{
"description": "an integer is a number",
"data": 1,
"valid": true
},
{
"description": "a float with zero fractional part is a number (and an integer)",
"data": 1.0,
"valid": true
},
{
"description": "a float is a number",
"data": 1.1,
"valid": true
},
{
"description": "a string is not a number",
"data": "foo",
"valid": false
},
{
"description": "a string is still not a number, even if it looks like one",
"data": "1",
"valid": false
},
{
"description": "an object is not a number",
"data": {},
"valid": false
},
{
"description": "an array is not a number",
"data": [],
"valid": false
},
{
"description": "a boolean is not a number",
"data": true,
"valid": false
},
{
"description": "null is not a number",
"data": null,
"valid": false
}
]
},
{
"description": "string type matches strings",
"schema": {"type": "string"},
"tests": [
{
"description": "1 is not a string",
"data": 1,
"valid": false
},
{
"description": "a float is not a string",
"data": 1.1,
"valid": false
},
{
"description": "a string is a string",
"data": "foo",
"valid": true
},
{
"description": "a string is still a string, even if it looks like a number",
"data": "1",
"valid": true
},
{
"description": "an empty string is still a string",
"data": "",
"valid": true
},
{
"description": "an object is not a string",
"data": {},
"valid": false
},
{
"description": "an array is not a string",
"data": [],
"valid": false
},
{
"description": "a boolean is not a string",
"data": true,
"valid": false
},
{
"description": "null is not a string",
"data": null,
"valid": false
}
]
},
{
"description": "object type matches objects",
"schema": {"type": "object"},
"tests": [
{
"description": "an integer is not an object",
"data": 1,
"valid": false
},
{
"description": "a float is not an object",
"data": 1.1,
"valid": false
},
{
"description": "a string is not an object",
"data": "foo",
"valid": false
},
{
"description": "an object is an object",
"data": {},
"valid": true
},
{
"description": "an array is not an object",
"data": [],
"valid": false
},
{
"description": "a boolean is not an object",
"data": true,
"valid": false
},
{
"description": "null is not an object",
"data": null,
"valid": false
}
]
},
{
"description": "array type matches arrays",
"schema": {"type": "array"},
"tests": [
{
"description": "an integer is not an array",
"data": 1,
"valid": false
},
{
"description": "a float is not an array",
"data": 1.1,
"valid": false
},
{
"description": "a string is not an array",
"data": "foo",
"valid": false
},
{
"description": "an object is not an array",
"data": {},
"valid": false
},
{
"description": "an array is an array",
"data": [],
"valid": true
},
{
"description": "a boolean is not an array",
"data": true,
"valid": false
},
{
"description": "null is not an array",
"data": null,
"valid": false
}
]
},
{
"description": "boolean type matches booleans",
"schema": {"type": "boolean"},
"tests": [
{
"description": "an integer is not a boolean",
"data": 1,
"valid": false
},
{
"description": "zero is not a boolean",
"data": 0,
"valid": false
},
{
"description": "a float is not a boolean",
"data": 1.1,
"valid": false
},
{
"description": "a string is not a boolean",
"data": "foo",
"valid": false
},
{
"description": "an empty string is not a boolean",
"data": "",
"valid": false
},
{
"description": "an object is not a boolean",
"data": {},
"valid": false
},
{
"description": "an array is not a boolean",
"data": [],
"valid": false
},
{
"description": "true is a boolean",
"data": true,
"valid": true
},
{
"description": "false is a boolean",
"data": false,
"valid": true
},
{
"description": "null is not a boolean",
"data": null,
"valid": false
}
]
},
{
"description": "null type matches only the null object",
"schema": {"type": "null"},
"tests": [
{
"description": "an integer is not null",
"data": 1,
"valid": false
},
{
"description": "a float is not null",
"data": 1.1,
"valid": false
},
{
"description": "zero is not null",
"data": 0,
"valid": false
},
{
"description": "a string is not null",
"data": "foo",
"valid": false
},
{
"description": "an empty string is not null",
"data": "",
"valid": false
},
{
"description": "an object is not null",
"data": {},
"valid": false
},
{
"description": "an array is not null",
"data": [],
"valid": false
},
{
"description": "true is not null",
"data": true,
"valid": false
},
{
"description": "false is not null",
"data": false,
"valid": false
},
{
"description": "null is null",
"data": null,
"valid": true
}
]
},
{
"description": "multiple types can be specified in an array",
"schema": {"type": ["integer", "string"]},
"tests": [
{
"description": "an integer is valid",
"data": 1,
"valid": true
},
{
"description": "a string is valid",
"data": "foo",
"valid": true
},
{
"description": "a float is invalid",
"data": 1.1,
"valid": false
},
{
"description": "an object is invalid",
"data": {},
"valid": false
},
{
"description": "an array is invalid",
"data": [],
"valid": false
},
{
"description": "a boolean is invalid",
"data": true,
"valid": false
},
{
"description": "null is invalid",
"data": null,
"valid": false
}
]
},
{
"description": "type as array with one item",
"schema": {
"type": ["string"]
},
"tests": [
{
"description": "string is valid",
"data": "foo",
"valid": true
},
{
"description": "number is invalid",
"data": 123,
"valid": false
}
]
},
{
"description": "type: array or object",
"schema": {
"type": ["array", "object"]
},
"tests": [
{
"description": "array is valid",
"data": [1,2,3],
"valid": true
},
{
"description": "object is valid",
"data": {"foo": 123},
"valid": true
},
{
"description": "number is invalid",
"data": 123,
"valid": false
},
{
"description": "string is invalid",
"data": "foo",
"valid": false
},
{
"description": "null is invalid",
"data": null,
"valid": false
}
]
},
{
"description": "type: array, object or null",
"schema": {
"type": ["array", "object", "null"]
},
"tests": [
{
"description": "array is valid",
"data": [1,2,3],
"valid": true
},
{
"description": "object is valid",
"data": {"foo": 123},
"valid": true
},
{
"description": "null is valid",
"data": null,
"valid": true
},
{
"description": "number is invalid",
"data": 123,
"valid": false
},
{
"description": "string is invalid",
"data": "foo",
"valid": false
}
]
}
]

View File

@ -0,0 +1,404 @@
[
{
"description": "uniqueItems validation",
"schema": {"uniqueItems": true},
"tests": [
{
"description": "unique array of integers is valid",
"data": [1, 2],
"valid": true
},
{
"description": "non-unique array of integers is invalid",
"data": [1, 1],
"valid": false
},
{
"description": "non-unique array of more than two integers is invalid",
"data": [1, 2, 1],
"valid": false
},
{
"description": "numbers are unique if mathematically unequal",
"data": [1.0, 1.00, 1],
"valid": false
},
{
"description": "false is not equal to zero",
"data": [0, false],
"valid": true
},
{
"description": "true is not equal to one",
"data": [1, true],
"valid": true
},
{
"description": "unique array of strings is valid",
"data": ["foo", "bar", "baz"],
"valid": true
},
{
"description": "non-unique array of strings is invalid",
"data": ["foo", "bar", "foo"],
"valid": false
},
{
"description": "unique array of objects is valid",
"data": [{"foo": "bar"}, {"foo": "baz"}],
"valid": true
},
{
"description": "non-unique array of objects is invalid",
"data": [{"foo": "bar"}, {"foo": "bar"}],
"valid": false
},
{
"description": "unique array of nested objects is valid",
"data": [
{"foo": {"bar" : {"baz" : true}}},
{"foo": {"bar" : {"baz" : false}}}
],
"valid": true
},
{
"description": "non-unique array of nested objects is invalid",
"data": [
{"foo": {"bar" : {"baz" : true}}},
{"foo": {"bar" : {"baz" : true}}}
],
"valid": false
},
{
"description": "unique array of arrays is valid",
"data": [["foo"], ["bar"]],
"valid": true
},
{
"description": "non-unique array of arrays is invalid",
"data": [["foo"], ["foo"]],
"valid": false
},
{
"description": "non-unique array of more than two arrays is invalid",
"data": [["foo"], ["bar"], ["foo"]],
"valid": false
},
{
"description": "1 and true are unique",
"data": [1, true],
"valid": true
},
{
"description": "0 and false are unique",
"data": [0, false],
"valid": true
},
{
"description": "[1] and [true] are unique",
"data": [[1], [true]],
"valid": true
},
{
"description": "[0] and [false] are unique",
"data": [[0], [false]],
"valid": true
},
{
"description": "nested [1] and [true] are unique",
"data": [[[1], "foo"], [[true], "foo"]],
"valid": true
},
{
"description": "nested [0] and [false] are unique",
"data": [[[0], "foo"], [[false], "foo"]],
"valid": true
},
{
"description": "unique heterogeneous types are valid",
"data": [{}, [1], true, null, 1, "{}"],
"valid": true
},
{
"description": "non-unique heterogeneous types are invalid",
"data": [{}, [1], true, null, {}, 1],
"valid": false
},
{
"description": "different objects are unique",
"data": [{"a": 1, "b": 2}, {"a": 2, "b": 1}],
"valid": true
},
{
"description": "objects are non-unique despite key order",
"data": [{"a": 1, "b": 2}, {"b": 2, "a": 1}],
"valid": false
},
{
"description": "{\"a\": false} and {\"a\": 0} are unique",
"data": [{"a": false}, {"a": 0}],
"valid": true
},
{
"description": "{\"a\": true} and {\"a\": 1} are unique",
"data": [{"a": true}, {"a": 1}],
"valid": true
}
]
},
{
"description": "uniqueItems with an array of items",
"schema": {
"items": [{"type": "boolean"}, {"type": "boolean"}],
"uniqueItems": true
},
"tests": [
{
"description": "[false, true] from items array is valid",
"data": [false, true],
"valid": true
},
{
"description": "[true, false] from items array is valid",
"data": [true, false],
"valid": true
},
{
"description": "[false, false] from items array is not valid",
"data": [false, false],
"valid": false
},
{
"description": "[true, true] from items array is not valid",
"data": [true, true],
"valid": false
},
{
"description": "unique array extended from [false, true] is valid",
"data": [false, true, "foo", "bar"],
"valid": true
},
{
"description": "unique array extended from [true, false] is valid",
"data": [true, false, "foo", "bar"],
"valid": true
},
{
"description": "non-unique array extended from [false, true] is not valid",
"data": [false, true, "foo", "foo"],
"valid": false
},
{
"description": "non-unique array extended from [true, false] is not valid",
"data": [true, false, "foo", "foo"],
"valid": false
}
]
},
{
"description": "uniqueItems with an array of items and additionalItems=false",
"schema": {
"items": [{"type": "boolean"}, {"type": "boolean"}],
"uniqueItems": true,
"additionalItems": false
},
"tests": [
{
"description": "[false, true] from items array is valid",
"data": [false, true],
"valid": true
},
{
"description": "[true, false] from items array is valid",
"data": [true, false],
"valid": true
},
{
"description": "[false, false] from items array is not valid",
"data": [false, false],
"valid": false
},
{
"description": "[true, true] from items array is not valid",
"data": [true, true],
"valid": false
},
{
"description": "extra items are invalid even if unique",
"data": [false, true, null],
"valid": false
}
]
},
{
"description": "uniqueItems=false validation",
"schema": { "uniqueItems": false },
"tests": [
{
"description": "unique array of integers is valid",
"data": [1, 2],
"valid": true
},
{
"description": "non-unique array of integers is valid",
"data": [1, 1],
"valid": true
},
{
"description": "numbers are unique if mathematically unequal",
"data": [1.0, 1.00, 1],
"valid": true
},
{
"description": "false is not equal to zero",
"data": [0, false],
"valid": true
},
{
"description": "true is not equal to one",
"data": [1, true],
"valid": true
},
{
"description": "unique array of objects is valid",
"data": [{"foo": "bar"}, {"foo": "baz"}],
"valid": true
},
{
"description": "non-unique array of objects is valid",
"data": [{"foo": "bar"}, {"foo": "bar"}],
"valid": true
},
{
"description": "unique array of nested objects is valid",
"data": [
{"foo": {"bar" : {"baz" : true}}},
{"foo": {"bar" : {"baz" : false}}}
],
"valid": true
},
{
"description": "non-unique array of nested objects is valid",
"data": [
{"foo": {"bar" : {"baz" : true}}},
{"foo": {"bar" : {"baz" : true}}}
],
"valid": true
},
{
"description": "unique array of arrays is valid",
"data": [["foo"], ["bar"]],
"valid": true
},
{
"description": "non-unique array of arrays is valid",
"data": [["foo"], ["foo"]],
"valid": true
},
{
"description": "1 and true are unique",
"data": [1, true],
"valid": true
},
{
"description": "0 and false are unique",
"data": [0, false],
"valid": true
},
{
"description": "unique heterogeneous types are valid",
"data": [{}, [1], true, null, 1],
"valid": true
},
{
"description": "non-unique heterogeneous types are valid",
"data": [{}, [1], true, null, {}, 1],
"valid": true
}
]
},
{
"description": "uniqueItems=false with an array of items",
"schema": {
"items": [{"type": "boolean"}, {"type": "boolean"}],
"uniqueItems": false
},
"tests": [
{
"description": "[false, true] from items array is valid",
"data": [false, true],
"valid": true
},
{
"description": "[true, false] from items array is valid",
"data": [true, false],
"valid": true
},
{
"description": "[false, false] from items array is valid",
"data": [false, false],
"valid": true
},
{
"description": "[true, true] from items array is valid",
"data": [true, true],
"valid": true
},
{
"description": "unique array extended from [false, true] is valid",
"data": [false, true, "foo", "bar"],
"valid": true
},
{
"description": "unique array extended from [true, false] is valid",
"data": [true, false, "foo", "bar"],
"valid": true
},
{
"description": "non-unique array extended from [false, true] is valid",
"data": [false, true, "foo", "foo"],
"valid": true
},
{
"description": "non-unique array extended from [true, false] is valid",
"data": [true, false, "foo", "foo"],
"valid": true
}
]
},
{
"description": "uniqueItems=false with an array of items and additionalItems=false",
"schema": {
"items": [{"type": "boolean"}, {"type": "boolean"}],
"uniqueItems": false,
"additionalItems": false
},
"tests": [
{
"description": "[false, true] from items array is valid",
"data": [false, true],
"valid": true
},
{
"description": "[true, false] from items array is valid",
"data": [true, false],
"valid": true
},
{
"description": "[false, false] from items array is valid",
"data": [false, false],
"valid": true
},
{
"description": "[true, true] from items array is valid",
"data": [true, true],
"valid": true
},
{
"description": "extra items are invalid even if unique",
"data": [false, true, null],
"valid": false
}
]
}
]

View File

@ -0,0 +1,56 @@
[
{
"description": "$id inside an unknown keyword is not a real identifier",
"comment": "the implementation must not be confused by an $id in locations we do not know how to parse",
"schema": {
"definitions": {
"id_in_unknown0": {
"not": {
"array_of_schemas": [
{
"$id": "https://localhost:1234/unknownKeyword/my_identifier.json",
"type": "null"
}
]
}
},
"real_id_in_schema": {
"$id": "https://localhost:1234/unknownKeyword/my_identifier.json",
"type": "string"
},
"id_in_unknown1": {
"not": {
"object_of_schemas": {
"foo": {
"$id": "https://localhost:1234/unknownKeyword/my_identifier.json",
"type": "integer"
}
}
}
}
},
"anyOf": [
{ "$ref": "#/definitions/id_in_unknown0" },
{ "$ref": "#/definitions/id_in_unknown1" },
{ "$ref": "https://localhost:1234/unknownKeyword/my_identifier.json" }
]
},
"tests": [
{
"description": "type matches second anyOf, which has a real schema in it",
"data": "a string",
"valid": true
},
{
"description": "type matches non-schema in first anyOf",
"data": null,
"valid": false
},
{
"description": "type matches non-schema in third anyOf",
"data": 1,
"valid": false
}
]
}
]

View File

@ -0,0 +1,220 @@
[
{
"description": "property refs containing component schema",
"schema": {
"properties": {
"foo": {"$ref": "#/components/schemas/PropertyRefsContainingComponentSchema"}
},
"additionalProperties": false
},
"tests": [
{
"description": "match",
"data": {"foo": false},
"valid": true
},
{
"description": "recursive match",
"data": {"foo": {"foo": false}},
"valid": true
},
{
"description": "mismatch",
"data": {"bar": false},
"valid": false
},
{
"description": "recursive mismatch",
"data": {"foo": {"bar": false}},
"valid": false
}
]
},
{
"description": "property refs adjacent property",
"schema": {
"properties": {
"foo": {"type": "integer"},
"bar": {"$ref": "#/components/schemas/PropertyRefsAdjacentProperty/properties/foo"}
}
},
"tests": [
{
"description": "match",
"data": {"bar": 3},
"valid": true
},
{
"description": "mismatch",
"data": {"bar": true},
"valid": false
}
]
},
{
"description": "component refs another component",
"schema": {
"$ref": "#/components/schemas/PropertyNamedRefThatIsNotAReference"
},
"tests": [
{
"description": "property named $ref valid",
"data": {"$ref": "a"},
"valid": true
},
{
"description": "property named $ref invalid",
"data": {"$ref": 2},
"valid": false
}
]
},
{
"description": "ref in additionalProperties",
"schema": {
"additionalProperties": {
"$ref": "#/components/schemas/PropertyNamedRefThatIsNotAReference"
}
},
"tests": [
{
"description": "property named $ref valid",
"data": {"someProp": {"$ref": "a"}},
"valid": true
},
{
"description": "property named $ref invalid",
"data": {"someProp": {"$ref": 2}},
"valid": false
}
]
},
{
"description": "ref in items",
"schema": {
"items": {
"$ref": "#/components/schemas/PropertyNamedRefThatIsNotAReference"
}
},
"tests": [
{
"description": "property named $ref valid",
"data": [{"$ref": "a"}],
"valid": true
},
{
"description": "property named $ref invalid",
"data": [{"$ref": 2}],
"valid": false
}
]
},
{
"description": "ref in property",
"schema": {
"properties": {
"a": {
"$ref": "#/components/schemas/PropertyNamedRefThatIsNotAReference"
}
}
},
"tests": [
{
"description": "property named $ref valid",
"data": {"a": {"$ref": "a"}},
"valid": true
},
{
"description": "property named $ref invalid",
"data": {"a": {"$ref": 2}},
"valid": false
}
]
},
{
"description": "ref in allOf",
"schema": {
"allOf": [
{
"$ref": "#/components/schemas/PropertyNamedRefThatIsNotAReference"
}
]
},
"tests": [
{
"description": "property named $ref valid",
"data": {"$ref": "a"},
"valid": true
},
{
"description": "property named $ref invalid",
"data": {"$ref": 2},
"valid": false
}
]
},
{
"description": "ref in oneOf",
"schema": {
"oneOf": [
{
"$ref": "#/components/schemas/PropertyNamedRefThatIsNotAReference"
}
]
},
"tests": [
{
"description": "property named $ref valid",
"data": {"$ref": "a"},
"valid": true
},
{
"description": "property named $ref invalid",
"data": {"$ref": 2},
"valid": false
}
]
},
{
"description": "ref in anyOf",
"schema": {
"anyOf": [
{
"$ref": "#/components/schemas/PropertyNamedRefThatIsNotAReference"
}
]
},
"tests": [
{
"description": "property named $ref valid",
"data": {"$ref": "a"},
"valid": true
},
{
"description": "property named $ref invalid",
"data": {"$ref": 2},
"valid": false
}
]
},
{
"description": "ref in not",
"schema": {
"not": {
"$ref": "#/components/schemas/PropertyNamedRefThatIsNotAReference"
}
},
"tests": [
{
"description": "property named $ref invalid",
"data": {"$ref": "a"},
"valid": false
},
{
"description": "property named $ref valid",
"data": {"$ref": 2},
"valid": true
}
]
}
]

View File

@ -0,0 +1,43 @@
[
{
"description": "array type matches arrays",
"schema": {"type": "array", "items": {}},
"tests": [
{
"description": "an integer is not an array",
"data": 1,
"valid": false
},
{
"description": "a float is not an array",
"data": 1.1,
"valid": false
},
{
"description": "a string is not an array",
"data": "foo",
"valid": false
},
{
"description": "an object is not an array",
"data": {},
"valid": false
},
{
"description": "an array is an array",
"data": [],
"valid": true
},
{
"description": "a boolean is not an array",
"data": true,
"valid": false
},
{
"description": "null is not an array",
"data": null,
"valid": false
}
]
}
]

View File

@ -0,0 +1,391 @@
import dataclasses
import re
import json
import pathlib
import typing
import yaml
"""
This file ingests json schemas from
https://github.com/json-schema-org/JSON-Schema-Test-Suite/tree/main/tests
and writes those test schemas and test cases into a sample openapi spec document
That spec document can then be used to write clients or server stubs which
can contain autogenerated tests that use the json schema test cases
The python-experimental client is the first user of this test spec.
TODO:
- [DONE] load json file and write it into components/schemas
- [DONE] ensure that examples are being written there
- [DONE] add recursive casting of test examples to ObjectWithTypeBooleans
- [DONE] move processing to defaultCodegen
- [DONE] turn tests on
- add endpoints with those components in:
- request body
- response body
- all parameter types
- add main spec that uses type spec
"""
@dataclasses.dataclass
class JsonSchemaTestCase:
description: str
data: typing.Union[str, int, float, bool, None, list, dict]
valid: bool
JsonSchemaDict = typing.TypedDict(
'JsonSchema',
{
'additionalProperties': 'JsonSchema',
'allOf': typing.List['JsonSchema'],
'anyOf': typing.List['JsonSchema'],
'default': typing.Any,
'enum': typing.List[typing.Any],
'exclusiveMaximum': typing.Union[int, float],
'exclusiveMinimum': typing.Union[int, float],
'format': str,
'items': 'JsonSchema',
'maximum': typing.Union[int, float],
'maxItems': int,
'maxLength': int,
'maxProperties': int,
'minimum': typing.Union[int, float],
'minItems': int,
'minLength': int,
'minProperties': int,
'multipleOf': typing.Union[int, float],
'not': 'JsonSchema',
'oneOf': typing.List['JsonSchema'],
'pattern': str,
'properties': typing.Dict[str, 'JsonSchema'],
'$ref': str,
'required': typing.List[str],
'type': str,
'uniqueItems': bool,
},
total=False
)
JsonSchema = typing.Union['JsonSchemaDict', bool]
@dataclasses.dataclass
class JsonSchemaTestSchema:
description: str
schema: JsonSchema
tests: typing.List[JsonSchemaTestCase]
comment: typing.Optional[str] = None
class ExclusionReason:
v303_does_not_support_array_of_types = 'v3.0.3 does not support type with array of values'
v303_requires_array_have_items = 'v3.0.3 requires that items MUST be present if the type is array'
v303_does_not_support_additionalItems = 'v3.0.3 does not support the additionalItems keyword'
v303_does_not_support_patternProperties = 'v3.0.3 does not support the patternProperties keyword'
v303_does_not_support_const = 'v3.0.3 does not support the const keyword'
v303_does_not_support_boolean_schemas_in_location = 'v3.0.3 does not support boolean schemas in location'
v303_does_not_support_contains = 'v3.0.3 does not support the contains keyword'
v303_does_not_support_definitions = 'v3.0.3 does not support the definitions keyword'
v303_does_not_support_dependencies = 'v3.0.3 does not support the dependencies keyword'
swagger_parser_enum_type_bug = "swagger-parser has a bug where schema type is incorrectly set for an enum, https://github.com/swagger-api/swagger-parser/issues/1761"
swagger_parser_validation_missing_bug = 'swagger-parser has a bug where validations are unset, https://github.com/swagger-api/swagger-parser/issues/1762'
swagger_parser_items_type_bug = "swagger-parser has a bug where schema type is incorrectly set with items, https://github.com/swagger-api/swagger-parser/issues/1763"
v303_does_not_support_id = 'v3.0.3 does not support the $id keyword'
v303_does_not_support_patternProperties = 'v3.0.3 does not support the patternProperties keyword'
v303_does_not_support_propertyNames = 'v3.0.3 does not support the propertyNames keyword'
v303_does_not_support_items_schema_array = 'v3.0.3 does not support an array of schemas for items'
swagger_parser_exception = 'swagger-parser threw and exception for this test case'
ref_location_not_the_same_for_json_and_openapi = 'the location referenced is not the same going from json schema to openapi'
ref_to_adjacent_property_bug = 'Refing an adjacent property does not work, issue at https://github.com/OpenAPITools/openapi-generator/issues/12729'
swagger_parser_anytype_bug = 'Swagger parser sets type incorrectly for this anyType schema https://github.com/swagger-api/swagger-parser/issues/1603'
component_ref_component_bug = 'A component refing another component does not work, issue at https://github.com/OpenAPITools/openapi-generator/issues/12730'
not_running_the_localhost_server = 'the openapo-generator is not running the localhost server needed to serve remoteRef files'
required_vars_missing_for_anytype_schema_bug = 'fails because of a bug where required vars are forgotten, see issue https://github.com/OpenAPITools/openapi-generator/issues/8906'
v303_requires_that_the_default_value_is_an_allowed_type = 'v3.0.3 requires that the default value is an allowed type per the schema'
not_ref_import_missing = 'this test fails because of this open issue https://github.com/OpenAPITools/openapi-generator/issues/12756'
json_schema_test_draft = 'draft6'
openapi_additions = 'openapi_additions'
FILEPATH_TO_EXCLUDED_CASE_AND_REASON = {
(json_schema_test_draft, 'default.json'): {
'invalid type for default': ExclusionReason.v303_requires_that_the_default_value_is_an_allowed_type,
},
(json_schema_test_draft, 'enum.json'): {
'heterogeneous enum validation': ExclusionReason.swagger_parser_enum_type_bug,
'heterogeneous enum-with-null validation': ExclusionReason.swagger_parser_enum_type_bug,
},
(json_schema_test_draft, 'additionalProperties.json'): {
'non-ASCII pattern with additionalProperties': ExclusionReason.v303_does_not_support_patternProperties,
'additionalProperties being false does not allow other properties': ExclusionReason.v303_does_not_support_patternProperties,
},
(json_schema_test_draft, 'items.json'): {
'an array of schemas for items': ExclusionReason.v303_does_not_support_array_of_types,
'items and subitems': ExclusionReason.v303_does_not_support_definitions,
'items with boolean schema (true)': ExclusionReason.v303_does_not_support_boolean_schemas_in_location,
'items with boolean schemas': ExclusionReason.v303_does_not_support_boolean_schemas_in_location,
'items with boolean schema (false)': ExclusionReason.v303_does_not_support_boolean_schemas_in_location,
'items with boolean schema (false)': ExclusionReason.v303_does_not_support_boolean_schemas_in_location,
'a schema given for items': ExclusionReason.swagger_parser_items_type_bug,
},
(json_schema_test_draft, 'not.json'): {
'not with boolean schema true': ExclusionReason.v303_does_not_support_boolean_schemas_in_location,
'not with boolean schema false': ExclusionReason.v303_does_not_support_boolean_schemas_in_location,
'not multiple types': ExclusionReason.v303_does_not_support_array_of_types,
},
(json_schema_test_draft, 'oneOf.json'): {
'oneOf with missing optional property': ExclusionReason.v303_does_not_support_boolean_schemas_in_location,
},
(json_schema_test_draft, 'properties.json'): {
'properties, patternProperties, additionalProperties interaction': ExclusionReason.v303_does_not_support_patternProperties,
'properties with boolean schema': ExclusionReason.v303_does_not_support_boolean_schemas_in_location,
},
(json_schema_test_draft, 'ref.json'): {
'relative refs with absolute uris and defs': ExclusionReason.v303_does_not_support_id,
'$ref prevents a sibling $id from changing the base uri': ExclusionReason.v303_does_not_support_id,
'property named $ref, containing an actual $ref': ExclusionReason.v303_does_not_support_definitions,
'naive replacement of $ref with its destination is not correct': ExclusionReason.v303_does_not_support_definitions,
'relative pointer ref to array': ExclusionReason.v303_does_not_support_items_schema_array,
'ref overrides any sibling keywords': ExclusionReason.v303_does_not_support_definitions,
'Location-independent identifier with base URI change in subschema': ExclusionReason.v303_does_not_support_definitions,
'escaped pointer ref': ExclusionReason.v303_does_not_support_definitions,
'Location-independent identifier': ExclusionReason.v303_does_not_support_definitions,
'refs with relative uris and defs': ExclusionReason.v303_does_not_support_id,
'Recursive references between schemas': ExclusionReason.v303_does_not_support_definitions,
'refs with quote': ExclusionReason.v303_does_not_support_definitions,
'refs with quote': ExclusionReason.v303_does_not_support_definitions,
'$ref to boolean schema true': ExclusionReason.v303_does_not_support_definitions,
'Recursive references between schemas': ExclusionReason.v303_does_not_support_id,
'nested refs': ExclusionReason.v303_does_not_support_definitions,
'$ref to boolean schema false': ExclusionReason.v303_does_not_support_definitions,
'remote ref, containing refs itself': ExclusionReason.swagger_parser_exception,
'relative pointer ref to object': ExclusionReason.ref_location_not_the_same_for_json_and_openapi,
'root pointer ref': ExclusionReason.ref_location_not_the_same_for_json_and_openapi,
},
(openapi_additions, 'ref.json'): {
'property refs adjacent property': ExclusionReason.ref_to_adjacent_property_bug,
'property refs containing component schema': ExclusionReason.swagger_parser_anytype_bug,
'component refs another component': ExclusionReason.component_ref_component_bug,
'ref in not': ExclusionReason.not_ref_import_missing
},
(json_schema_test_draft, 'refRemote.json'): {
'base URI change - change folder': ExclusionReason.v303_does_not_support_id,
'base URI change - change folder in subschema': ExclusionReason.v303_does_not_support_definitions,
'remote ref with ref to definitions': ExclusionReason.v303_does_not_support_id,
'root ref in remote ref': ExclusionReason.v303_does_not_support_id,
'base URI change': ExclusionReason.v303_does_not_support_id,
'remote ref': ExclusionReason.not_running_the_localhost_server,
'fragment within remote ref': ExclusionReason.not_running_the_localhost_server,
'ref within remote ref': ExclusionReason.not_running_the_localhost_server,
},
(json_schema_test_draft, 'required.json'): {
'required with escaped characters': ExclusionReason.required_vars_missing_for_anytype_schema_bug,
},
(json_schema_test_draft, 'type.json'): {
'multiple types can be specified in an array': ExclusionReason.v303_does_not_support_array_of_types,
'type as array with one item': ExclusionReason.v303_does_not_support_array_of_types,
'type: array or object': ExclusionReason.v303_does_not_support_array_of_types,
'type: array, object or null': ExclusionReason.v303_does_not_support_array_of_types,
'array type matches arrays': ExclusionReason.v303_requires_array_have_items,
},
(json_schema_test_draft, 'uniqueItems.json'): {
'uniqueItems with an array of items': ExclusionReason.v303_does_not_support_items_schema_array,
'uniqueItems=false with an array of items': ExclusionReason.v303_does_not_support_items_schema_array,
'uniqueItems with an array of items and additionalItems=false': ExclusionReason.v303_does_not_support_items_schema_array,
'uniqueItems=false with an array of items and additionalItems=false': ExclusionReason.v303_does_not_support_items_schema_array,
},
}
FILEPATH_TO_EXCLUDE_REASON = {
(json_schema_test_draft, 'additionalItems.json'): ExclusionReason.v303_does_not_support_additionalItems,
(json_schema_test_draft, 'const.json'): ExclusionReason.v303_does_not_support_const,
(json_schema_test_draft, 'boolean_schema.json'): ExclusionReason.v303_does_not_support_boolean_schemas_in_location,
(json_schema_test_draft, 'contains.json'): ExclusionReason.v303_does_not_support_contains,
(json_schema_test_draft, 'definitions.json'): ExclusionReason.v303_does_not_support_definitions,
(json_schema_test_draft, 'dependencies.json'): ExclusionReason.v303_does_not_support_dependencies,
(json_schema_test_draft, 'exclusiveMaximum.json'): ExclusionReason.swagger_parser_validation_missing_bug,
(json_schema_test_draft, 'exclusiveMinimum.json'): ExclusionReason.swagger_parser_validation_missing_bug,
(json_schema_test_draft, 'id.json'): ExclusionReason.v303_does_not_support_id,
(json_schema_test_draft, 'patternProperties.json'): ExclusionReason.v303_does_not_support_patternProperties,
(json_schema_test_draft, 'propertyNames.json'): ExclusionReason.v303_does_not_support_propertyNames,
(json_schema_test_draft, 'unknownKeyword.json'): ExclusionReason.v303_does_not_support_definitions,
}
JSON_SCHEMA_TEST_FILE_TO_FOLDERS = {
'additionalItems.json': (json_schema_test_draft,),
'additionalProperties.json': (json_schema_test_draft,),
# 'allOf.json': (json_schema_test_draft,), # activate later after fixing composition processing
# 'anyOf.json': (json_schema_test_draft,), # activate later after fixing composition processing
'boolean_schema.json': (json_schema_test_draft,),
'const.json': (json_schema_test_draft,),
'contains.json': (json_schema_test_draft,),
'default.json': (json_schema_test_draft,),
'definitions.json': (json_schema_test_draft,),
'dependencies.json': (json_schema_test_draft,),
'enum.json': (json_schema_test_draft,),
'exclusiveMaximum.json': (json_schema_test_draft,),
'exclusiveMinimum.json': (json_schema_test_draft,),
'format.json': (json_schema_test_draft,),
'id.json': (json_schema_test_draft,),
# 'infinite-loop-detection.json': (json_schema_test_draft,), # activate after fixing this
'items.json': (json_schema_test_draft,),
'maximum.json': (json_schema_test_draft,),
'maxItems.json': (json_schema_test_draft,),
'maxLength.json': (json_schema_test_draft,),
'maxProperties.json': (json_schema_test_draft,),
'minimum.json': (json_schema_test_draft,),
'minItems.json': (json_schema_test_draft,),
'minLength.json': (json_schema_test_draft,),
'minProperties.json': (json_schema_test_draft,),
'multipleOf.json': (json_schema_test_draft,),
'not.json': (json_schema_test_draft,),
# 'oneOf.json': (json_schema_test_draft,), # activate after fixing this
'pattern.json': (json_schema_test_draft,),
'patternProperties.json': (json_schema_test_draft,),
'properties.json': (json_schema_test_draft,),
'propertyNames.json': (json_schema_test_draft,),
'ref.json': (json_schema_test_draft, openapi_additions),
'refRemote.json': (json_schema_test_draft,),
'required.json': (json_schema_test_draft,),
'type.json': (json_schema_test_draft, openapi_additions),
'uniqueItems.json': (json_schema_test_draft,),
'unknownKeyword.json': (json_schema_test_draft,),
}
def get_json_schema_test_schemas(file_path: typing.Tuple[str]) -> typing.List[JsonSchemaTestSchema]:
json_schema_test_schemas = []
filename = file_path[-1]
exclude_file_reason = FILEPATH_TO_EXCLUDE_REASON.get(file_path)
if exclude_file_reason:
print(f'Excluding {file_path} because {exclude_file_reason}')
return
excluded_case_to_reason = FILEPATH_TO_EXCLUDED_CASE_AND_REASON.get(file_path, {})
path = pathlib.PurePath(*file_path)
with open(path) as json_file:
test_schema_dicts = json.load(json_file)
for test_schema_dict in test_schema_dicts:
test_schema_dict['tests'] = [JsonSchemaTestCase(**t) for t in test_schema_dict['tests']]
json_schema_test_schema = JsonSchemaTestSchema(**test_schema_dict)
test_case_desc = json_schema_test_schema.description
excluded_reason = excluded_case_to_reason.get(test_case_desc)
if excluded_reason:
print(f'Excluding {test_case_desc} because {excluded_reason}')
continue
json_schema_test_schemas.append(json_schema_test_schema)
return json_schema_test_schemas
openapi_version = '3.0.3'
@dataclasses.dataclass
class OpenApiDocumentInfo:
title: str
description: str
version: str
OpenApiSchema = typing.TypedDict(
'OpenApiSchema',
{
'type': str,
'x-test-examples': typing.Dict[str, JsonSchemaTestCase],
'items': 'OpenApiSchema',
'properties': typing.Dict[str, 'OpenApiSchema']
}
)
@dataclasses.dataclass
class OpenApiExample:
description: str
value: typing.Union[str, int, float, bool, None, list, dict]
OpenApiComponents = typing.TypedDict(
'OpenApiComponents',
{
'schemas': typing.Dict[str, typing.Union[bool, OpenApiSchema]],
'x-schema-test-examples': typing.Dict[str, typing.Dict[str, JsonSchemaTestCase]]
}
)
@dataclasses.dataclass
class OpenApiDocument:
openapi: str
info: OpenApiDocumentInfo
paths: typing.Dict[str, typing.Any]
components: OpenApiComponents
def get_new_openapi() -> OpenApiDocument:
return OpenApiDocument(
openapi=openapi_version,
info=OpenApiDocumentInfo(
title=f"openapi {openapi_version} sample spec",
description=f"sample spec for testing openapi functionality, built from json schema tests for {json_schema_test_draft}",
version="0.0.1"
),
paths={},
components=OpenApiComponents({
'schemas': {},
'x-schema-test-examples': {}
})
)
def description_to_component_name(descr: str) -> str:
res = ''.join(descr.title().split())
return re.sub(r'[^A-Za-z0-9 ]+', '', res)
def get_test_case_name(test: JsonSchemaTestSchema) -> str:
res = ''.join(test.description.title().split())
return re.sub(r'[^A-Za-z0-9 ]+', '', res)
def get_component_schemas_and_test_examples(json_schema_test_file: str, folders: typing.Tuple[str]) -> typing.Dict[str, OpenApiSchema]:
component_schemas = {}
component_name_to_test_examples = {}
for folder in folders:
file_path_tuple = (folder, json_schema_test_file)
test_schemas = get_json_schema_test_schemas(file_path_tuple)
if not test_schemas:
continue
for test_schema in test_schemas:
component_name = description_to_component_name(test_schema.description)
if isinstance(test_schema.schema, bool):
component_schemas[component_name] = test_schema.schema
else:
component_schemas[component_name] = OpenApiSchema(**test_schema.schema)
for test in test_schema.tests:
if component_name not in component_name_to_test_examples:
component_name_to_test_examples[component_name] = {}
test_case_name = get_test_case_name(test)
component_name_to_test_examples[component_name][test_case_name] = test
return component_schemas, component_name_to_test_examples
def write_openapi_spec():
openapi = get_new_openapi()
for json_schema_test_file, folders in JSON_SCHEMA_TEST_FILE_TO_FOLDERS.items():
component_schemas, component_name_to_test_examples = (
get_component_schemas_and_test_examples(json_schema_test_file, folders)
)
for component_name, schema in component_schemas.items():
if component_name in openapi.components['schemas']:
raise ValueError('A component schema with that name is already defined!')
openapi.components['schemas'][component_name] = schema
for component_name, test_examples in component_name_to_test_examples.items():
if component_name in openapi.components['x-schema-test-examples']:
raise ValueError('A component schema test example map with that name is already defined!')
openapi.components['x-schema-test-examples'][component_name] = test_examples
print(
yaml.dump(
dataclasses.asdict(openapi),
sort_keys=False
)
)
spec_out = '3_0_3_unit_test_spec.yaml'
with open(spec_out, 'w') as yaml_out:
yaml_out.write(
yaml.dump(
dataclasses.asdict(openapi),
sort_keys=False
)
)
write_openapi_spec()

View File

@ -0,0 +1,67 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
dev-requirements.txt.log
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
venv/
.venv/
.python-version
.pytest_cache
# Translations
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
# PyBuilder
target/
#Ipython Notebook
.ipynb_checkpoints

View File

@ -0,0 +1,24 @@
# ref: https://docs.gitlab.com/ee/ci/README.html
stages:
- test
.tests:
stage: test
script:
- pip install -r requirements.txt
- pip install -r test-requirements.txt
- pytest --cov=unit_test_api
test-3.5:
extends: .tests
image: python:3.5-alpine
test-3.6:
extends: .tests
image: python:3.6-alpine
test-3.7:
extends: .tests
image: python:3.7-alpine
test-3.8:
extends: .tests
image: python:3.8-alpine

View File

@ -0,0 +1,23 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.
# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md

View File

@ -0,0 +1,213 @@
.gitignore
.gitlab-ci.yml
.travis.yml
README.md
docs/AdditionalpropertiesAllowsASchemaWhichShouldValidate.md
docs/AdditionalpropertiesAreAllowedByDefault.md
docs/AdditionalpropertiesCanExistByItself.md
docs/AdditionalpropertiesShouldNotLookInApplicators.md
docs/ArrayTypeMatchesArrays.md
docs/BooleanTypeMatchesBooleans.md
docs/ByInt.md
docs/ByNumber.md
docs/BySmallNumber.md
docs/DateTimeFormat.md
docs/EmailFormat.md
docs/EnumWith0DoesNotMatchFalse.md
docs/EnumWith1DoesNotMatchTrue.md
docs/EnumWithEscapedCharacters.md
docs/EnumWithFalseDoesNotMatch0.md
docs/EnumWithTrueDoesNotMatch1.md
docs/EnumsInProperties.md
docs/ForbiddenProperty.md
docs/HostnameFormat.md
docs/IntegerTypeMatchesIntegers.md
docs/InvalidInstanceShouldNotRaiseErrorWhenFloatDivisionInf.md
docs/InvalidStringValueForDefault.md
docs/Ipv4Format.md
docs/Ipv6Format.md
docs/JsonPointerFormat.md
docs/MaximumValidation.md
docs/MaximumValidationWithUnsignedInteger.md
docs/MaxitemsValidation.md
docs/MaxlengthValidation.md
docs/Maxproperties0MeansTheObjectIsEmpty.md
docs/MaxpropertiesValidation.md
docs/MinimumValidation.md
docs/MinimumValidationWithSignedInteger.md
docs/MinitemsValidation.md
docs/MinlengthValidation.md
docs/MinpropertiesValidation.md
docs/ModelNot.md
docs/NestedItems.md
docs/NotMoreComplexSchema.md
docs/NulCharactersInStrings.md
docs/NullTypeMatchesOnlyTheNullObject.md
docs/NumberTypeMatchesNumbers.md
docs/ObjectPropertiesValidation.md
docs/PatternIsNotAnchored.md
docs/PatternValidation.md
docs/PropertiesWithEscapedCharacters.md
docs/PropertyNamedRefThatIsNotAReference.md
docs/RefInAdditionalproperties.md
docs/RefInAllof.md
docs/RefInAnyof.md
docs/RefInItems.md
docs/RefInOneof.md
docs/RefInProperty.md
docs/RequiredDefaultValidation.md
docs/RequiredValidation.md
docs/RequiredWithEmptyArray.md
docs/SimpleEnumValidation.md
docs/StringTypeMatchesStrings.md
docs/TheDefaultKeywordDoesNotDoAnythingIfThePropertyIsMissing.md
docs/UniqueitemsFalseValidation.md
docs/UniqueitemsValidation.md
docs/UriFormat.md
docs/UriReferenceFormat.md
docs/UriTemplateFormat.md
git_push.sh
requirements.txt
setup.cfg
setup.py
test-requirements.txt
test/__init__.py
test/test_additionalproperties_allows_a_schema_which_should_validate.py
test/test_additionalproperties_are_allowed_by_default.py
test/test_additionalproperties_can_exist_by_itself.py
test/test_additionalproperties_should_not_look_in_applicators.py
test/test_array_type_matches_arrays.py
test/test_boolean_type_matches_booleans.py
test/test_by_int.py
test/test_by_number.py
test/test_by_small_number.py
test/test_date_time_format.py
test/test_email_format.py
test/test_enum_with0_does_not_match_false.py
test/test_enum_with1_does_not_match_true.py
test/test_enum_with_escaped_characters.py
test/test_enum_with_false_does_not_match0.py
test/test_enum_with_true_does_not_match1.py
test/test_enums_in_properties.py
test/test_forbidden_property.py
test/test_hostname_format.py
test/test_integer_type_matches_integers.py
test/test_invalid_instance_should_not_raise_error_when_float_division_inf.py
test/test_invalid_string_value_for_default.py
test/test_ipv4_format.py
test/test_ipv6_format.py
test/test_json_pointer_format.py
test/test_maximum_validation.py
test/test_maximum_validation_with_unsigned_integer.py
test/test_maxitems_validation.py
test/test_maxlength_validation.py
test/test_maxproperties0_means_the_object_is_empty.py
test/test_maxproperties_validation.py
test/test_minimum_validation.py
test/test_minimum_validation_with_signed_integer.py
test/test_minitems_validation.py
test/test_minlength_validation.py
test/test_minproperties_validation.py
test/test_model_not.py
test/test_nested_items.py
test/test_not_more_complex_schema.py
test/test_nul_characters_in_strings.py
test/test_null_type_matches_only_the_null_object.py
test/test_number_type_matches_numbers.py
test/test_object_properties_validation.py
test/test_pattern_is_not_anchored.py
test/test_pattern_validation.py
test/test_properties_with_escaped_characters.py
test/test_property_named_ref_that_is_not_a_reference.py
test/test_ref_in_additionalproperties.py
test/test_ref_in_allof.py
test/test_ref_in_anyof.py
test/test_ref_in_items.py
test/test_ref_in_oneof.py
test/test_ref_in_property.py
test/test_required_default_validation.py
test/test_required_validation.py
test/test_required_with_empty_array.py
test/test_simple_enum_validation.py
test/test_string_type_matches_strings.py
test/test_the_default_keyword_does_not_do_anything_if_the_property_is_missing.py
test/test_uniqueitems_false_validation.py
test/test_uniqueitems_validation.py
test/test_uri_format.py
test/test_uri_reference_format.py
test/test_uri_template_format.py
tox.ini
unit_test_api/__init__.py
unit_test_api/api/__init__.py
unit_test_api/api_client.py
unit_test_api/apis/__init__.py
unit_test_api/configuration.py
unit_test_api/exceptions.py
unit_test_api/model/__init__.py
unit_test_api/model/additionalproperties_allows_a_schema_which_should_validate.py
unit_test_api/model/additionalproperties_are_allowed_by_default.py
unit_test_api/model/additionalproperties_can_exist_by_itself.py
unit_test_api/model/additionalproperties_should_not_look_in_applicators.py
unit_test_api/model/array_type_matches_arrays.py
unit_test_api/model/boolean_type_matches_booleans.py
unit_test_api/model/by_int.py
unit_test_api/model/by_number.py
unit_test_api/model/by_small_number.py
unit_test_api/model/date_time_format.py
unit_test_api/model/email_format.py
unit_test_api/model/enum_with0_does_not_match_false.py
unit_test_api/model/enum_with1_does_not_match_true.py
unit_test_api/model/enum_with_escaped_characters.py
unit_test_api/model/enum_with_false_does_not_match0.py
unit_test_api/model/enum_with_true_does_not_match1.py
unit_test_api/model/enums_in_properties.py
unit_test_api/model/forbidden_property.py
unit_test_api/model/hostname_format.py
unit_test_api/model/integer_type_matches_integers.py
unit_test_api/model/invalid_instance_should_not_raise_error_when_float_division_inf.py
unit_test_api/model/invalid_string_value_for_default.py
unit_test_api/model/ipv4_format.py
unit_test_api/model/ipv6_format.py
unit_test_api/model/json_pointer_format.py
unit_test_api/model/maximum_validation.py
unit_test_api/model/maximum_validation_with_unsigned_integer.py
unit_test_api/model/maxitems_validation.py
unit_test_api/model/maxlength_validation.py
unit_test_api/model/maxproperties0_means_the_object_is_empty.py
unit_test_api/model/maxproperties_validation.py
unit_test_api/model/minimum_validation.py
unit_test_api/model/minimum_validation_with_signed_integer.py
unit_test_api/model/minitems_validation.py
unit_test_api/model/minlength_validation.py
unit_test_api/model/minproperties_validation.py
unit_test_api/model/model_not.py
unit_test_api/model/nested_items.py
unit_test_api/model/not_more_complex_schema.py
unit_test_api/model/nul_characters_in_strings.py
unit_test_api/model/null_type_matches_only_the_null_object.py
unit_test_api/model/number_type_matches_numbers.py
unit_test_api/model/object_properties_validation.py
unit_test_api/model/pattern_is_not_anchored.py
unit_test_api/model/pattern_validation.py
unit_test_api/model/properties_with_escaped_characters.py
unit_test_api/model/property_named_ref_that_is_not_a_reference.py
unit_test_api/model/ref_in_additionalproperties.py
unit_test_api/model/ref_in_allof.py
unit_test_api/model/ref_in_anyof.py
unit_test_api/model/ref_in_items.py
unit_test_api/model/ref_in_oneof.py
unit_test_api/model/ref_in_property.py
unit_test_api/model/required_default_validation.py
unit_test_api/model/required_validation.py
unit_test_api/model/required_with_empty_array.py
unit_test_api/model/simple_enum_validation.py
unit_test_api/model/string_type_matches_strings.py
unit_test_api/model/the_default_keyword_does_not_do_anything_if_the_property_is_missing.py
unit_test_api/model/uniqueitems_false_validation.py
unit_test_api/model/uniqueitems_validation.py
unit_test_api/model/uri_format.py
unit_test_api/model/uri_reference_format.py
unit_test_api/model/uri_template_format.py
unit_test_api/models/__init__.py
unit_test_api/rest.py
unit_test_api/schemas.py

View File

@ -0,0 +1,13 @@
# ref: https://docs.travis-ci.com/user/languages/python
language: python
python:
- "3.5"
- "3.6"
- "3.7"
- "3.8"
# command to install dependencies
install:
- "pip install -r requirements.txt"
- "pip install -r test-requirements.txt"
# command to run tests
script: pytest --cov=unit_test_api

View File

@ -0,0 +1,16 @@
REQUIREMENTS_FILE=dev-requirements.txt
REQUIREMENTS_OUT=dev-requirements.txt.log
SETUP_OUT=*.egg-info
VENV=venv
clean:
rm -rf $(REQUIREMENTS_OUT)
rm -rf $(SETUP_OUT)
rm -rf $(VENV)
rm -rf .tox
rm -rf .coverage
find . -name "*.py[oc]" -delete
find . -name "__pycache__" -delete
test: clean
bash ./test_python.sh

View File

@ -0,0 +1,154 @@
# unit-test-api
sample spec for testing openapi functionality, built from json schema tests for draft6
This Python package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
- API version: 0.0.1
- Package version: 1.0.0
- Build package: org.openapitools.codegen.languages.PythonExperimentalClientCodegen
## Requirements.
Python &gt;&#x3D;3.9
v3.9 is needed so one can combine classmethod and property decorators to define
object schema properties as classes
## Installation & Usage
### pip install
If the python package is hosted on a repository, you can install directly using:
```sh
pip install git+https://github.com/GIT_USER_ID/GIT_REPO_ID.git
```
(you may need to run `pip` with root permission: `sudo pip install git+https://github.com/GIT_USER_ID/GIT_REPO_ID.git`)
Then import the package:
```python
import unit_test_api
```
### Setuptools
Install via [Setuptools](http://pypi.python.org/pypi/setuptools).
```sh
python setup.py install --user
```
(or `sudo python setup.py install` to install the package for all users)
Then import the package:
```python
import unit_test_api
```
## Getting Started
Please follow the [installation procedure](#installation--usage) and then run the following:
```python
import time
import unit_test_api
from pprint import pprint
```
## Documentation for API Endpoints
All URIs are relative to *http://localhost*
Class | Method | HTTP request | Description
------------ | ------------- | ------------- | -------------
## Documentation For Models
- [AdditionalpropertiesAllowsASchemaWhichShouldValidate](docs/AdditionalpropertiesAllowsASchemaWhichShouldValidate.md)
- [AdditionalpropertiesAreAllowedByDefault](docs/AdditionalpropertiesAreAllowedByDefault.md)
- [AdditionalpropertiesCanExistByItself](docs/AdditionalpropertiesCanExistByItself.md)
- [AdditionalpropertiesShouldNotLookInApplicators](docs/AdditionalpropertiesShouldNotLookInApplicators.md)
- [ArrayTypeMatchesArrays](docs/ArrayTypeMatchesArrays.md)
- [BooleanTypeMatchesBooleans](docs/BooleanTypeMatchesBooleans.md)
- [ByInt](docs/ByInt.md)
- [ByNumber](docs/ByNumber.md)
- [BySmallNumber](docs/BySmallNumber.md)
- [DateTimeFormat](docs/DateTimeFormat.md)
- [EmailFormat](docs/EmailFormat.md)
- [EnumWith0DoesNotMatchFalse](docs/EnumWith0DoesNotMatchFalse.md)
- [EnumWith1DoesNotMatchTrue](docs/EnumWith1DoesNotMatchTrue.md)
- [EnumWithEscapedCharacters](docs/EnumWithEscapedCharacters.md)
- [EnumWithFalseDoesNotMatch0](docs/EnumWithFalseDoesNotMatch0.md)
- [EnumWithTrueDoesNotMatch1](docs/EnumWithTrueDoesNotMatch1.md)
- [EnumsInProperties](docs/EnumsInProperties.md)
- [ForbiddenProperty](docs/ForbiddenProperty.md)
- [HostnameFormat](docs/HostnameFormat.md)
- [IntegerTypeMatchesIntegers](docs/IntegerTypeMatchesIntegers.md)
- [InvalidInstanceShouldNotRaiseErrorWhenFloatDivisionInf](docs/InvalidInstanceShouldNotRaiseErrorWhenFloatDivisionInf.md)
- [InvalidStringValueForDefault](docs/InvalidStringValueForDefault.md)
- [Ipv4Format](docs/Ipv4Format.md)
- [Ipv6Format](docs/Ipv6Format.md)
- [JsonPointerFormat](docs/JsonPointerFormat.md)
- [MaximumValidation](docs/MaximumValidation.md)
- [MaximumValidationWithUnsignedInteger](docs/MaximumValidationWithUnsignedInteger.md)
- [MaxitemsValidation](docs/MaxitemsValidation.md)
- [MaxlengthValidation](docs/MaxlengthValidation.md)
- [Maxproperties0MeansTheObjectIsEmpty](docs/Maxproperties0MeansTheObjectIsEmpty.md)
- [MaxpropertiesValidation](docs/MaxpropertiesValidation.md)
- [MinimumValidation](docs/MinimumValidation.md)
- [MinimumValidationWithSignedInteger](docs/MinimumValidationWithSignedInteger.md)
- [MinitemsValidation](docs/MinitemsValidation.md)
- [MinlengthValidation](docs/MinlengthValidation.md)
- [MinpropertiesValidation](docs/MinpropertiesValidation.md)
- [ModelNot](docs/ModelNot.md)
- [NestedItems](docs/NestedItems.md)
- [NotMoreComplexSchema](docs/NotMoreComplexSchema.md)
- [NulCharactersInStrings](docs/NulCharactersInStrings.md)
- [NullTypeMatchesOnlyTheNullObject](docs/NullTypeMatchesOnlyTheNullObject.md)
- [NumberTypeMatchesNumbers](docs/NumberTypeMatchesNumbers.md)
- [ObjectPropertiesValidation](docs/ObjectPropertiesValidation.md)
- [PatternIsNotAnchored](docs/PatternIsNotAnchored.md)
- [PatternValidation](docs/PatternValidation.md)
- [PropertiesWithEscapedCharacters](docs/PropertiesWithEscapedCharacters.md)
- [PropertyNamedRefThatIsNotAReference](docs/PropertyNamedRefThatIsNotAReference.md)
- [RefInAdditionalproperties](docs/RefInAdditionalproperties.md)
- [RefInAllof](docs/RefInAllof.md)
- [RefInAnyof](docs/RefInAnyof.md)
- [RefInItems](docs/RefInItems.md)
- [RefInOneof](docs/RefInOneof.md)
- [RefInProperty](docs/RefInProperty.md)
- [RequiredDefaultValidation](docs/RequiredDefaultValidation.md)
- [RequiredValidation](docs/RequiredValidation.md)
- [RequiredWithEmptyArray](docs/RequiredWithEmptyArray.md)
- [SimpleEnumValidation](docs/SimpleEnumValidation.md)
- [StringTypeMatchesStrings](docs/StringTypeMatchesStrings.md)
- [TheDefaultKeywordDoesNotDoAnythingIfThePropertyIsMissing](docs/TheDefaultKeywordDoesNotDoAnythingIfThePropertyIsMissing.md)
- [UniqueitemsFalseValidation](docs/UniqueitemsFalseValidation.md)
- [UniqueitemsValidation](docs/UniqueitemsValidation.md)
- [UriFormat](docs/UriFormat.md)
- [UriReferenceFormat](docs/UriReferenceFormat.md)
- [UriTemplateFormat](docs/UriTemplateFormat.md)
## Documentation For Authorization
All endpoints do not require authorization.
## Author
## Notes for Large OpenAPI documents
If the OpenAPI document is large, imports in unit_test_api.apis and unit_test_api.models may fail with a
RecursionError indicating the maximum recursion limit has been exceeded. In that case, there are a couple of solutions:
Solution 1:
Use specific imports for apis and models like:
- `from unit_test_api.api.default_api import DefaultApi`
- `from unit_test_api.model.pet import Pet`
Solution 1:
Before importing the package, adjust the maximum recursion limit as shown below:
```
import sys
sys.setrecursionlimit(1500)
import unit_test_api
from unit_test_api.apis import *
from unit_test_api.models import *
```

View File

@ -0,0 +1,11 @@
# AdditionalpropertiesAllowsASchemaWhichShouldValidate
#### Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**foo** | **bool, date, datetime, dict, float, int, list, str, none_type** | | [optional]
**bar** | **bool, date, datetime, dict, float, int, list, str, none_type** | | [optional]
**any string name** | **bool** | any string name can be used but the value must be the correct type | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@ -0,0 +1,11 @@
# AdditionalpropertiesAreAllowedByDefault
#### Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**foo** | **bool, date, datetime, dict, float, int, list, str, none_type** | | [optional]
**bar** | **bool, date, datetime, dict, float, int, list, str, none_type** | | [optional]
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@ -0,0 +1,9 @@
# AdditionalpropertiesCanExistByItself
#### Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**any string name** | **bool** | any string name can be used but the value must be the correct type | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@ -0,0 +1,9 @@
# AdditionalpropertiesShouldNotLookInApplicators
#### Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**any string name** | **bool** | any string name can be used but the value must be the correct type | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@ -0,0 +1,8 @@
# ArrayTypeMatchesArrays
Type | Description | Notes
------------- | ------------- | -------------
**[bool, date, datetime, dict, float, int, list, str, none_type]** | |
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@ -0,0 +1,8 @@
# BooleanTypeMatchesBooleans
Type | Description | Notes
------------- | ------------- | -------------
**bool** | |
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@ -0,0 +1,9 @@
# ByInt
#### Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@ -0,0 +1,9 @@
# ByNumber
#### Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@ -0,0 +1,9 @@
# BySmallNumber
#### Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@ -0,0 +1,9 @@
# DateTimeFormat
#### Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@ -0,0 +1,9 @@
# EmailFormat
#### Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@ -0,0 +1,8 @@
# EnumWith0DoesNotMatchFalse
Type | Description | Notes
------------- | ------------- | -------------
**float** | | must be one of [0, ]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@ -0,0 +1,8 @@
# EnumWith1DoesNotMatchTrue
Type | Description | Notes
------------- | ------------- | -------------
**float** | | must be one of [1, ]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@ -0,0 +1,8 @@
# EnumWithEscapedCharacters
Type | Description | Notes
------------- | ------------- | -------------
**str** | | must be one of ["foo\nbar", "foo\rbar", ]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@ -0,0 +1,8 @@
# EnumWithFalseDoesNotMatch0
Type | Description | Notes
------------- | ------------- | -------------
**bool** | | must be one of [False, ]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@ -0,0 +1,8 @@
# EnumWithTrueDoesNotMatch1
Type | Description | Notes
------------- | ------------- | -------------
**bool** | | must be one of [True, ]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@ -0,0 +1,11 @@
# EnumsInProperties
#### Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**foo** | **str** | | [optional]
**bar** | **str** | |
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@ -0,0 +1,10 @@
# ForbiddenProperty
#### Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**foo** | **bool, date, datetime, dict, float, int, list, str, none_type** | | [optional]
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

Some files were not shown because too many files have changed in this diff Show More