Skip to content

BUG: Keyword oneOf doesn't contain sub errors in version 2.x #98

Closed
@liborm85

Description

@liborm85

Validation in version 1.x return sub errors for keyword oneOf, but version 2.x return only The data should match exactly one schema. Keyword anyOf works correctly with sub errors in both versions. I think both keywords oneOf and anyOf should work similarly.

See examples bellow.

Details

Examples for reproduce:

Example to reproduce issue in version 1.1.0
use Opis\JsonSchema\{
    Validator, ValidationResult, ValidationError, Schema
};

$dataJson = <<<'JSON'
{
  "case1A": "foo"
}
JSON;

$schemaJson = <<<'JSON'
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "oneOf": [
    {
      "$comment": "Case 1",
      "additionalProperties": false,
      "properties": {
        "case1A": {
          "type": "string"
        },
        "case1B": {
          "type": "string"
        }
      },
      "required": [
        "case1A",
        "case1B"
      ]
    },
    {
      "$comment": "Case 2",
      "additionalProperties": false,
      "properties": {
        "case2A": {
          "type": "string"
        },
        "case2B": {
          "type": "string"
        }
      },
      "required": [
        "case2A",
        "case2B"
      ]
    },
    {
      "$comment": "Case 3",
      "additionalProperties": false,
      "properties": {
        "case3A": {
          "type": "string"
        },
        "case3B": {
          "type": "string"
        }
      },
      "required": [
        "case3A",
        "case3B"
      ]
    }
  ]
}
JSON;

$data = json_decode($dataJson);
$schema = Schema::fromJsonString($schemaJson);

$validator = new Validator();

/** @var ValidationResult $result */
$result = $validator->schemaValidation($data, $schema);

if ($result->isValid()) {
    echo '$data is valid', PHP_EOL;
} else {
    /** @var ValidationError $error */
    $error = $result->getFirstError();
    echo '$data is invalid', PHP_EOL;
    echo "Error: ", $error->keyword(), PHP_EOL;
    echo json_encode($error->keywordArgs(), JSON_PRETTY_PRINT), PHP_EOL;
    foreach ($error->subErrors() as $subError) {
        echo "Sub Error: ", $subError->keyword(), PHP_EOL;
        echo json_encode($subError->keywordArgs(), JSON_PRETTY_PRINT), PHP_EOL;
    }
}
Example to reproduce issue in version 2.2.0
use Opis\JsonSchema\{
    Validator, ValidationResult, Errors\ErrorFormatter,
};

$dataJson = <<<'JSON'
{
  "case1A": "foo"
}
JSON;

$schemaJson = <<<'JSON'
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "oneOf": [
    {
      "$comment": "Case 1",
      "additionalProperties": false,
      "properties": {
        "case1A": {
          "type": "string"
        },
        "case1B": {
          "type": "string"
        }
      },
      "required": [
        "case1A",
        "case1B"
      ]
    },
    {
      "$comment": "Case 2",
      "additionalProperties": false,
      "properties": {
        "case2A": {
          "type": "string"
        },
        "case2B": {
          "type": "string"
        }
      },
      "required": [
        "case2A",
        "case2B"
      ]
    },
    {
      "$comment": "Case 3",
      "additionalProperties": false,
      "properties": {
        "case3A": {
          "type": "string"
        },
        "case3B": {
          "type": "string"
        }
      },
      "required": [
        "case3A",
        "case3B"
      ]
    }
  ]
}
JSON;

$validator = new Validator();
$data = json_decode($dataJson);
$schema = $validator->loader()->loadObjectSchema(json_decode($schemaJson));

/** @var ValidationResult $result */
$result = $validator->validate($data, $schema);

if ($result->isValid()) {
    echo "Valid", PHP_EOL;
} else {
    // Print errors
    echo "Error: ";
    print_r((new ErrorFormatter())->format($result->error()));
    foreach ($result->error()->subErrors() as $subError) {
        echo "Sub Error: ";
        /** @var \Opis\JsonSchema\Errors\ValidationError $subError */
        print_r((new ErrorFormatter())->format($subError));
    }
}

Output in version 1.1.0:

$data is invalid
Error: oneOf
{
    "matched": 0
}
Sub Error: required
{
    "missing": "case1B"
}
Sub Error: required
{
    "missing": "case2A"
}
Sub Error: required
{
    "missing": "case3A"
}

Wrong output without sub errors in version 2.2.0:

Error: Array
(
    [/] => Array
        (
            [0] => The data should match exactly one schema
        )

)

If I try it in with anyOf keyword in version 2.x output is correct:

Example with anyOf in version 2.2.0
use Opis\JsonSchema\{
    Validator, ValidationResult, Errors\ErrorFormatter,
};

$dataJson = <<<'JSON'
{
  "case1A": "foo"
}
JSON;

$schemaJson = <<<'JSON'
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "anyOf": [
    {
      "$comment": "Case 1",
      "additionalProperties": false,
      "properties": {
        "case1A": {
          "type": "string"
        },
        "case1B": {
          "type": "string"
        }
      },
      "required": [
        "case1A",
        "case1B"
      ]
    },
    {
      "$comment": "Case 2",
      "additionalProperties": false,
      "properties": {
        "case2A": {
          "type": "string"
        },
        "case2B": {
          "type": "string"
        }
      },
      "required": [
        "case2A",
        "case2B"
      ]
    },
    {
      "$comment": "Case 3",
      "additionalProperties": false,
      "properties": {
        "case3A": {
          "type": "string"
        },
        "case3B": {
          "type": "string"
        }
      },
      "required": [
        "case3A",
        "case3B"
      ]
    }
  ]
}
JSON;

$validator = new Validator();
$data = json_decode($dataJson);
$schema = $validator->loader()->loadObjectSchema(json_decode($schemaJson));

/** @var ValidationResult $result */
$result = $validator->validate($data, $schema);

if ($result->isValid()) {
    echo "Valid", PHP_EOL;
} else {
    // Print errors
    echo "Error: ";
    print_r((new ErrorFormatter())->format($result->error()));
    foreach ($result->error()->subErrors() as $subError) {
        echo "Sub Error: ";
        /** @var \Opis\JsonSchema\Errors\ValidationError $subError */
        print_r((new ErrorFormatter())->format($subError));
    }
}

Output in version 2.2.0 for anyOf:

Error: Array
(
    [/] => Array
        (
            [0] => The required properties (case1B) are missing
            [1] => The required properties (case2A) are missing
            [2] => The required properties (case3A) are missing
        )

)
Sub Error: Array
(
    [/] => Array
        (
            [0] => The required properties (case1B) are missing
        )

)
Sub Error: Array
(
    [/] => Array
        (
            [0] => The required properties (case2A) are missing
        )

)
Sub Error: Array
(
    [/] => Array
        (
            [0] => The required properties (case3A) are missing
        )

)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions