Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
liborm85 opened this issue Dec 14, 2021 · 1 comment · Fixed by #99
Closed

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

liborm85 opened this issue Dec 14, 2021 · 1 comment · Fixed by #99

Comments

@liborm85
Copy link
Contributor

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
        )

)
@liborm85
Copy link
Contributor Author

Pull request with fix: #99

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant