refactor: Split benchmarks
Signed-off-by: Dmitry Dygalo <dadygalo@gmail.com>
This commit is contained in:
parent
5aaa4aad92
commit
6c76d48215
|
@ -1,6 +1,7 @@
|
|||
# Rust
|
||||
/jsonschema/target
|
||||
/bindings/*/target
|
||||
/bench_helpers/target
|
||||
.hypothesis
|
||||
.benchmarks
|
||||
/jsonschema/Cargo.lock
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "bench_helpers"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "bench_helpers"
|
||||
version = "0.1.0"
|
||||
authors = ["dmitry.dygalo <dadygalo@gmail.com>"]
|
||||
edition = "2018"
|
||||
license = "MIT"
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
criterion = "0.3"
|
|
@ -0,0 +1,108 @@
|
|||
use criterion::Criterion;
|
||||
use serde::Deserialize;
|
||||
use serde_json::{from_str, Value};
|
||||
use std::fs::read_to_string;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct Benchmark<'a> {
|
||||
name: &'a str,
|
||||
schema: Value,
|
||||
valid: Option<Vec<Value>>,
|
||||
invalid: Vec<Value>,
|
||||
}
|
||||
|
||||
pub fn read_json(filepath: &str) -> Value {
|
||||
let content = read_to_string(filepath).expect("Can't read file");
|
||||
from_str(&content).expect("Invalid JSON")
|
||||
}
|
||||
|
||||
fn strip_characters(original: &str) -> String {
|
||||
original
|
||||
.chars()
|
||||
.filter(|&c| !"{}:\" ,[]".contains(c))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn bench_openapi(bench: &mut dyn FnMut(&str, Value, Value)) {
|
||||
let schema = read_json("benches/data/openapi.json");
|
||||
let instance = read_json("benches/data/zuora.json");
|
||||
bench("openapi", schema, instance)
|
||||
}
|
||||
|
||||
pub fn bench_swagger(bench: &mut dyn FnMut(&str, Value, Value)) {
|
||||
let schema = read_json("benches/data/swagger.json");
|
||||
let instance = read_json("benches/data/kubernetes.json");
|
||||
bench("swagger", schema, instance)
|
||||
}
|
||||
|
||||
pub fn bench_geojson(bench: &mut dyn FnMut(&str, Value, Value)) {
|
||||
let schema = read_json("benches/data/geojson.json");
|
||||
let instance = read_json("benches/data/canada.json");
|
||||
bench("geojson", schema, instance)
|
||||
}
|
||||
|
||||
pub fn bench_citm(bench: &mut dyn FnMut(&str, Value, Value)) {
|
||||
let schema = read_json("benches/data/citm_catalog_schema.json");
|
||||
let instance = read_json("benches/data/citm_catalog.json");
|
||||
bench("CITM", schema, instance)
|
||||
}
|
||||
|
||||
pub fn bench_fast(bench: &mut dyn FnMut(&str, Value, Value, Value)) {
|
||||
let schema = read_json("benches/data/fast_schema.json");
|
||||
let valid = read_json("benches/data/fast_valid.json");
|
||||
let invalid = read_json("benches/data/fast_invalid.json");
|
||||
bench("fast", schema, valid, invalid)
|
||||
}
|
||||
|
||||
pub fn bench_keywords(
|
||||
c: &mut Criterion,
|
||||
is_skipped: &dyn Fn(&str) -> bool,
|
||||
is_valid: &dyn Fn(&Value, &Value) -> bool,
|
||||
bench_compile: &mut dyn FnMut(&mut Criterion, &str, &Value),
|
||||
bench_valid: fn(&mut Criterion, &str, &Value, &Value),
|
||||
bench_invalid: fn(&mut Criterion, &str, &Value, &Value),
|
||||
) {
|
||||
let content = read_to_string("benches/data/keywords.json").expect("Can't read file");
|
||||
let data: Vec<Benchmark> = serde_json::from_str(&content).expect("Deserialization error");
|
||||
for benchmark in data {
|
||||
if is_skipped(benchmark.name) {
|
||||
eprintln!("Skip {}", benchmark.name);
|
||||
continue;
|
||||
}
|
||||
// Schema compilation
|
||||
let suffix = strip_characters(&benchmark.schema.to_string());
|
||||
bench_compile(
|
||||
c,
|
||||
&format!("{} {}", benchmark.name, suffix),
|
||||
&benchmark.schema,
|
||||
);
|
||||
// Valid cases
|
||||
if let Some(valid_cases) = benchmark.valid {
|
||||
for instance in valid_cases {
|
||||
if !is_valid(&benchmark.schema, &instance) {
|
||||
eprintln!("This instance should be VALID: {}", benchmark.name);
|
||||
}
|
||||
let suffix = strip_characters(&instance.to_string());
|
||||
bench_valid(
|
||||
c,
|
||||
&format!("{} valid {}", benchmark.name, suffix),
|
||||
&benchmark.schema,
|
||||
&instance,
|
||||
)
|
||||
}
|
||||
}
|
||||
// Invalid cases
|
||||
for instance in benchmark.invalid {
|
||||
if is_valid(&benchmark.schema, &instance) {
|
||||
eprintln!("This instance should be INVALID: {}", benchmark.name);
|
||||
}
|
||||
let suffix = strip_characters(&instance.to_string());
|
||||
bench_invalid(
|
||||
c,
|
||||
&format!("{} invalid {}", benchmark.name, suffix),
|
||||
&benchmark.schema,
|
||||
&instance,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -40,15 +40,27 @@ criterion = ">= 0.1"
|
|||
mockito = ">= 0"
|
||||
json_schema_test_suite = ">= 0.3"
|
||||
jsonschema-valid = "0.4.0"
|
||||
bench_helpers = { path = "../bench_helpers" }
|
||||
valico = "3.6.0"
|
||||
test-case = "1"
|
||||
paste = ">= 0.1"
|
||||
reqwest = { version = ">= 0.10", features = ["blocking", "json"] }
|
||||
|
||||
# Benchmarks for `jsonschema`
|
||||
[[bench]]
|
||||
name = "jsonschema"
|
||||
harness = false
|
||||
|
||||
# Benchmarks for `valico`
|
||||
[[bench]]
|
||||
name = "valico"
|
||||
harness = false
|
||||
|
||||
# Benchmarks for `jsonschema_valid`
|
||||
[[bench]]
|
||||
name = "jsonschema_valid"
|
||||
harness = false
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
lto = "on"
|
||||
|
|
|
@ -0,0 +1,932 @@
|
|||
[
|
||||
{
|
||||
"name": "additional_items_boolean",
|
||||
"schema": {
|
||||
"items": [
|
||||
{},
|
||||
{},
|
||||
{}
|
||||
],
|
||||
"additionalItems": false
|
||||
},
|
||||
"valid": [
|
||||
[
|
||||
1,
|
||||
2,
|
||||
3
|
||||
]
|
||||
],
|
||||
"invalid": [
|
||||
[
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "additional_items_object",
|
||||
"schema": {
|
||||
"items": [
|
||||
{},
|
||||
{},
|
||||
{}
|
||||
],
|
||||
"additionalItems": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"valid": [
|
||||
[
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
"foo"
|
||||
]
|
||||
],
|
||||
"invalid": [
|
||||
[
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "additional_properties_single",
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"valid": [
|
||||
{
|
||||
"foo": "bar"
|
||||
}
|
||||
],
|
||||
"invalid": [
|
||||
{
|
||||
"foo": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "additional_properties_and_properties",
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"properties": {
|
||||
"foo": {}
|
||||
}
|
||||
},
|
||||
"valid": [
|
||||
{
|
||||
"foo": 1
|
||||
}
|
||||
],
|
||||
"invalid": [
|
||||
{
|
||||
"foo": 1,
|
||||
"bar": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "additional_properties_and_pattern_properties",
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"patternProperties": {
|
||||
"f.*o": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"valid": [
|
||||
{
|
||||
"foo": 1
|
||||
}
|
||||
],
|
||||
"invalid": [
|
||||
{
|
||||
"foo": 1,
|
||||
"bar": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "additional_properties_and_properties_and_pattern_properties",
|
||||
"schema": {
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"properties": {
|
||||
"foo": {}
|
||||
},
|
||||
"patternProperties": {
|
||||
"f.*a": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"valid": [
|
||||
{
|
||||
"foo": null,
|
||||
"fza": 2
|
||||
}
|
||||
],
|
||||
"invalid": [
|
||||
{
|
||||
"foo": null,
|
||||
"fzo": 2,
|
||||
"bar": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "additional_properties_false",
|
||||
"schema": {
|
||||
"additionalProperties": false
|
||||
},
|
||||
"valid": [
|
||||
{}
|
||||
],
|
||||
"invalid": [
|
||||
{
|
||||
"foo": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "additional_properties_false_and_properties",
|
||||
"schema": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"foo": {}
|
||||
}
|
||||
},
|
||||
"valid": [
|
||||
{
|
||||
"foo": 1
|
||||
}
|
||||
],
|
||||
"invalid": [
|
||||
{
|
||||
"foo": 1,
|
||||
"bar": 2
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "additional_properties_false_and_pattern_properties",
|
||||
"schema": {
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {
|
||||
"f.*o": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"valid": [
|
||||
{
|
||||
"foo": 1
|
||||
}
|
||||
],
|
||||
"invalid": [
|
||||
{
|
||||
"foo": 1,
|
||||
"bar": 2
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "additional_properties_false_and_properties_and_pattern_properties",
|
||||
"schema": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"foo": {}
|
||||
},
|
||||
"patternProperties": {
|
||||
"f.*o": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"valid": [
|
||||
{
|
||||
"foo": 1
|
||||
}
|
||||
],
|
||||
"invalid": [
|
||||
{
|
||||
"foo": 1,
|
||||
"fz0": 2,
|
||||
"bar": 2
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "all_of",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"minimum": 2
|
||||
}
|
||||
]
|
||||
},
|
||||
"valid": [
|
||||
4
|
||||
],
|
||||
"invalid": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "any_of",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"minimum": 2
|
||||
}
|
||||
]
|
||||
},
|
||||
"valid": [
|
||||
1
|
||||
],
|
||||
"invalid": [
|
||||
1.5
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "any_of_multiple_types",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"valid": [
|
||||
"foo"
|
||||
],
|
||||
"invalid": [
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "boolean_false",
|
||||
"schema": false,
|
||||
"invalid": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "const",
|
||||
"schema": {
|
||||
"const": 1
|
||||
},
|
||||
"valid": [
|
||||
1
|
||||
],
|
||||
"invalid": [
|
||||
"foo"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "contains",
|
||||
"schema": {
|
||||
"contains": {
|
||||
"minimum": 5
|
||||
}
|
||||
},
|
||||
"valid": [
|
||||
[
|
||||
5
|
||||
]
|
||||
],
|
||||
"invalid": [
|
||||
[
|
||||
1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "enum",
|
||||
"schema": {
|
||||
"enum": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
]
|
||||
},
|
||||
"valid": [
|
||||
4
|
||||
],
|
||||
"invalid": [
|
||||
5,
|
||||
"6"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "exclusive_maximum",
|
||||
"schema": {
|
||||
"exclusiveMaximum": 3
|
||||
},
|
||||
"valid": [
|
||||
2
|
||||
],
|
||||
"invalid": [
|
||||
3
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "exclusive_minimum",
|
||||
"schema": {
|
||||
"exclusiveMinimum": 3
|
||||
},
|
||||
"valid": [
|
||||
4
|
||||
],
|
||||
"invalid": [
|
||||
3
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "format_date",
|
||||
"schema": {
|
||||
"format": "date"
|
||||
},
|
||||
"valid": [
|
||||
"1963-06-19"
|
||||
],
|
||||
"invalid": [
|
||||
"06/19/1963"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "format_datetime",
|
||||
"schema": {
|
||||
"format": "date-time"
|
||||
},
|
||||
"valid": [
|
||||
"1963-06-19T08:30:06.283185Z"
|
||||
],
|
||||
"invalid": [
|
||||
"1990-02-31T15:59:60.123-08:00"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "format_email",
|
||||
"schema": {
|
||||
"format": "email"
|
||||
},
|
||||
"valid": [
|
||||
"test@test.com"
|
||||
],
|
||||
"invalid": [
|
||||
"foo"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "format_hostname",
|
||||
"schema": {
|
||||
"format": "hostname"
|
||||
},
|
||||
"valid": [
|
||||
"www.example.com"
|
||||
],
|
||||
"invalid": [
|
||||
"not_a_valid_host_name"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "format_ipv4",
|
||||
"schema": {
|
||||
"format": "ipv4"
|
||||
},
|
||||
"valid": [
|
||||
"127.0.0.1"
|
||||
],
|
||||
"invalid": [
|
||||
"127.0.0.999",
|
||||
"foobar",
|
||||
"2001:0db8:85a3:0000:0000:8a2e:0370:7334"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "format_ipv6",
|
||||
"schema": {
|
||||
"format": "ipv6"
|
||||
},
|
||||
"valid": [
|
||||
"2001:0db8:85a3:0000:0000:8a2e:0370:7334"
|
||||
],
|
||||
"invalid": [
|
||||
"127.0.0.1",
|
||||
"foobar"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "format_iri",
|
||||
"schema": {
|
||||
"format": "iri"
|
||||
},
|
||||
"valid": [
|
||||
"http://\u0192\u00f8\u00f8.\u00df\u00e5r/?\u2202\u00e9\u0153=\u03c0\u00eex#\u03c0\u00ee\u00fcx"
|
||||
],
|
||||
"invalid": [
|
||||
"/abc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "format_iri_reference",
|
||||
"schema": {
|
||||
"format": "iri-reference"
|
||||
},
|
||||
"valid": [
|
||||
"http://\u0192\u00f8\u00f8.\u00df\u00e5r/?\u2202\u00e9\u0153=\u03c0\u00eex#\u03c0\u00ee\u00fcx"
|
||||
],
|
||||
"invalid": [
|
||||
"#\u0192r\u00e4g\\m\u00eant"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "format_json_pointer",
|
||||
"schema": {
|
||||
"format": "json-pointer"
|
||||
},
|
||||
"valid": [
|
||||
"/foo/bar~0/baz~1/%a"
|
||||
],
|
||||
"invalid": [
|
||||
"/foo/bar~"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "format_regex",
|
||||
"schema": {
|
||||
"format": "regex"
|
||||
},
|
||||
"valid": [
|
||||
"([abc])+\\s+$"
|
||||
],
|
||||
"invalid": [
|
||||
"^(abc]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "format_relative_json_pointer",
|
||||
"schema": {
|
||||
"format": "relative-json-pointer"
|
||||
},
|
||||
"valid": [
|
||||
"1"
|
||||
],
|
||||
"invalid": [
|
||||
"/foo/bar"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "format_time",
|
||||
"schema": {
|
||||
"format": "time"
|
||||
},
|
||||
"valid": [
|
||||
"08:30:06.283185Z"
|
||||
],
|
||||
"invalid": [
|
||||
"01:01:01,1111"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "format_uri_reference",
|
||||
"schema": {
|
||||
"format": "uri-reference"
|
||||
},
|
||||
"valid": [
|
||||
"http://foo.bar/?baz=qux#quux"
|
||||
],
|
||||
"invalid": [
|
||||
"#frag\\ment"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "format_uri_template",
|
||||
"schema": {
|
||||
"format": "uri-template"
|
||||
},
|
||||
"valid": [
|
||||
"http://example.com/dictionary/{term:1}/{term}"
|
||||
],
|
||||
"invalid": [
|
||||
"http://example.com/dictionary/{term:1}/{term"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "items",
|
||||
"schema": {
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"valid": [
|
||||
[
|
||||
1,
|
||||
2,
|
||||
3
|
||||
]
|
||||
],
|
||||
"invalid": [
|
||||
[
|
||||
1,
|
||||
2,
|
||||
"x"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "maximum",
|
||||
"schema": {
|
||||
"maximum": 3
|
||||
},
|
||||
"valid": [
|
||||
3
|
||||
],
|
||||
"invalid": [
|
||||
5
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "max_items",
|
||||
"schema": {
|
||||
"maxItems": 1
|
||||
},
|
||||
"valid": [
|
||||
[
|
||||
1
|
||||
]
|
||||
],
|
||||
"invalid": [
|
||||
[
|
||||
1,
|
||||
2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "max_length",
|
||||
"schema": {
|
||||
"maxLength": 3
|
||||
},
|
||||
"valid": [
|
||||
"foo"
|
||||
],
|
||||
"invalid": [
|
||||
"foob"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "max_properties",
|
||||
"schema": {
|
||||
"maxProperties": 1
|
||||
},
|
||||
"valid": [
|
||||
{
|
||||
"a": 1
|
||||
}
|
||||
],
|
||||
"invalid": [
|
||||
{
|
||||
"a": 1,
|
||||
"b": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "minimum",
|
||||
"schema": {
|
||||
"minimum": 3
|
||||
},
|
||||
"valid": [
|
||||
5
|
||||
],
|
||||
"invalid": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "min_items",
|
||||
"schema": {
|
||||
"minItems": 2
|
||||
},
|
||||
"valid": [
|
||||
[
|
||||
1,
|
||||
2
|
||||
]
|
||||
],
|
||||
"invalid": [
|
||||
[
|
||||
1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "min_length",
|
||||
"schema": {
|
||||
"minLength": 3
|
||||
},
|
||||
"valid": [
|
||||
"123"
|
||||
],
|
||||
"invalid": [
|
||||
"12"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "min_properties",
|
||||
"schema": {
|
||||
"minProperties": 2
|
||||
},
|
||||
"valid": [
|
||||
{
|
||||
"a": 1,
|
||||
"b": 2
|
||||
}
|
||||
],
|
||||
"invalid": [
|
||||
{
|
||||
"a": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "multiple_of_integer",
|
||||
"schema": {
|
||||
"multipleOf": 5
|
||||
},
|
||||
"valid": [
|
||||
125
|
||||
],
|
||||
"invalid": [
|
||||
212,
|
||||
212.4
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "multiple_of_number",
|
||||
"schema": {
|
||||
"multipleOf": 2.5
|
||||
},
|
||||
"valid": [
|
||||
127.5
|
||||
],
|
||||
"invalid": [
|
||||
112.2
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "not",
|
||||
"schema": {
|
||||
"not": {
|
||||
"type": "null"
|
||||
}
|
||||
},
|
||||
"valid": [
|
||||
1
|
||||
],
|
||||
"invalid": [
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "one_of",
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"minimum": 2
|
||||
}
|
||||
]
|
||||
},
|
||||
"valid": [
|
||||
1
|
||||
],
|
||||
"invalid": [
|
||||
3
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "pattern",
|
||||
"schema": {
|
||||
"pattern": "A[0-9]{2}Z"
|
||||
},
|
||||
"valid": [
|
||||
"A11Z"
|
||||
],
|
||||
"invalid": [
|
||||
"A119"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "pattern_properties",
|
||||
"schema": {
|
||||
"patternProperties": {
|
||||
"f.*o": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"valid": [
|
||||
{
|
||||
"foo": 1
|
||||
}
|
||||
],
|
||||
"invalid": [
|
||||
{
|
||||
"foo": "bar",
|
||||
"fooooo": 2
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "properties",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"foo": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"valid": [
|
||||
{
|
||||
"foo": "bar"
|
||||
}
|
||||
],
|
||||
"invalid": [
|
||||
{
|
||||
"foo": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "property_names",
|
||||
"schema": {
|
||||
"propertyNames": {
|
||||
"maxLength": 3
|
||||
}
|
||||
},
|
||||
"valid": [
|
||||
{
|
||||
"ABC": 1
|
||||
}
|
||||
],
|
||||
"invalid": [
|
||||
{
|
||||
"ABCD": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ref",
|
||||
"schema": {
|
||||
"items": [
|
||||
{
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"$ref": "#/items/0"
|
||||
}
|
||||
]
|
||||
},
|
||||
"valid": [
|
||||
[
|
||||
1,
|
||||
2
|
||||
]
|
||||
],
|
||||
"invalid": [
|
||||
[
|
||||
1,
|
||||
"b"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "required",
|
||||
"schema": {
|
||||
"required": [
|
||||
"a"
|
||||
]
|
||||
},
|
||||
"valid": [
|
||||
{
|
||||
"a": 1
|
||||
}
|
||||
],
|
||||
"invalid": [
|
||||
{}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "type_integer",
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
},
|
||||
"valid": [
|
||||
1,
|
||||
1.0
|
||||
],
|
||||
"invalid": [
|
||||
1.4,
|
||||
"foo"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "type_string",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"valid": [
|
||||
"foo"
|
||||
],
|
||||
"invalid": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "type_multiple",
|
||||
"schema": {
|
||||
"type": [
|
||||
"integer",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"valid": [
|
||||
"foo"
|
||||
],
|
||||
"invalid": [
|
||||
[]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "unique_items",
|
||||
"schema": {
|
||||
"uniqueItems": true
|
||||
},
|
||||
"valid": [
|
||||
[
|
||||
1,
|
||||
"2",
|
||||
[
|
||||
3
|
||||
],
|
||||
{
|
||||
"4": 4
|
||||
},
|
||||
5,
|
||||
"6",
|
||||
[
|
||||
7
|
||||
],
|
||||
{
|
||||
"8": 8
|
||||
},
|
||||
9,
|
||||
"10",
|
||||
[
|
||||
11
|
||||
],
|
||||
{
|
||||
"12": 12
|
||||
}
|
||||
]
|
||||
],
|
||||
"invalid": [
|
||||
[
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
1
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
|
@ -1,624 +1,140 @@
|
|||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
use bench_helpers::{
|
||||
bench_citm, bench_fast, bench_geojson, bench_keywords, bench_openapi, bench_swagger,
|
||||
};
|
||||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
|
||||
use jsonschema::JSONSchema;
|
||||
use jsonschema_valid::schemas;
|
||||
use serde_json::{from_str, json, Value};
|
||||
use std::{fs::File, io::Read, path::Path};
|
||||
use valico::json_schema;
|
||||
|
||||
fn read_json(filepath: &str) -> Value {
|
||||
let path = Path::new(filepath);
|
||||
let mut file = File::open(&path).unwrap();
|
||||
let mut content = String::new();
|
||||
file.read_to_string(&mut content).ok().unwrap();
|
||||
let data: Value = from_str(&content).unwrap();
|
||||
data
|
||||
}
|
||||
|
||||
fn strip_characters(original: &str) -> String {
|
||||
original
|
||||
.chars()
|
||||
.filter(|&c| !"{}:\" ,[]".contains(c))
|
||||
.collect()
|
||||
}
|
||||
|
||||
macro_rules! bench {
|
||||
(
|
||||
name = $name:tt;
|
||||
schema = $schema:tt;
|
||||
valid = $( $valid:tt ),* $(,)*;
|
||||
invalid = $( $invalid:tt ),* $(,)*;
|
||||
) => {
|
||||
paste::item! {
|
||||
#[allow(dead_code)]
|
||||
fn [<bench_ $name>](c: &mut Criterion) {
|
||||
let schema = json!($schema);
|
||||
let validator = JSONSchema::compile(&schema).unwrap();
|
||||
let suffix = strip_characters(stringify!($schema));
|
||||
c.bench_function(format!("jsonschema-rs {} compile {}", $name, suffix).as_str(), |b| b.iter(|| JSONSchema::compile(&schema).unwrap()));
|
||||
$(
|
||||
let instance = black_box(json!($valid));
|
||||
assert!(validator.is_valid(&instance));
|
||||
let suffix = strip_characters(stringify!($valid));
|
||||
c.bench_function(format!("jsonschema-rs {} is_valid valid {}", $name, suffix).as_str(), |b| b.iter(|| validator.is_valid(&instance)));
|
||||
c.bench_function(format!("jsonschema-rs {} validate valid {}", $name, suffix).as_str(), |b| b.iter(|| validator.validate(&instance).ok()));
|
||||
)*
|
||||
$(
|
||||
let instance = black_box(json!($invalid));
|
||||
assert!(!validator.is_valid(&instance));
|
||||
let suffix = strip_characters(stringify!($invalid));
|
||||
c.bench_function(format!("jsonschema-rs {} is_valid invalid {}", $name, suffix).as_str(), |b| b.iter(|| validator.is_valid(&instance)));
|
||||
c.bench_function(format!("jsonschema-rs {} validate invalid {}", $name, suffix).as_str(), |b| b.iter(|| {
|
||||
let _: Vec<_> = validator.validate(&instance).unwrap_err().collect();
|
||||
}));
|
||||
)*
|
||||
}
|
||||
}
|
||||
};
|
||||
(
|
||||
name = $name:tt;
|
||||
schema = $schema:tt;
|
||||
invalid = $( $invalid:tt ),* $(,)*;
|
||||
) => {
|
||||
paste::item! {
|
||||
fn [<bench_ $name>](c: &mut Criterion) {
|
||||
let schema = json!($schema);
|
||||
let validator = JSONSchema::compile(&schema).unwrap();
|
||||
let suffix = strip_characters(stringify!($schema));
|
||||
c.bench_function(format!("jsonschema-rs {} compile {}", $name, suffix).as_str(), |b| b.iter(|| JSONSchema::compile(&schema).unwrap()));
|
||||
$(
|
||||
let instance = black_box(json!($invalid));
|
||||
assert!(!validator.is_valid(&instance));
|
||||
let suffix = strip_characters(stringify!($invalid));
|
||||
c.bench_function(format!("jsonschema-rs {} is_valid invalid {}", $name, suffix).as_str(), |b| b.iter(|| validator.is_valid(&instance)));
|
||||
c.bench_function(format!("jsonschema-rs {} validate invalid {}", $name, suffix).as_str(), |b| b.iter(|| {
|
||||
let _: Vec<_> = validator.validate(&instance).unwrap_err().collect();
|
||||
}));
|
||||
)*
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
use serde_json::Value;
|
||||
|
||||
macro_rules! jsonschema_rs_bench {
|
||||
($c:tt, $name:expr, $schema:ident, $instance:ident) => {{
|
||||
let validator = JSONSchema::options()
|
||||
let compiled = JSONSchema::options()
|
||||
.with_meta_schemas()
|
||||
.compile(&$schema)
|
||||
.expect("Invalid schema");
|
||||
assert!(validator.is_valid(&$instance), "Invalid instance");
|
||||
assert!(validator.validate(&$instance).is_ok(), "Invalid instance");
|
||||
assert!(compiled.is_valid(&$instance), "Invalid instance");
|
||||
assert!(compiled.validate(&$instance).is_ok(), "Invalid instance");
|
||||
$c.bench_function(&format!("jsonschema-rs {} compile", $name), |b| {
|
||||
b.iter(|| JSONSchema::options().with_meta_schemas().compile(&$schema))
|
||||
});
|
||||
$c.bench_function(&format!("jsonschema-rs {} is_valid", $name), |b| {
|
||||
b.iter(|| validator.is_valid(&$instance))
|
||||
b.iter(|| compiled.is_valid(&$instance))
|
||||
});
|
||||
$c.bench_function(&format!("jsonschema-rs {} validate", $name), |b| {
|
||||
b.iter(|| validator.validate(&$instance).ok())
|
||||
});
|
||||
}};
|
||||
}
|
||||
macro_rules! jsonschema_valid_bench {
|
||||
($c:tt, $name:expr, $schema:ident, $instance:ident, $draft:expr) => {{
|
||||
let cfg =
|
||||
jsonschema_valid::Config::from_schema(&$schema, Some($draft)).expect("Invalid schema");
|
||||
assert!(
|
||||
jsonschema_valid::validate(&cfg, &$instance).is_ok(),
|
||||
"Invalid instance"
|
||||
);
|
||||
$c.bench_function(&format!("jsonschema-valid {}", $name), |b| {
|
||||
// There is no specialized method for fast boolean return value
|
||||
b.iter(|| jsonschema_valid::validate(&cfg, &$instance).is_ok())
|
||||
});
|
||||
}};
|
||||
}
|
||||
macro_rules! valico_bench {
|
||||
($c:tt, $name:expr, $schema:ident, $instance:ident) => {{
|
||||
let mut scope = json_schema::Scope::new();
|
||||
let valico_validator = scope.compile_and_return($schema.clone(), false).unwrap();
|
||||
assert!(
|
||||
valico_validator.validate(&$instance).is_valid(),
|
||||
"Invalid instance"
|
||||
);
|
||||
$c.bench_function(&format!("valico {}", $name), |b| {
|
||||
// There is no specialized method for fast boolean return value
|
||||
b.iter(|| valico_validator.validate(&$instance).is_valid())
|
||||
b.iter(|| compiled.validate(&$instance).ok())
|
||||
});
|
||||
}};
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn large_schemas(c: &mut Criterion) {
|
||||
// Open API JSON Schema
|
||||
// Only `jsonschema` works correctly - other libraries do not recognize `zuora` as valid
|
||||
let openapi = read_json("benches/openapi.json");
|
||||
let zuora = read_json("benches/zuora.json");
|
||||
jsonschema_rs_bench!(c, "openapi", openapi, zuora);
|
||||
|
||||
bench_openapi(&mut |name, schema, instance| jsonschema_rs_bench!(c, name, schema, instance));
|
||||
// Swagger JSON Schema
|
||||
let swagger = read_json("benches/swagger.json");
|
||||
let kubernetes = read_json("benches/kubernetes.json");
|
||||
jsonschema_rs_bench!(c, "swagger", swagger, kubernetes);
|
||||
valico_bench!(c, "swagger", swagger, kubernetes);
|
||||
|
||||
bench_swagger(&mut |name, schema, instance| jsonschema_rs_bench!(c, name, schema, instance));
|
||||
// Canada borders in GeoJSON
|
||||
let geojson = read_json("benches/geojson.json");
|
||||
let canada = read_json("benches/canada.json");
|
||||
jsonschema_rs_bench!(c, "canada", geojson, canada);
|
||||
jsonschema_valid_bench!(c, "canada", geojson, canada, schemas::Draft::Draft7);
|
||||
valico_bench!(c, "canada", geojson, canada);
|
||||
|
||||
bench_geojson(&mut |name, schema, instance| jsonschema_rs_bench!(c, name, schema, instance));
|
||||
// CITM catalog
|
||||
let citm_catalog_schema = read_json("benches/citm_catalog_schema.json");
|
||||
let citm_catalog = read_json("benches/citm_catalog.json");
|
||||
jsonschema_rs_bench!(c, "citm_catalog", citm_catalog_schema, citm_catalog);
|
||||
jsonschema_valid_bench!(
|
||||
c,
|
||||
"citm_catalog",
|
||||
citm_catalog_schema,
|
||||
citm_catalog,
|
||||
schemas::Draft::Draft7
|
||||
);
|
||||
valico_bench!(c, "citm_catalog", citm_catalog_schema, citm_catalog);
|
||||
bench_citm(&mut |name, schema, instance| jsonschema_rs_bench!(c, name, schema, instance));
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn fast_schema(c: &mut Criterion) {
|
||||
let schema = read_json("benches/fast_schema.json");
|
||||
let valid =
|
||||
black_box(json!([9, "hello", [1, "a", true], {"a": "a", "b": "b", "d": "d"}, 42, 3]));
|
||||
let invalid =
|
||||
black_box(json!([10, "world", [1, "a", true], {"a": "a", "b": "b", "c": "xy"}, "str", 5]));
|
||||
|
||||
// jsonschema
|
||||
let validator = JSONSchema::compile(&schema).unwrap();
|
||||
assert!(validator.is_valid(&valid));
|
||||
assert!(!validator.is_valid(&invalid));
|
||||
c.bench_function("compare jsonschema-rs small schema compile", |b| {
|
||||
b.iter(|| JSONSchema::compile(&schema).unwrap())
|
||||
});
|
||||
c.bench_function("compare jsonschema-rs small schema is_valid valid", |b| {
|
||||
b.iter(|| validator.is_valid(&valid))
|
||||
});
|
||||
c.bench_function("compare jsonschema-rs small schema validate valid", |b| {
|
||||
b.iter(|| validator.validate(&valid).ok())
|
||||
});
|
||||
c.bench_function("compare jsonschema-rs small schema is_valid invalid", |b| {
|
||||
b.iter(|| validator.is_valid(&invalid))
|
||||
});
|
||||
c.bench_function("compare jsonschema-rs small schema validate invalid", |b| {
|
||||
b.iter(|| {
|
||||
let _: Vec<_> = validator.validate(&invalid).unwrap_err().collect();
|
||||
})
|
||||
});
|
||||
|
||||
// jsonschema_valid
|
||||
let cfg = jsonschema_valid::Config::from_schema(&schema, Some(schemas::Draft::Draft7)).unwrap();
|
||||
c.bench_function("compare jsonschema_valid small schema compile", |b| {
|
||||
b.iter(|| {
|
||||
jsonschema_valid::Config::from_schema(&schema, Some(schemas::Draft::Draft7)).unwrap()
|
||||
})
|
||||
});
|
||||
c.bench_function(
|
||||
"compare jsonschema_valid small schema validate valid",
|
||||
|b| b.iter(|| jsonschema_valid::validate(&cfg, &valid)),
|
||||
);
|
||||
c.bench_function(
|
||||
"compare jsonschema_valid small schema validate invalid",
|
||||
|b| b.iter(|| jsonschema_valid::validate(&cfg, &invalid).ok()),
|
||||
);
|
||||
|
||||
// valico
|
||||
let mut scope = json_schema::Scope::new();
|
||||
let compiled = scope.compile_and_return(schema.clone(), false).unwrap();
|
||||
c.bench_function("compare valico small schema compile", |b| {
|
||||
b.iter(|| {
|
||||
let mut scope = json_schema::Scope::new();
|
||||
scope.compile_and_return(schema.clone(), false).unwrap();
|
||||
})
|
||||
});
|
||||
c.bench_function("compare valico small schema validate valid", |b| {
|
||||
b.iter(|| compiled.validate(&valid).is_valid())
|
||||
});
|
||||
c.bench_function("compare valico small schema validate invalid", |b| {
|
||||
b.iter(|| compiled.validate(&invalid).is_valid())
|
||||
bench_fast(&mut |name, schema, valid, invalid| {
|
||||
let compiled = JSONSchema::compile(&schema).expect("Valid schema");
|
||||
assert!(compiled.is_valid(&valid));
|
||||
assert!(!compiled.is_valid(&invalid));
|
||||
c.bench_function(&format!("jsonschema-rs {} compile", name), |b| {
|
||||
b.iter(|| JSONSchema::compile(&schema).expect("Valid schema"))
|
||||
});
|
||||
c.bench_function(&format!("jsonschema-rs {} is_valid valid", name), |b| {
|
||||
b.iter(|| compiled.is_valid(&valid))
|
||||
});
|
||||
c.bench_function(&format!("jsonschema-rs {} validate valid", name), |b| {
|
||||
b.iter(|| compiled.validate(&valid).ok())
|
||||
});
|
||||
c.bench_function(&format!("jsonschema-rs {} is_valid invalid", name), |b| {
|
||||
b.iter(|| compiled.is_valid(&invalid))
|
||||
});
|
||||
c.bench_function(&format!("jsonschema-rs {} validate invalid", name), |b| {
|
||||
b.iter(|| {
|
||||
let _: Vec<_> = compiled
|
||||
.validate(&invalid)
|
||||
.expect_err("There should be errors")
|
||||
.collect();
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
bench!(
|
||||
name = "additional_items_boolean";
|
||||
schema = {"items": [{}, {}, {}], "additionalItems": false};
|
||||
valid = [1, 2, 3];
|
||||
invalid = [1, 2, 3, 4];
|
||||
);
|
||||
bench!(
|
||||
name = "additional_items_object";
|
||||
schema = {"items": [{}, {}, {}], "additionalItems": {"type": "string"}};
|
||||
valid = [1, 2, 3, "foo"];
|
||||
invalid = [1, 2, 3, 4];
|
||||
);
|
||||
bench!(
|
||||
name = "additional_properties_single";
|
||||
schema = {"additionalProperties": {"type": "string"}};
|
||||
valid = {"foo": "bar"};
|
||||
invalid = {"foo": 1};
|
||||
);
|
||||
bench!(
|
||||
name = "additional_properties_and_properties";
|
||||
schema = {"additionalProperties": {"type": "string"}, "properties": {"foo": {}}};
|
||||
valid = {"foo": 1};
|
||||
invalid = {"foo": 1, "bar": true};
|
||||
);
|
||||
bench!(
|
||||
name = "additional_properties_and_pattern_properties";
|
||||
schema = {"additionalProperties": {"type": "string"}, "patternProperties": {"f.*o": {"type": "integer"}}};
|
||||
valid = {"foo": 1};
|
||||
invalid = {"foo": 1, "bar": true};
|
||||
);
|
||||
bench!(
|
||||
name = "additional_properties_and_properties_and_pattern_properties";
|
||||
schema = {"additionalProperties": {"type": "string"}, "properties": {"foo": {}}, "patternProperties": {"f.*a": {"type": "integer"}}};
|
||||
valid = {"foo": null, "fza": 2};
|
||||
invalid = {"foo": null, "fzo": 2, "bar": true};
|
||||
);
|
||||
bench!(
|
||||
name = "additional_properties_false";
|
||||
schema = {"additionalProperties": false};
|
||||
valid = {};
|
||||
invalid = {"foo": 1};
|
||||
);
|
||||
bench!(
|
||||
name = "additional_properties_false_and_properties";
|
||||
schema = {"additionalProperties": false, "properties": {"foo": {}}};
|
||||
valid = {"foo": 1};
|
||||
invalid = {"foo": 1, "bar": 2};
|
||||
);
|
||||
bench!(
|
||||
name = "additional_properties_false_and_pattern_properties";
|
||||
schema = {"additionalProperties": false, "patternProperties": {"f.*o": {"type": "integer"}}};
|
||||
valid = {"foo": 1};
|
||||
invalid = {"foo": 1, "bar": 2};
|
||||
);
|
||||
bench!(
|
||||
name = "additional_properties_false_and_properties_and_pattern_properties";
|
||||
schema = {"additionalProperties": false, "properties": {"foo": {}}, "patternProperties": {"f.*o": {"type": "integer"}}};
|
||||
valid = {"foo": 1};
|
||||
invalid = {"foo": 1, "fz0": 2, "bar": 2};
|
||||
);
|
||||
bench!(
|
||||
name = "all_of";
|
||||
schema = {"allOf": [{"type": "integer"}, {"minimum": 2}]};
|
||||
valid = 4;
|
||||
invalid = 1;
|
||||
);
|
||||
bench!(
|
||||
name = "any_of";
|
||||
schema = {"anyOf": [{"type": "integer"}, {"minimum": 2}]};
|
||||
valid = 1;
|
||||
invalid = 1.5;
|
||||
);
|
||||
bench!(
|
||||
name = "any_of_multiple_types";
|
||||
schema = {"anyOf": [{"type": "integer"}, {"type": "string"}]};
|
||||
valid = "foo";
|
||||
invalid = null;
|
||||
);
|
||||
bench!(
|
||||
name = "boolean_false";
|
||||
schema = false;
|
||||
invalid = 1;
|
||||
);
|
||||
bench!(
|
||||
name = "const";
|
||||
schema = {"const": 1};
|
||||
valid = 1;
|
||||
invalid = "foo";
|
||||
);
|
||||
bench!(
|
||||
name = "contains";
|
||||
schema = {"contains": {"minimum": 5}};
|
||||
valid = [5];
|
||||
invalid = [1];
|
||||
);
|
||||
bench!(
|
||||
name = "enum";
|
||||
schema = {"enum": [1, 2, 3, 4]};
|
||||
valid = 4;
|
||||
invalid = 5, "6";
|
||||
);
|
||||
bench!(
|
||||
name = "exclusive_maximum";
|
||||
schema = {"exclusiveMaximum": 3};
|
||||
valid = 2;
|
||||
invalid = 3;
|
||||
);
|
||||
bench!(
|
||||
name = "exclusive_minimum";
|
||||
schema = {"exclusiveMinimum": 3};
|
||||
valid = 4;
|
||||
invalid = 3;
|
||||
);
|
||||
bench!(
|
||||
name = "format_date";
|
||||
schema = {"format": "date"};
|
||||
valid = "1963-06-19";
|
||||
invalid = "06/19/1963";
|
||||
);
|
||||
bench!(
|
||||
name = "format_datetime";
|
||||
schema = {"format": "date-time"};
|
||||
valid = "1963-06-19T08:30:06.283185Z";
|
||||
invalid = "1990-02-31T15:59:60.123-08:00";
|
||||
);
|
||||
bench!(
|
||||
name = "format_email";
|
||||
schema = {"format": "email"};
|
||||
valid = "test@test.com";
|
||||
invalid = "foo";
|
||||
);
|
||||
bench!(
|
||||
name = "format_hostname";
|
||||
schema = {"format": "hostname"};
|
||||
valid = "www.example.com";
|
||||
invalid = "not_a_valid_host_name";
|
||||
);
|
||||
bench!(
|
||||
name = "format_ipv4";
|
||||
schema = {"format": "ipv4"};
|
||||
valid = "127.0.0.1";
|
||||
invalid = "127.0.0.999", "foobar", "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
|
||||
);
|
||||
bench!(
|
||||
name = "format_ipv6";
|
||||
schema = {"format": "ipv6"};
|
||||
valid = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
|
||||
invalid = "127.0.0.1", "foobar";
|
||||
);
|
||||
bench!(
|
||||
name = "format_iri";
|
||||
schema = {"format": "iri"};
|
||||
valid = "http://ƒøø.ßår/?∂éœ=πîx#πîüx";
|
||||
invalid = "/abc";
|
||||
);
|
||||
bench!(
|
||||
name = "format_iri_reference";
|
||||
schema = {"format": "iri-reference"};
|
||||
valid = "http://ƒøø.ßår/?∂éœ=πîx#πîüx";
|
||||
invalid = "#ƒräg\\mênt";
|
||||
);
|
||||
bench!(
|
||||
name = "format_json_pointer";
|
||||
schema = {"format": "json-pointer"};
|
||||
valid = "/foo/bar~0/baz~1/%a";
|
||||
invalid = "/foo/bar~";
|
||||
);
|
||||
bench!(
|
||||
name = "format_regex";
|
||||
schema = {"format": "regex"};
|
||||
valid = r#"([abc])+\s+$"#;
|
||||
invalid = "^(abc]";
|
||||
);
|
||||
bench!(
|
||||
name = "format_relative_json_pointer";
|
||||
schema = {"format": "relative-json-pointer"};
|
||||
valid = "1";
|
||||
invalid = "/foo/bar";
|
||||
);
|
||||
bench!(
|
||||
name = "format_time";
|
||||
schema = {"format": "time"};
|
||||
valid = "08:30:06.283185Z";
|
||||
invalid = "01:01:01,1111";
|
||||
);
|
||||
bench!(
|
||||
name = "format_uri_reference";
|
||||
schema = {"format": "uri-reference"};
|
||||
valid = "http://foo.bar/?baz=qux#quux";
|
||||
invalid = "#frag\\ment";
|
||||
);
|
||||
bench!(
|
||||
name = "format_uri_template";
|
||||
schema = {"format": "uri-template"};
|
||||
valid = "http://example.com/dictionary/{term:1}/{term}";
|
||||
invalid = "http://example.com/dictionary/{term:1}/{term";
|
||||
);
|
||||
bench!(
|
||||
name = "items";
|
||||
schema = {"items": {"type": "integer"}};
|
||||
valid = [1, 2, 3];
|
||||
invalid = [1, 2, "x"];
|
||||
);
|
||||
bench!(
|
||||
name = "maximum";
|
||||
schema = {"maximum": 3};
|
||||
valid = 3;
|
||||
invalid = 5;
|
||||
);
|
||||
bench!(
|
||||
name = "max_items";
|
||||
schema = {"maxItems": 1};
|
||||
valid = [1];
|
||||
invalid = [1, 2];
|
||||
);
|
||||
bench!(
|
||||
name = "max_length";
|
||||
schema = {"maxLength": 3};
|
||||
valid = "foo";
|
||||
invalid = "foob";
|
||||
);
|
||||
bench!(
|
||||
name = "max_properties";
|
||||
schema = {"maxProperties": 1};
|
||||
valid = {"a": 1};
|
||||
invalid = {"a": 1, "b": 1};
|
||||
);
|
||||
bench!(
|
||||
name = "minimum";
|
||||
schema = {"minimum": 3};
|
||||
valid = 5;
|
||||
invalid = 1;
|
||||
);
|
||||
bench!(
|
||||
name = "min_items";
|
||||
schema = {"minItems": 2};
|
||||
valid = [1, 2];
|
||||
invalid = [1];
|
||||
);
|
||||
bench!(
|
||||
name = "min_length";
|
||||
schema = {"minLength": 3};
|
||||
valid = "123";
|
||||
invalid = "12";
|
||||
);
|
||||
bench!(
|
||||
name = "min_properties";
|
||||
schema = {"minProperties": 2};
|
||||
valid = {"a": 1, "b": 2};
|
||||
invalid = {"a": 1};
|
||||
);
|
||||
bench!(
|
||||
name = "multiple_of_integer";
|
||||
schema = {"multipleOf": 5};
|
||||
valid = 125;
|
||||
invalid = 212, 212.4;
|
||||
);
|
||||
bench!(
|
||||
name = "multiple_of_number";
|
||||
schema = {"multipleOf": 2.5};
|
||||
valid = 127.5;
|
||||
invalid = 112.2;
|
||||
);
|
||||
bench!(
|
||||
name = "not";
|
||||
schema = {"not": {"type": "null"}};
|
||||
valid = 1;
|
||||
invalid = null;
|
||||
);
|
||||
bench!(
|
||||
name = "one_of";
|
||||
schema = {"oneOf": [{"type": "integer"}, {"minimum": 2}]};
|
||||
valid = 1;
|
||||
invalid = 3;
|
||||
);
|
||||
bench!(
|
||||
name = "pattern";
|
||||
schema = {"pattern": "A[0-9]{2}Z"};
|
||||
valid = "A11Z";
|
||||
invalid = "A119";
|
||||
);
|
||||
bench!(
|
||||
name = "pattern_properties";
|
||||
schema = {"patternProperties": {"f.*o": {"type": "integer"}}};
|
||||
valid = {"foo": 1};
|
||||
invalid = {"foo": "bar", "fooooo": 2};
|
||||
);
|
||||
bench!(
|
||||
name = "properties";
|
||||
schema = {"properties": {"foo": {"type": "string"}}};
|
||||
valid = {"foo": "bar"};
|
||||
invalid = {"foo": 1};
|
||||
);
|
||||
bench!(
|
||||
name = "property_names";
|
||||
schema = {"propertyNames": {"maxLength": 3}};
|
||||
valid = {"ABC": 1};
|
||||
invalid = {"ABCD": 1};
|
||||
);
|
||||
bench!(
|
||||
name = "ref";
|
||||
schema = {"items": [{"type": "integer"},{"$ref": "#/items/0"}]};
|
||||
valid = [1, 2];
|
||||
invalid = [1, "b"];
|
||||
);
|
||||
bench!(
|
||||
name = "required";
|
||||
schema = {"required": ["a"]};
|
||||
valid = {"a": 1};
|
||||
invalid = {};
|
||||
);
|
||||
bench!(
|
||||
name = "type_integer";
|
||||
schema = {"type": "integer"};
|
||||
valid = 1, 1.0;
|
||||
invalid = 1.4, "foo";
|
||||
);
|
||||
bench!(
|
||||
name = "type_string";
|
||||
schema = {"type": "string"};
|
||||
valid = "foo";
|
||||
invalid = 1;
|
||||
);
|
||||
bench!(
|
||||
name = "type_multiple";
|
||||
schema = {"type": ["integer", "string"]};
|
||||
valid = "foo";
|
||||
invalid = [];
|
||||
);
|
||||
bench!(
|
||||
name = "unique_items";
|
||||
schema = {"uniqueItems": true};
|
||||
valid = [1, "2", [3], {"4": 4}, 5, "6", [7], {"8": 8}, 9, "10", [11], {"12": 12}];
|
||||
invalid = [1, 2, 3, 4, 5, 1];
|
||||
);
|
||||
fn keywords(c: &mut Criterion) {
|
||||
bench_keywords(
|
||||
c,
|
||||
&|_: &str| false,
|
||||
&|schema: &Value, instance: &Value| {
|
||||
let compiled = JSONSchema::compile(schema).expect("Valid schema");
|
||||
compiled.is_valid(instance)
|
||||
},
|
||||
&mut |c: &mut Criterion, name: &str, schema: &Value| {
|
||||
c.bench_with_input(
|
||||
BenchmarkId::new(name, "jsonschema_rs/compile"),
|
||||
schema,
|
||||
|b, schema| {
|
||||
b.iter(|| {
|
||||
JSONSchema::compile(schema).expect("Valid schema");
|
||||
})
|
||||
},
|
||||
);
|
||||
},
|
||||
validate_valid,
|
||||
validate_invalid,
|
||||
)
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
keywords,
|
||||
bench_additional_items_boolean,
|
||||
bench_additional_items_object,
|
||||
bench_additional_properties_single,
|
||||
bench_additional_properties_and_properties,
|
||||
bench_additional_properties_and_pattern_properties,
|
||||
bench_additional_properties_and_properties_and_pattern_properties,
|
||||
bench_additional_properties_false,
|
||||
bench_additional_properties_false_and_properties,
|
||||
bench_additional_properties_false_and_pattern_properties,
|
||||
bench_additional_properties_false_and_properties_and_pattern_properties,
|
||||
bench_all_of,
|
||||
bench_any_of,
|
||||
bench_any_of_multiple_types,
|
||||
bench_boolean_false,
|
||||
bench_const,
|
||||
bench_contains,
|
||||
bench_enum,
|
||||
bench_exclusive_maximum,
|
||||
bench_exclusive_minimum,
|
||||
bench_format_date,
|
||||
bench_format_datetime,
|
||||
bench_format_email,
|
||||
bench_format_hostname,
|
||||
bench_format_ipv4,
|
||||
bench_format_ipv6,
|
||||
bench_format_iri,
|
||||
bench_format_iri_reference,
|
||||
bench_format_json_pointer,
|
||||
bench_format_regex,
|
||||
bench_format_relative_json_pointer,
|
||||
bench_format_time,
|
||||
bench_format_uri_reference,
|
||||
bench_format_uri_template,
|
||||
bench_items,
|
||||
bench_maximum,
|
||||
bench_max_items,
|
||||
bench_max_length,
|
||||
bench_max_properties,
|
||||
bench_minimum,
|
||||
bench_min_items,
|
||||
bench_min_length,
|
||||
bench_min_properties,
|
||||
bench_multiple_of_integer,
|
||||
bench_multiple_of_number,
|
||||
bench_not,
|
||||
bench_one_of,
|
||||
bench_pattern,
|
||||
bench_pattern_properties,
|
||||
bench_properties,
|
||||
bench_property_names,
|
||||
bench_ref,
|
||||
bench_required,
|
||||
bench_type_integer,
|
||||
bench_type_string,
|
||||
bench_type_multiple,
|
||||
bench_unique_items,
|
||||
);
|
||||
criterion_group!(arbitrary, large_schemas, fast_schema);
|
||||
criterion_main!(arbitrary, keywords);
|
||||
fn validate_valid(c: &mut Criterion, name: &str, schema: &Value, instance: &Value) {
|
||||
let compiled = JSONSchema::compile(&schema).expect("Valid schema");
|
||||
c.bench_with_input(
|
||||
BenchmarkId::new(name, "jsonschema_rs/is_valid"),
|
||||
instance,
|
||||
|b, instance| {
|
||||
b.iter(|| {
|
||||
let _ = compiled.is_valid(instance);
|
||||
})
|
||||
},
|
||||
);
|
||||
c.bench_with_input(
|
||||
BenchmarkId::new(name, "jsonschema_rs/validate"),
|
||||
instance,
|
||||
|b, instance| {
|
||||
b.iter(|| {
|
||||
compiled.validate(instance).ok();
|
||||
})
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn validate_invalid(c: &mut Criterion, name: &str, schema: &Value, instance: &Value) {
|
||||
let compiled = JSONSchema::compile(&schema).expect("Valid schema");
|
||||
c.bench_with_input(
|
||||
BenchmarkId::new(name, "jsonschema_rs/is_valid"),
|
||||
instance,
|
||||
|b, instance| {
|
||||
b.iter(|| {
|
||||
let _ = compiled.is_valid(instance);
|
||||
})
|
||||
},
|
||||
);
|
||||
c.bench_with_input(
|
||||
BenchmarkId::new(name, "jsonschema_rs/validate"),
|
||||
instance,
|
||||
|b, instance| {
|
||||
b.iter(|| {
|
||||
let _: Vec<_> = compiled
|
||||
.validate(&instance)
|
||||
.expect_err("There should be errors")
|
||||
.collect();
|
||||
})
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
criterion_group!(arbitrary, large_schemas, fast_schema, keywords);
|
||||
criterion_main!(arbitrary);
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
use bench_helpers::{bench_citm, bench_fast, bench_geojson, bench_keywords};
|
||||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
|
||||
use jsonschema_valid::schemas;
|
||||
use serde_json::Value;
|
||||
|
||||
macro_rules! jsonschema_valid_bench {
|
||||
($c:tt, $name:expr, $schema:ident, $instance:ident, $draft:expr) => {{
|
||||
let cfg =
|
||||
jsonschema_valid::Config::from_schema(&$schema, Some($draft)).expect("Invalid schema");
|
||||
assert!(
|
||||
jsonschema_valid::validate(&cfg, &$instance).is_ok(),
|
||||
"Invalid instance"
|
||||
);
|
||||
$c.bench_function(&format!("jsonschema-valid {}", $name), |b| {
|
||||
// There is no specialized method for fast boolean return value
|
||||
b.iter(|| jsonschema_valid::validate(&cfg, &$instance).is_ok())
|
||||
});
|
||||
}};
|
||||
}
|
||||
|
||||
fn large_schemas(c: &mut Criterion) {
|
||||
// Canada borders in GeoJSON
|
||||
bench_geojson(&mut |name, schema, instance| {
|
||||
jsonschema_valid_bench!(c, name, schema, instance, schemas::Draft::Draft7)
|
||||
});
|
||||
// CITM catalog
|
||||
bench_citm(&mut |name, schema, instance| {
|
||||
jsonschema_valid_bench!(c, name, schema, instance, schemas::Draft::Draft7)
|
||||
});
|
||||
}
|
||||
|
||||
fn fast_schema(c: &mut Criterion) {
|
||||
bench_fast(&mut |name, schema, valid, invalid| {
|
||||
let cfg = jsonschema_valid::Config::from_schema(&schema, Some(schemas::Draft::Draft7))
|
||||
.expect("Valid schema");
|
||||
c.bench_function(&format!("jsonschema_valid {} compile", name), |b| {
|
||||
b.iter(|| {
|
||||
jsonschema_valid::Config::from_schema(&schema, Some(schemas::Draft::Draft7))
|
||||
.expect("Valid schema")
|
||||
})
|
||||
});
|
||||
c.bench_function(&format!("jsonschema_valid {} validate valid", name), |b| {
|
||||
b.iter(|| jsonschema_valid::validate(&cfg, &valid))
|
||||
});
|
||||
c.bench_function(
|
||||
&format!("jsonschema_valid {} validate invalid", name),
|
||||
|b| b.iter(|| jsonschema_valid::validate(&cfg, &invalid).ok()),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
fn keywords(c: &mut Criterion) {
|
||||
bench_keywords(
|
||||
c,
|
||||
&|name: &str| {
|
||||
// Bug in `jsonschema_valid`
|
||||
// `Option::unwrap()` on a `None` value'
|
||||
// https://github.com/mdboom/jsonschema-valid/blob/de1da64fb624085eccde290e036a2ed592656f38/src/validators.rs#L531
|
||||
name == "multiple_of_integer"
|
||||
},
|
||||
&|schema: &Value, instance: &Value| {
|
||||
let compiled =
|
||||
jsonschema_valid::Config::from_schema(schema, Some(schemas::Draft::Draft7))
|
||||
.expect("Valid schema");
|
||||
let result = jsonschema_valid::validate(&compiled, instance).is_ok();
|
||||
result
|
||||
},
|
||||
&mut |c: &mut Criterion, name: &str, schema: &Value| {
|
||||
c.bench_with_input(
|
||||
BenchmarkId::new(name, "jsonschema_valid/compile"),
|
||||
schema,
|
||||
|b, schema| {
|
||||
b.iter(|| {
|
||||
jsonschema_valid::Config::from_schema(&schema, Some(schemas::Draft::Draft7))
|
||||
.expect("Valid schema")
|
||||
})
|
||||
},
|
||||
);
|
||||
},
|
||||
validate,
|
||||
validate,
|
||||
)
|
||||
}
|
||||
|
||||
fn validate(c: &mut Criterion, name: &str, schema: &Value, instance: &Value) {
|
||||
let compiled = jsonschema_valid::Config::from_schema(&schema, Some(schemas::Draft::Draft7))
|
||||
.expect("Valid schema");
|
||||
c.bench_with_input(
|
||||
BenchmarkId::new(name, "jsonschema_valid"),
|
||||
&(compiled, instance),
|
||||
|b, (compiled, instance)| {
|
||||
b.iter(|| {
|
||||
let _ = jsonschema_valid::validate(compiled, instance);
|
||||
})
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
criterion_group!(jsonschema_valid, large_schemas, fast_schema, keywords);
|
||||
criterion_main!(jsonschema_valid);
|
|
@ -0,0 +1,98 @@
|
|||
use bench_helpers::{bench_citm, bench_fast, bench_geojson, bench_keywords, bench_swagger};
|
||||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
|
||||
use serde_json::Value;
|
||||
use valico::json_schema;
|
||||
|
||||
macro_rules! valico_bench {
|
||||
($c:tt, $name:expr, $schema:ident, $instance:ident) => {{
|
||||
let mut scope = json_schema::Scope::new();
|
||||
let compiled = scope
|
||||
.compile_and_return($schema.clone(), false)
|
||||
.expect("Valid schema");
|
||||
assert!(compiled.validate(&$instance).is_valid(), "Invalid instance");
|
||||
$c.bench_function(&format!("valico {}", $name), |b| {
|
||||
// There is no specialized method for fast boolean return value
|
||||
b.iter(|| compiled.validate(&$instance).is_valid())
|
||||
});
|
||||
}};
|
||||
}
|
||||
|
||||
fn large_schemas(c: &mut Criterion) {
|
||||
// Swagger JSON Schema
|
||||
bench_swagger(&mut |name, schema, instance| valico_bench!(c, name, schema, instance));
|
||||
// Canada borders in GeoJSON
|
||||
bench_geojson(&mut |name, schema, instance| valico_bench!(c, name, schema, instance));
|
||||
// CITM catalog
|
||||
bench_citm(&mut |name, schema, instance| valico_bench!(c, name, schema, instance));
|
||||
}
|
||||
|
||||
fn fast_schema(c: &mut Criterion) {
|
||||
bench_fast(&mut |name, schema, valid, invalid| {
|
||||
let mut scope = json_schema::Scope::new();
|
||||
let compiled = scope
|
||||
.compile_and_return(schema.clone(), false)
|
||||
.expect("Valid schema");
|
||||
c.bench_function(&format!("valico {} compile", name), |b| {
|
||||
b.iter(|| {
|
||||
let mut scope = json_schema::Scope::new();
|
||||
scope
|
||||
.compile_and_return(schema.clone(), false)
|
||||
.expect("Valid schema");
|
||||
})
|
||||
});
|
||||
c.bench_function(&format!("valico {} validate valid", name), |b| {
|
||||
b.iter(|| compiled.validate(&valid).is_valid())
|
||||
});
|
||||
c.bench_function(&format!("valico {} validate invalid", name), |b| {
|
||||
b.iter(|| compiled.validate(&invalid).is_valid())
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn keywords(c: &mut Criterion) {
|
||||
bench_keywords(
|
||||
c,
|
||||
&|_: &str| false,
|
||||
&|schema: &Value, instance: &Value| {
|
||||
let mut scope = json_schema::Scope::new();
|
||||
let compiled = scope
|
||||
.compile_and_return(schema.clone(), false)
|
||||
.expect("Valid schema");
|
||||
compiled.validate(instance).is_valid()
|
||||
},
|
||||
&mut |c: &mut Criterion, name: &str, schema: &Value| {
|
||||
c.bench_with_input(
|
||||
BenchmarkId::new(name, "valico/compile"),
|
||||
schema,
|
||||
|b, schema| {
|
||||
b.iter_with_setup(
|
||||
|| schema.clone(),
|
||||
|schema| {
|
||||
let mut scope = json_schema::Scope::new();
|
||||
scope
|
||||
.compile_and_return(schema, false)
|
||||
.expect("Valid schema");
|
||||
},
|
||||
)
|
||||
},
|
||||
);
|
||||
},
|
||||
validate,
|
||||
validate,
|
||||
)
|
||||
}
|
||||
|
||||
fn validate(c: &mut Criterion, name: &str, schema: &Value, instance: &Value) {
|
||||
let mut scope = json_schema::Scope::new();
|
||||
let compiled = scope
|
||||
.compile_and_return(schema.clone(), false)
|
||||
.expect("Valid schema");
|
||||
c.bench_with_input(BenchmarkId::new(name, "valico"), instance, |b, instance| {
|
||||
b.iter(|| {
|
||||
compiled.validate(instance).is_valid();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(valico, large_schemas, fast_schema, keywords);
|
||||
criterion_main!(valico);
|
Loading…
Reference in New Issue