mirror of
https://github.com/gosticks/wordpress-develop.git
synced 2026-08-12 04:40:26 +00:00
REST API: Add support for the oneOf and anyOf keywords.
This allows for REST API routes to define more complex validation requirements as JSON Schema instead of procedural validation. The error code returned from `rest_validate_value_from_schema` for invalid parameter types has been changed from the generic `rest_invalid_param` to the more specific `rest_invalid_type`. Props yakimun, johnbillion, TimothyBlynJacobs. Fixes #51025. git-svn-id: https://develop.svn.wordpress.org/trunk@49246 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
@@ -1085,7 +1085,7 @@ class Tests_REST_API extends WP_UnitTestCase {
|
||||
|
||||
public function _dp_rest_filter_response_by_context() {
|
||||
return array(
|
||||
'default' => array(
|
||||
'default' => array(
|
||||
array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'type' => 'object',
|
||||
@@ -1106,7 +1106,7 @@ class Tests_REST_API extends WP_UnitTestCase {
|
||||
),
|
||||
array( 'first' => 'a' ),
|
||||
),
|
||||
'keeps missing context' => array(
|
||||
'keeps missing context' => array(
|
||||
array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'type' => 'object',
|
||||
@@ -1129,7 +1129,7 @@ class Tests_REST_API extends WP_UnitTestCase {
|
||||
'second' => 'b',
|
||||
),
|
||||
),
|
||||
'removes empty context' => array(
|
||||
'removes empty context' => array(
|
||||
array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'type' => 'object',
|
||||
@@ -1150,7 +1150,7 @@ class Tests_REST_API extends WP_UnitTestCase {
|
||||
),
|
||||
array( 'first' => 'a' ),
|
||||
),
|
||||
'nested properties' => array(
|
||||
'nested properties' => array(
|
||||
array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'type' => 'object',
|
||||
@@ -1179,7 +1179,7 @@ class Tests_REST_API extends WP_UnitTestCase {
|
||||
),
|
||||
array( 'parent' => array( 'child' => 'hi' ) ),
|
||||
),
|
||||
'grand child properties' => array(
|
||||
'grand child properties' => array(
|
||||
array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'type' => 'object',
|
||||
@@ -1215,7 +1215,7 @@ class Tests_REST_API extends WP_UnitTestCase {
|
||||
),
|
||||
array( 'parent' => array( 'child' => array( 'grand' => 'hi' ) ) ),
|
||||
),
|
||||
'array' => array(
|
||||
'array' => array(
|
||||
array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'type' => 'object',
|
||||
@@ -1250,7 +1250,7 @@ class Tests_REST_API extends WP_UnitTestCase {
|
||||
),
|
||||
array( 'arr' => array( array( 'visible' => 'hi' ) ) ),
|
||||
),
|
||||
'additional properties' => array(
|
||||
'additional properties' => array(
|
||||
array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'type' => 'object',
|
||||
@@ -1284,7 +1284,7 @@ class Tests_REST_API extends WP_UnitTestCase {
|
||||
),
|
||||
array( 'additional' => array( 'a' => '1' ) ),
|
||||
),
|
||||
'pattern properties' => array(
|
||||
'pattern properties' => array(
|
||||
array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'type' => 'object',
|
||||
@@ -1320,7 +1320,7 @@ class Tests_REST_API extends WP_UnitTestCase {
|
||||
'0' => '3',
|
||||
),
|
||||
),
|
||||
'multiple types object' => array(
|
||||
'multiple types object' => array(
|
||||
array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'type' => 'object',
|
||||
@@ -1349,7 +1349,7 @@ class Tests_REST_API extends WP_UnitTestCase {
|
||||
),
|
||||
array( 'multi' => array( 'a' => '1' ) ),
|
||||
),
|
||||
'multiple types array' => array(
|
||||
'multiple types array' => array(
|
||||
array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'type' => 'object',
|
||||
@@ -1384,7 +1384,7 @@ class Tests_REST_API extends WP_UnitTestCase {
|
||||
),
|
||||
array( 'multi' => array( array( 'visible' => '1' ) ) ),
|
||||
),
|
||||
'does not traverse missing context' => array(
|
||||
'does not traverse missing context' => array(
|
||||
array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'type' => 'object',
|
||||
@@ -1427,7 +1427,7 @@ class Tests_REST_API extends WP_UnitTestCase {
|
||||
),
|
||||
),
|
||||
),
|
||||
'object with no matching properties' => array(
|
||||
'object with no matching properties' => array(
|
||||
array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'type' => 'object',
|
||||
@@ -1448,7 +1448,7 @@ class Tests_REST_API extends WP_UnitTestCase {
|
||||
),
|
||||
array(),
|
||||
),
|
||||
'array whose type does not match' => array(
|
||||
'array whose type does not match' => array(
|
||||
array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'type' => 'object',
|
||||
@@ -1468,7 +1468,7 @@ class Tests_REST_API extends WP_UnitTestCase {
|
||||
),
|
||||
array( 'arr' => array() ),
|
||||
),
|
||||
'array and object type passed object' => array(
|
||||
'array and object type passed object' => array(
|
||||
array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'type' => array( 'array', 'object' ),
|
||||
@@ -1506,7 +1506,7 @@ class Tests_REST_API extends WP_UnitTestCase {
|
||||
'b' => 'bar',
|
||||
),
|
||||
),
|
||||
'array and object type passed array' => array(
|
||||
'array and object type passed array' => array(
|
||||
array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'type' => array( 'array', 'object' ),
|
||||
@@ -1547,6 +1547,210 @@ class Tests_REST_API extends WP_UnitTestCase {
|
||||
),
|
||||
array(),
|
||||
),
|
||||
'anyOf applies the correct schema' => array(
|
||||
array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'type' => 'object',
|
||||
'anyOf' => array(
|
||||
array(
|
||||
'properties' => array(
|
||||
'a' => array(
|
||||
'type' => 'string',
|
||||
'context' => array( 'view' ),
|
||||
),
|
||||
'b' => array(
|
||||
'type' => 'string',
|
||||
'context' => array( 'edit' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'properties' => array(
|
||||
'a' => array(
|
||||
'type' => 'integer',
|
||||
'context' => array( 'edit' ),
|
||||
),
|
||||
'b' => array(
|
||||
'type' => 'integer',
|
||||
'context' => array( 'view' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'a' => 1,
|
||||
'b' => 2,
|
||||
),
|
||||
array(
|
||||
'b' => 2,
|
||||
),
|
||||
),
|
||||
'anyOf is ignored if no valid schema is found' => array(
|
||||
array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'type' => 'object',
|
||||
'anyOf' => array(
|
||||
array(
|
||||
'properties' => array(
|
||||
'a' => array(
|
||||
'type' => 'string',
|
||||
'context' => array( 'view' ),
|
||||
),
|
||||
'b' => array(
|
||||
'type' => 'string',
|
||||
'context' => array( 'edit' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'properties' => array(
|
||||
'a' => array(
|
||||
'type' => 'integer',
|
||||
'context' => array( 'edit' ),
|
||||
),
|
||||
'b' => array(
|
||||
'type' => 'integer',
|
||||
'context' => array( 'view' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'a' => true,
|
||||
'b' => false,
|
||||
),
|
||||
array(
|
||||
'a' => true,
|
||||
'b' => false,
|
||||
),
|
||||
),
|
||||
'oneOf applies the correct schema' => array(
|
||||
array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'type' => 'object',
|
||||
'oneOf' => array(
|
||||
array(
|
||||
'properties' => array(
|
||||
'a' => array(
|
||||
'type' => 'string',
|
||||
'context' => array( 'view' ),
|
||||
),
|
||||
'b' => array(
|
||||
'type' => 'string',
|
||||
'context' => array( 'edit' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'properties' => array(
|
||||
'a' => array(
|
||||
'type' => 'integer',
|
||||
'context' => array( 'edit' ),
|
||||
),
|
||||
'b' => array(
|
||||
'type' => 'integer',
|
||||
'context' => array( 'view' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'a' => 1,
|
||||
'b' => 2,
|
||||
),
|
||||
array(
|
||||
'b' => 2,
|
||||
),
|
||||
),
|
||||
'oneOf ignored if no valid schema was found' => array(
|
||||
array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'type' => 'object',
|
||||
'anyOf' => array(
|
||||
array(
|
||||
'properties' => array(
|
||||
'a' => array(
|
||||
'type' => 'string',
|
||||
'context' => array( 'view' ),
|
||||
),
|
||||
'b' => array(
|
||||
'type' => 'string',
|
||||
'context' => array( 'edit' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'properties' => array(
|
||||
'a' => array(
|
||||
'type' => 'integer',
|
||||
'context' => array( 'edit' ),
|
||||
),
|
||||
'b' => array(
|
||||
'type' => 'integer',
|
||||
'context' => array( 'view' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'a' => true,
|
||||
'b' => false,
|
||||
),
|
||||
array(
|
||||
'a' => true,
|
||||
'b' => false,
|
||||
),
|
||||
),
|
||||
'oneOf combined with base' => array(
|
||||
array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'type' => 'object',
|
||||
'properties' => array(
|
||||
'c' => array(
|
||||
'type' => 'integer',
|
||||
'context' => array( 'edit' ),
|
||||
),
|
||||
),
|
||||
'oneOf' => array(
|
||||
array(
|
||||
'properties' => array(
|
||||
'a' => array(
|
||||
'type' => 'string',
|
||||
'context' => array( 'view' ),
|
||||
),
|
||||
'b' => array(
|
||||
'type' => 'string',
|
||||
'context' => array( 'edit' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'properties' => array(
|
||||
'a' => array(
|
||||
'type' => 'integer',
|
||||
'context' => array( 'edit' ),
|
||||
),
|
||||
'b' => array(
|
||||
'type' => 'integer',
|
||||
'context' => array( 'view' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'a' => 1,
|
||||
'b' => 2,
|
||||
'c' => 3,
|
||||
),
|
||||
array(
|
||||
'b' => 2,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
[
|
||||
{
|
||||
"description": "anyOf",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"type": [
|
||||
"integer",
|
||||
"number"
|
||||
],
|
||||
"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": {
|
||||
"type": "object",
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,365 @@
|
||||
[
|
||||
{
|
||||
"description": "oneOf",
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"type": [
|
||||
"number",
|
||||
"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": {
|
||||
"type": "object",
|
||||
"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": {
|
||||
"type": "object",
|
||||
"oneOf": [
|
||||
{
|
||||
"properties": {
|
||||
"bar": {
|
||||
"type": "integer"
|
||||
},
|
||||
"baz": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"bar"
|
||||
]
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"foo": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -66,7 +66,7 @@ class WP_Test_REST_Controller extends WP_Test_REST_TestCase {
|
||||
);
|
||||
|
||||
$this->assertErrorResponse(
|
||||
'rest_invalid_param',
|
||||
'rest_invalid_type',
|
||||
rest_validate_request_arg( 'abc', $this->request, 'someinteger' )
|
||||
);
|
||||
}
|
||||
@@ -140,7 +140,7 @@ class WP_Test_REST_Controller extends WP_Test_REST_TestCase {
|
||||
);
|
||||
|
||||
$this->assertErrorResponse(
|
||||
'rest_invalid_param',
|
||||
'rest_invalid_type',
|
||||
rest_validate_request_arg( '123', $this->request, 'someboolean' )
|
||||
);
|
||||
}
|
||||
@@ -152,7 +152,7 @@ class WP_Test_REST_Controller extends WP_Test_REST_TestCase {
|
||||
);
|
||||
|
||||
$this->assertErrorResponse(
|
||||
'rest_invalid_param',
|
||||
'rest_invalid_type',
|
||||
rest_validate_request_arg( array( 'foo' => 'bar' ), $this->request, 'somestring' )
|
||||
);
|
||||
}
|
||||
@@ -297,6 +297,8 @@ class WP_Test_REST_Controller extends WP_Test_REST_TestCase {
|
||||
'additionalProperties',
|
||||
'minProperties',
|
||||
'maxProperties',
|
||||
'anyOf',
|
||||
'oneOf',
|
||||
);
|
||||
foreach ( $object_properties as $property ) {
|
||||
$this->assertArrayHasKey( $property, $args['someobject'] );
|
||||
|
||||
@@ -692,7 +692,7 @@ class WP_Test_REST_Post_Meta_Fields extends WP_Test_REST_TestCase {
|
||||
$request->set_body_params( $data );
|
||||
|
||||
$response = rest_get_server()->dispatch( $request );
|
||||
$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
|
||||
$this->assertErrorResponse( 'rest_invalid_type', $response, 400 );
|
||||
}
|
||||
|
||||
public function test_set_value_invalid_value_multiple() {
|
||||
@@ -717,7 +717,7 @@ class WP_Test_REST_Post_Meta_Fields extends WP_Test_REST_TestCase {
|
||||
$request->set_body_params( $data );
|
||||
|
||||
$response = rest_get_server()->dispatch( $request );
|
||||
$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
|
||||
$this->assertErrorResponse( 'rest_invalid_type', $response, 400 );
|
||||
}
|
||||
|
||||
public function test_set_value_sanitized() {
|
||||
|
||||
@@ -587,4 +587,51 @@ class WP_Test_REST_Schema_Sanitization extends WP_UnitTestCase {
|
||||
$this->assertTrue( rest_validate_value_from_schema( $data, $schema ) );
|
||||
$this->assertWPError( rest_sanitize_value_from_schema( $data, $schema ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @ticket 51025
|
||||
*/
|
||||
public function test_any_of() {
|
||||
$schema = array(
|
||||
'anyOf' => array(
|
||||
array(
|
||||
'type' => 'integer',
|
||||
'multipleOf' => 2,
|
||||
),
|
||||
array(
|
||||
'type' => 'string',
|
||||
'maxLength' => 1,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$this->assertSame( 4, rest_sanitize_value_from_schema( '4', $schema ) );
|
||||
$this->assertSame( '5', rest_sanitize_value_from_schema( '5', $schema ) );
|
||||
$this->assertWPError( rest_sanitize_value_from_schema( true, $schema ) );
|
||||
$this->assertWPError( rest_sanitize_value_from_schema( '11', $schema ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @ticket 51025
|
||||
*/
|
||||
public function test_one_of() {
|
||||
$schema = array(
|
||||
'oneOf' => array(
|
||||
array(
|
||||
'type' => 'integer',
|
||||
'multipleOf' => 2,
|
||||
),
|
||||
array(
|
||||
'type' => 'string',
|
||||
'maxLength' => 1,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$this->assertSame( 10, rest_sanitize_value_from_schema( '10', $schema ) );
|
||||
$this->assertSame( '5', rest_sanitize_value_from_schema( '5', $schema ) );
|
||||
$this->assertWPError( rest_sanitize_value_from_schema( true, $schema ) );
|
||||
$this->assertWPError( rest_sanitize_value_from_schema( '11', $schema ) );
|
||||
$this->assertWPError( rest_sanitize_value_from_schema( '4', $schema ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1253,4 +1253,312 @@ class WP_Test_REST_Schema_Validation extends WP_UnitTestCase {
|
||||
$this->assertWPError( rest_validate_value_from_schema( 15.5, $schema ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @ticket 51025
|
||||
*
|
||||
* @dataProvider data_any_of
|
||||
*
|
||||
* @param array $data
|
||||
* @param array $schema
|
||||
* @param bool $valid
|
||||
*/
|
||||
public function test_any_of( $data, $schema, $valid ) {
|
||||
$is_valid = rest_validate_value_from_schema( $data, $schema );
|
||||
|
||||
if ( $valid ) {
|
||||
$this->assertTrue( $is_valid );
|
||||
} else {
|
||||
$this->assertWPError( $is_valid );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function data_any_of() {
|
||||
$suites = json_decode( file_get_contents( __DIR__ . '/json_schema_test_suite/anyof.json' ), true );
|
||||
$skip = array(
|
||||
'anyOf with boolean schemas, all true',
|
||||
'anyOf with boolean schemas, some true',
|
||||
'anyOf with boolean schemas, all false',
|
||||
'anyOf with one empty schema',
|
||||
'nested anyOf, to check validation semantics',
|
||||
);
|
||||
|
||||
$tests = array();
|
||||
|
||||
foreach ( $suites as $suite ) {
|
||||
if ( in_array( $suite['description'], $skip, true ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $suite['tests'] as $test ) {
|
||||
$tests[ $suite['description'] . ': ' . $test['description'] ] = array(
|
||||
$test['data'],
|
||||
$suite['schema'],
|
||||
$test['valid'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ticket 51025
|
||||
*
|
||||
* @dataProvider data_one_of
|
||||
*
|
||||
* @param array $data
|
||||
* @param array $schema
|
||||
* @param bool $valid
|
||||
*/
|
||||
public function test_one_of( $data, $schema, $valid ) {
|
||||
$is_valid = rest_validate_value_from_schema( $data, $schema );
|
||||
|
||||
if ( $valid ) {
|
||||
$this->assertTrue( $is_valid );
|
||||
} else {
|
||||
$this->assertWPError( $is_valid );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function data_one_of() {
|
||||
$suites = json_decode( file_get_contents( __DIR__ . '/json_schema_test_suite/oneof.json' ), true );
|
||||
$skip = array(
|
||||
'oneOf with boolean schemas, all true',
|
||||
'oneOf with boolean schemas, one true',
|
||||
'oneOf with boolean schemas, more than one true',
|
||||
'oneOf with boolean schemas, all false',
|
||||
'oneOf with empty schema',
|
||||
'nested oneOf, to check validation semantics',
|
||||
);
|
||||
|
||||
$tests = array();
|
||||
|
||||
foreach ( $suites as $suite ) {
|
||||
if ( in_array( $suite['description'], $skip, true ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ( $suite['tests'] as $test ) {
|
||||
$tests[ $suite['description'] . ': ' . $test['description'] ] = array(
|
||||
$test['data'],
|
||||
$suite['schema'],
|
||||
$test['valid'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ticket 51025
|
||||
*
|
||||
* @dataProvider data_combining_operation_error_message
|
||||
*
|
||||
* @param $data
|
||||
* @param $schema
|
||||
* @param $expected
|
||||
*/
|
||||
public function test_combining_operation_error_message( $data, $schema, $expected ) {
|
||||
$is_valid = rest_validate_value_from_schema( $data, $schema, 'foo' );
|
||||
|
||||
$this->assertWPError( $is_valid );
|
||||
$this->assertSame( $expected, $is_valid->get_error_message() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function data_combining_operation_error_message() {
|
||||
return array(
|
||||
array(
|
||||
10,
|
||||
array(
|
||||
'anyOf' => array(
|
||||
array(
|
||||
'title' => 'circle',
|
||||
'type' => 'integer',
|
||||
'maximum' => 5,
|
||||
),
|
||||
),
|
||||
),
|
||||
'foo is not a valid circle. Reason: foo must be less than or equal to 5',
|
||||
),
|
||||
array(
|
||||
10,
|
||||
array(
|
||||
'anyOf' => array(
|
||||
array(
|
||||
'type' => 'integer',
|
||||
'maximum' => 5,
|
||||
),
|
||||
),
|
||||
),
|
||||
'foo does not match the expected format. Reason: foo must be less than or equal to 5',
|
||||
),
|
||||
array(
|
||||
array( 'a' => 1 ),
|
||||
array(
|
||||
'anyOf' => array(
|
||||
array( 'type' => 'boolean' ),
|
||||
array(
|
||||
'title' => 'circle',
|
||||
'type' => 'object',
|
||||
'properties' => array(
|
||||
'a' => array( 'type' => 'string' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
'foo is not a valid circle. Reason: foo[a] is not of type string.',
|
||||
),
|
||||
array(
|
||||
array( 'a' => 1 ),
|
||||
array(
|
||||
'anyOf' => array(
|
||||
array( 'type' => 'boolean' ),
|
||||
array(
|
||||
'type' => 'object',
|
||||
'properties' => array(
|
||||
'a' => array( 'type' => 'string' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
'foo does not match the expected format. Reason: foo[a] is not of type string.',
|
||||
),
|
||||
array(
|
||||
array(
|
||||
'a' => 1,
|
||||
'b' => 2,
|
||||
'c' => 3,
|
||||
),
|
||||
array(
|
||||
'anyOf' => array(
|
||||
array( 'type' => 'boolean' ),
|
||||
array(
|
||||
'type' => 'object',
|
||||
'properties' => array(
|
||||
'a' => array( 'type' => 'string' ),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'title' => 'square',
|
||||
'type' => 'object',
|
||||
'properties' => array(
|
||||
'b' => array( 'type' => 'string' ),
|
||||
'c' => array( 'type' => 'string' ),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'type' => 'object',
|
||||
'properties' => array(
|
||||
'b' => array( 'type' => 'boolean' ),
|
||||
'x' => array( 'type' => 'boolean' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
'foo is not a valid square. Reason: foo[b] is not of type string.',
|
||||
),
|
||||
array(
|
||||
array(
|
||||
'a' => 1,
|
||||
'b' => 2,
|
||||
'c' => 3,
|
||||
),
|
||||
array(
|
||||
'anyOf' => array(
|
||||
array( 'type' => 'boolean' ),
|
||||
array(
|
||||
'type' => 'object',
|
||||
'properties' => array(
|
||||
'a' => array( 'type' => 'string' ),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'type' => 'object',
|
||||
'properties' => array(
|
||||
'b' => array( 'type' => 'string' ),
|
||||
'c' => array( 'type' => 'string' ),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'type' => 'object',
|
||||
'properties' => array(
|
||||
'b' => array( 'type' => 'boolean' ),
|
||||
'x' => array( 'type' => 'boolean' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
'foo does not match the expected format. Reason: foo[b] is not of type string.',
|
||||
),
|
||||
array(
|
||||
'test',
|
||||
array(
|
||||
'anyOf' => array(
|
||||
array(
|
||||
'title' => 'circle',
|
||||
'type' => 'boolean',
|
||||
),
|
||||
array(
|
||||
'title' => 'square',
|
||||
'type' => 'integer',
|
||||
),
|
||||
array(
|
||||
'title' => 'triangle',
|
||||
'type' => 'null',
|
||||
),
|
||||
),
|
||||
),
|
||||
'foo is not a valid circle, square, and triangle.',
|
||||
),
|
||||
array(
|
||||
'test',
|
||||
array(
|
||||
'anyOf' => array(
|
||||
array( 'type' => 'boolean' ),
|
||||
array( 'type' => 'integer' ),
|
||||
array( 'type' => 'null' ),
|
||||
),
|
||||
),
|
||||
'foo does not match any of the expected formats.',
|
||||
),
|
||||
array(
|
||||
'test',
|
||||
array(
|
||||
'oneOf' => array(
|
||||
array(
|
||||
'title' => 'circle',
|
||||
'type' => 'string',
|
||||
),
|
||||
array( 'type' => 'integer' ),
|
||||
array(
|
||||
'title' => 'triangle',
|
||||
'type' => 'string',
|
||||
),
|
||||
),
|
||||
),
|
||||
'foo matches circle and triangle, but should match only one.',
|
||||
),
|
||||
array(
|
||||
'test',
|
||||
array(
|
||||
'oneOf' => array(
|
||||
array( 'type' => 'string' ),
|
||||
array( 'type' => 'integer' ),
|
||||
array( 'type' => 'string' ),
|
||||
),
|
||||
),
|
||||
'foo matches more than one of the expected formats.',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -639,7 +639,7 @@ class WP_Test_REST_Term_Meta_Fields extends WP_Test_REST_TestCase {
|
||||
$request->set_body_params( $data );
|
||||
|
||||
$response = rest_get_server()->dispatch( $request );
|
||||
$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
|
||||
$this->assertErrorResponse( 'rest_invalid_type', $response, 400 );
|
||||
}
|
||||
|
||||
public function test_set_value_invalid_value_multiple() {
|
||||
@@ -664,7 +664,7 @@ class WP_Test_REST_Term_Meta_Fields extends WP_Test_REST_TestCase {
|
||||
$request->set_body_params( $data );
|
||||
|
||||
$response = rest_get_server()->dispatch( $request );
|
||||
$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
|
||||
$this->assertErrorResponse( 'rest_invalid_type', $response, 400 );
|
||||
}
|
||||
|
||||
public function test_set_value_sanitized() {
|
||||
|
||||
@@ -128,6 +128,42 @@ class WP_REST_Test_Controller extends WP_REST_Controller {
|
||||
),
|
||||
'minProperties' => 1,
|
||||
'maxProperties' => 10,
|
||||
'anyOf' => array(
|
||||
array(
|
||||
'properties' => array(
|
||||
'object_id' => array(
|
||||
'type' => 'integer',
|
||||
'minimum' => 100,
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'properties' => array(
|
||||
'object_id' => array(
|
||||
'type' => 'integer',
|
||||
'maximum' => 100,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
'oneOf' => array(
|
||||
array(
|
||||
'properties' => array(
|
||||
'object_id' => array(
|
||||
'type' => 'integer',
|
||||
'minimum' => 100,
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'properties' => array(
|
||||
'object_id' => array(
|
||||
'type' => 'integer',
|
||||
'maximum' => 100,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
'ignored_prop' => 'ignored_prop',
|
||||
'context' => array( 'view' ),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user