Building Project Files
هذا الالتزام موجود في:
904
venv/lib/python3.12/site-packages/jsonschema/tests/test_cli.py
Normal file
904
venv/lib/python3.12/site-packages/jsonschema/tests/test_cli.py
Normal file
@@ -0,0 +1,904 @@
|
||||
from contextlib import redirect_stderr, redirect_stdout
|
||||
from importlib import metadata
|
||||
from io import StringIO
|
||||
from json import JSONDecodeError
|
||||
from pathlib import Path
|
||||
from textwrap import dedent
|
||||
from unittest import TestCase
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import warnings
|
||||
|
||||
from jsonschema import Draft4Validator, Draft202012Validator
|
||||
from jsonschema.exceptions import (
|
||||
SchemaError,
|
||||
ValidationError,
|
||||
_RefResolutionError,
|
||||
)
|
||||
from jsonschema.validators import _LATEST_VERSION, validate
|
||||
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
from jsonschema import cli
|
||||
|
||||
|
||||
def fake_validator(*errors):
|
||||
errors = list(reversed(errors))
|
||||
|
||||
class FakeValidator:
|
||||
def __init__(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def iter_errors(self, instance):
|
||||
if errors:
|
||||
return errors.pop()
|
||||
return [] # pragma: no cover
|
||||
|
||||
@classmethod
|
||||
def check_schema(self, schema):
|
||||
pass
|
||||
|
||||
return FakeValidator
|
||||
|
||||
|
||||
def fake_open(all_contents):
|
||||
def open(path):
|
||||
contents = all_contents.get(path)
|
||||
if contents is None:
|
||||
raise FileNotFoundError(path)
|
||||
return StringIO(contents)
|
||||
return open
|
||||
|
||||
|
||||
def _message_for(non_json):
|
||||
try:
|
||||
json.loads(non_json)
|
||||
except JSONDecodeError as error:
|
||||
return str(error)
|
||||
else: # pragma: no cover
|
||||
raise RuntimeError("Tried and failed to capture a JSON dump error.")
|
||||
|
||||
|
||||
class TestCLI(TestCase):
|
||||
def run_cli(
|
||||
self, argv, files=None, stdin=StringIO(), exit_code=0, **override,
|
||||
):
|
||||
arguments = cli.parse_args(argv)
|
||||
arguments.update(override)
|
||||
|
||||
self.assertFalse(hasattr(cli, "open"))
|
||||
cli.open = fake_open(files or {})
|
||||
try:
|
||||
stdout, stderr = StringIO(), StringIO()
|
||||
actual_exit_code = cli.run(
|
||||
arguments,
|
||||
stdin=stdin,
|
||||
stdout=stdout,
|
||||
stderr=stderr,
|
||||
)
|
||||
finally:
|
||||
del cli.open
|
||||
|
||||
self.assertEqual(
|
||||
actual_exit_code, exit_code, msg=dedent(
|
||||
f"""
|
||||
Expected an exit code of {exit_code} != {actual_exit_code}.
|
||||
|
||||
stdout: {stdout.getvalue()}
|
||||
|
||||
stderr: {stderr.getvalue()}
|
||||
""",
|
||||
),
|
||||
)
|
||||
return stdout.getvalue(), stderr.getvalue()
|
||||
|
||||
def assertOutputs(self, stdout="", stderr="", **kwargs):
|
||||
self.assertEqual(
|
||||
self.run_cli(**kwargs),
|
||||
(dedent(stdout), dedent(stderr)),
|
||||
)
|
||||
|
||||
def test_invalid_instance(self):
|
||||
error = ValidationError("I am an error!", instance=12)
|
||||
self.assertOutputs(
|
||||
files=dict(
|
||||
some_schema='{"does not": "matter since it is stubbed"}',
|
||||
some_instance=json.dumps(error.instance),
|
||||
),
|
||||
validator=fake_validator([error]),
|
||||
|
||||
argv=["-i", "some_instance", "some_schema"],
|
||||
|
||||
exit_code=1,
|
||||
stderr="12: I am an error!\n",
|
||||
)
|
||||
|
||||
def test_invalid_instance_pretty_output(self):
|
||||
error = ValidationError("I am an error!", instance=12)
|
||||
self.assertOutputs(
|
||||
files=dict(
|
||||
some_schema='{"does not": "matter since it is stubbed"}',
|
||||
some_instance=json.dumps(error.instance),
|
||||
),
|
||||
validator=fake_validator([error]),
|
||||
|
||||
argv=["-i", "some_instance", "--output", "pretty", "some_schema"],
|
||||
|
||||
exit_code=1,
|
||||
stderr="""\
|
||||
===[ValidationError]===(some_instance)===
|
||||
|
||||
I am an error!
|
||||
-----------------------------
|
||||
""",
|
||||
)
|
||||
|
||||
def test_invalid_instance_explicit_plain_output(self):
|
||||
error = ValidationError("I am an error!", instance=12)
|
||||
self.assertOutputs(
|
||||
files=dict(
|
||||
some_schema='{"does not": "matter since it is stubbed"}',
|
||||
some_instance=json.dumps(error.instance),
|
||||
),
|
||||
validator=fake_validator([error]),
|
||||
|
||||
argv=["--output", "plain", "-i", "some_instance", "some_schema"],
|
||||
|
||||
exit_code=1,
|
||||
stderr="12: I am an error!\n",
|
||||
)
|
||||
|
||||
def test_invalid_instance_multiple_errors(self):
|
||||
instance = 12
|
||||
first = ValidationError("First error", instance=instance)
|
||||
second = ValidationError("Second error", instance=instance)
|
||||
|
||||
self.assertOutputs(
|
||||
files=dict(
|
||||
some_schema='{"does not": "matter since it is stubbed"}',
|
||||
some_instance=json.dumps(instance),
|
||||
),
|
||||
validator=fake_validator([first, second]),
|
||||
|
||||
argv=["-i", "some_instance", "some_schema"],
|
||||
|
||||
exit_code=1,
|
||||
stderr="""\
|
||||
12: First error
|
||||
12: Second error
|
||||
""",
|
||||
)
|
||||
|
||||
def test_invalid_instance_multiple_errors_pretty_output(self):
|
||||
instance = 12
|
||||
first = ValidationError("First error", instance=instance)
|
||||
second = ValidationError("Second error", instance=instance)
|
||||
|
||||
self.assertOutputs(
|
||||
files=dict(
|
||||
some_schema='{"does not": "matter since it is stubbed"}',
|
||||
some_instance=json.dumps(instance),
|
||||
),
|
||||
validator=fake_validator([first, second]),
|
||||
|
||||
argv=["-i", "some_instance", "--output", "pretty", "some_schema"],
|
||||
|
||||
exit_code=1,
|
||||
stderr="""\
|
||||
===[ValidationError]===(some_instance)===
|
||||
|
||||
First error
|
||||
-----------------------------
|
||||
===[ValidationError]===(some_instance)===
|
||||
|
||||
Second error
|
||||
-----------------------------
|
||||
""",
|
||||
)
|
||||
|
||||
def test_multiple_invalid_instances(self):
|
||||
first_instance = 12
|
||||
first_errors = [
|
||||
ValidationError("An error", instance=first_instance),
|
||||
ValidationError("Another error", instance=first_instance),
|
||||
]
|
||||
second_instance = "foo"
|
||||
second_errors = [ValidationError("BOOM", instance=second_instance)]
|
||||
|
||||
self.assertOutputs(
|
||||
files=dict(
|
||||
some_schema='{"does not": "matter since it is stubbed"}',
|
||||
some_first_instance=json.dumps(first_instance),
|
||||
some_second_instance=json.dumps(second_instance),
|
||||
),
|
||||
validator=fake_validator(first_errors, second_errors),
|
||||
|
||||
argv=[
|
||||
"-i", "some_first_instance",
|
||||
"-i", "some_second_instance",
|
||||
"some_schema",
|
||||
],
|
||||
|
||||
exit_code=1,
|
||||
stderr="""\
|
||||
12: An error
|
||||
12: Another error
|
||||
foo: BOOM
|
||||
""",
|
||||
)
|
||||
|
||||
def test_multiple_invalid_instances_pretty_output(self):
|
||||
first_instance = 12
|
||||
first_errors = [
|
||||
ValidationError("An error", instance=first_instance),
|
||||
ValidationError("Another error", instance=first_instance),
|
||||
]
|
||||
second_instance = "foo"
|
||||
second_errors = [ValidationError("BOOM", instance=second_instance)]
|
||||
|
||||
self.assertOutputs(
|
||||
files=dict(
|
||||
some_schema='{"does not": "matter since it is stubbed"}',
|
||||
some_first_instance=json.dumps(first_instance),
|
||||
some_second_instance=json.dumps(second_instance),
|
||||
),
|
||||
validator=fake_validator(first_errors, second_errors),
|
||||
|
||||
argv=[
|
||||
"--output", "pretty",
|
||||
"-i", "some_first_instance",
|
||||
"-i", "some_second_instance",
|
||||
"some_schema",
|
||||
],
|
||||
|
||||
exit_code=1,
|
||||
stderr="""\
|
||||
===[ValidationError]===(some_first_instance)===
|
||||
|
||||
An error
|
||||
-----------------------------
|
||||
===[ValidationError]===(some_first_instance)===
|
||||
|
||||
Another error
|
||||
-----------------------------
|
||||
===[ValidationError]===(some_second_instance)===
|
||||
|
||||
BOOM
|
||||
-----------------------------
|
||||
""",
|
||||
)
|
||||
|
||||
def test_custom_error_format(self):
|
||||
first_instance = 12
|
||||
first_errors = [
|
||||
ValidationError("An error", instance=first_instance),
|
||||
ValidationError("Another error", instance=first_instance),
|
||||
]
|
||||
second_instance = "foo"
|
||||
second_errors = [ValidationError("BOOM", instance=second_instance)]
|
||||
|
||||
self.assertOutputs(
|
||||
files=dict(
|
||||
some_schema='{"does not": "matter since it is stubbed"}',
|
||||
some_first_instance=json.dumps(first_instance),
|
||||
some_second_instance=json.dumps(second_instance),
|
||||
),
|
||||
validator=fake_validator(first_errors, second_errors),
|
||||
|
||||
argv=[
|
||||
"--error-format", ":{error.message}._-_.{error.instance}:",
|
||||
"-i", "some_first_instance",
|
||||
"-i", "some_second_instance",
|
||||
"some_schema",
|
||||
],
|
||||
|
||||
exit_code=1,
|
||||
stderr=":An error._-_.12::Another error._-_.12::BOOM._-_.foo:",
|
||||
)
|
||||
|
||||
def test_invalid_schema(self):
|
||||
self.assertOutputs(
|
||||
files=dict(some_schema='{"type": 12}'),
|
||||
argv=["some_schema"],
|
||||
|
||||
exit_code=1,
|
||||
stderr="""\
|
||||
12: 12 is not valid under any of the given schemas
|
||||
""",
|
||||
)
|
||||
|
||||
def test_invalid_schema_pretty_output(self):
|
||||
schema = {"type": 12}
|
||||
|
||||
with self.assertRaises(SchemaError) as e:
|
||||
validate(schema=schema, instance="")
|
||||
error = str(e.exception)
|
||||
|
||||
self.assertOutputs(
|
||||
files=dict(some_schema=json.dumps(schema)),
|
||||
argv=["--output", "pretty", "some_schema"],
|
||||
|
||||
exit_code=1,
|
||||
stderr=(
|
||||
"===[SchemaError]===(some_schema)===\n\n"
|
||||
+ str(error)
|
||||
+ "\n-----------------------------\n"
|
||||
),
|
||||
)
|
||||
|
||||
def test_invalid_schema_multiple_errors(self):
|
||||
self.assertOutputs(
|
||||
files=dict(some_schema='{"type": 12, "items": 57}'),
|
||||
argv=["some_schema"],
|
||||
|
||||
exit_code=1,
|
||||
stderr="""\
|
||||
57: 57 is not of type 'object', 'boolean'
|
||||
""",
|
||||
)
|
||||
|
||||
def test_invalid_schema_multiple_errors_pretty_output(self):
|
||||
schema = {"type": 12, "items": 57}
|
||||
|
||||
with self.assertRaises(SchemaError) as e:
|
||||
validate(schema=schema, instance="")
|
||||
error = str(e.exception)
|
||||
|
||||
self.assertOutputs(
|
||||
files=dict(some_schema=json.dumps(schema)),
|
||||
argv=["--output", "pretty", "some_schema"],
|
||||
|
||||
exit_code=1,
|
||||
stderr=(
|
||||
"===[SchemaError]===(some_schema)===\n\n"
|
||||
+ str(error)
|
||||
+ "\n-----------------------------\n"
|
||||
),
|
||||
)
|
||||
|
||||
def test_invalid_schema_with_invalid_instance(self):
|
||||
"""
|
||||
"Validating" an instance that's invalid under an invalid schema
|
||||
just shows the schema error.
|
||||
"""
|
||||
self.assertOutputs(
|
||||
files=dict(
|
||||
some_schema='{"type": 12, "minimum": 30}',
|
||||
some_instance="13",
|
||||
),
|
||||
argv=["-i", "some_instance", "some_schema"],
|
||||
|
||||
exit_code=1,
|
||||
stderr="""\
|
||||
12: 12 is not valid under any of the given schemas
|
||||
""",
|
||||
)
|
||||
|
||||
def test_invalid_schema_with_invalid_instance_pretty_output(self):
|
||||
instance, schema = 13, {"type": 12, "minimum": 30}
|
||||
|
||||
with self.assertRaises(SchemaError) as e:
|
||||
validate(schema=schema, instance=instance)
|
||||
error = str(e.exception)
|
||||
|
||||
self.assertOutputs(
|
||||
files=dict(
|
||||
some_schema=json.dumps(schema),
|
||||
some_instance=json.dumps(instance),
|
||||
),
|
||||
argv=["--output", "pretty", "-i", "some_instance", "some_schema"],
|
||||
|
||||
exit_code=1,
|
||||
stderr=(
|
||||
"===[SchemaError]===(some_schema)===\n\n"
|
||||
+ str(error)
|
||||
+ "\n-----------------------------\n"
|
||||
),
|
||||
)
|
||||
|
||||
def test_invalid_instance_continues_with_the_rest(self):
|
||||
self.assertOutputs(
|
||||
files=dict(
|
||||
some_schema='{"minimum": 30}',
|
||||
first_instance="not valid JSON!",
|
||||
second_instance="12",
|
||||
),
|
||||
argv=[
|
||||
"-i", "first_instance",
|
||||
"-i", "second_instance",
|
||||
"some_schema",
|
||||
],
|
||||
|
||||
exit_code=1,
|
||||
stderr="""\
|
||||
Failed to parse 'first_instance': {}
|
||||
12: 12 is less than the minimum of 30
|
||||
""".format(_message_for("not valid JSON!")),
|
||||
)
|
||||
|
||||
def test_custom_error_format_applies_to_schema_errors(self):
|
||||
instance, schema = 13, {"type": 12, "minimum": 30}
|
||||
|
||||
with self.assertRaises(SchemaError):
|
||||
validate(schema=schema, instance=instance)
|
||||
|
||||
self.assertOutputs(
|
||||
files=dict(some_schema=json.dumps(schema)),
|
||||
|
||||
argv=[
|
||||
"--error-format", ":{error.message}._-_.{error.instance}:",
|
||||
"some_schema",
|
||||
],
|
||||
|
||||
exit_code=1,
|
||||
stderr=":12 is not valid under any of the given schemas._-_.12:",
|
||||
)
|
||||
|
||||
def test_instance_is_invalid_JSON(self):
|
||||
instance = "not valid JSON!"
|
||||
|
||||
self.assertOutputs(
|
||||
files=dict(some_schema="{}", some_instance=instance),
|
||||
argv=["-i", "some_instance", "some_schema"],
|
||||
|
||||
exit_code=1,
|
||||
stderr=f"""\
|
||||
Failed to parse 'some_instance': {_message_for(instance)}
|
||||
""",
|
||||
)
|
||||
|
||||
def test_instance_is_invalid_JSON_pretty_output(self):
|
||||
stdout, stderr = self.run_cli(
|
||||
files=dict(
|
||||
some_schema="{}",
|
||||
some_instance="not valid JSON!",
|
||||
),
|
||||
|
||||
argv=["--output", "pretty", "-i", "some_instance", "some_schema"],
|
||||
|
||||
exit_code=1,
|
||||
)
|
||||
self.assertFalse(stdout)
|
||||
self.assertIn(
|
||||
"(some_instance)===\n\nTraceback (most recent call last):\n",
|
||||
stderr,
|
||||
)
|
||||
self.assertNotIn("some_schema", stderr)
|
||||
|
||||
def test_instance_is_invalid_JSON_on_stdin(self):
|
||||
instance = "not valid JSON!"
|
||||
|
||||
self.assertOutputs(
|
||||
files=dict(some_schema="{}"),
|
||||
stdin=StringIO(instance),
|
||||
|
||||
argv=["some_schema"],
|
||||
|
||||
exit_code=1,
|
||||
stderr=f"""\
|
||||
Failed to parse <stdin>: {_message_for(instance)}
|
||||
""",
|
||||
)
|
||||
|
||||
def test_instance_is_invalid_JSON_on_stdin_pretty_output(self):
|
||||
stdout, stderr = self.run_cli(
|
||||
files=dict(some_schema="{}"),
|
||||
stdin=StringIO("not valid JSON!"),
|
||||
|
||||
argv=["--output", "pretty", "some_schema"],
|
||||
|
||||
exit_code=1,
|
||||
)
|
||||
self.assertFalse(stdout)
|
||||
self.assertIn(
|
||||
"(<stdin>)===\n\nTraceback (most recent call last):\n",
|
||||
stderr,
|
||||
)
|
||||
self.assertNotIn("some_schema", stderr)
|
||||
|
||||
def test_schema_is_invalid_JSON(self):
|
||||
schema = "not valid JSON!"
|
||||
|
||||
self.assertOutputs(
|
||||
files=dict(some_schema=schema),
|
||||
|
||||
argv=["some_schema"],
|
||||
|
||||
exit_code=1,
|
||||
stderr=f"""\
|
||||
Failed to parse 'some_schema': {_message_for(schema)}
|
||||
""",
|
||||
)
|
||||
|
||||
def test_schema_is_invalid_JSON_pretty_output(self):
|
||||
stdout, stderr = self.run_cli(
|
||||
files=dict(some_schema="not valid JSON!"),
|
||||
|
||||
argv=["--output", "pretty", "some_schema"],
|
||||
|
||||
exit_code=1,
|
||||
)
|
||||
self.assertFalse(stdout)
|
||||
self.assertIn(
|
||||
"(some_schema)===\n\nTraceback (most recent call last):\n",
|
||||
stderr,
|
||||
)
|
||||
|
||||
def test_schema_and_instance_are_both_invalid_JSON(self):
|
||||
"""
|
||||
Only the schema error is reported, as we abort immediately.
|
||||
"""
|
||||
schema, instance = "not valid JSON!", "also not valid JSON!"
|
||||
self.assertOutputs(
|
||||
files=dict(some_schema=schema, some_instance=instance),
|
||||
|
||||
argv=["some_schema"],
|
||||
|
||||
exit_code=1,
|
||||
stderr=f"""\
|
||||
Failed to parse 'some_schema': {_message_for(schema)}
|
||||
""",
|
||||
)
|
||||
|
||||
def test_schema_and_instance_are_both_invalid_JSON_pretty_output(self):
|
||||
"""
|
||||
Only the schema error is reported, as we abort immediately.
|
||||
"""
|
||||
stdout, stderr = self.run_cli(
|
||||
files=dict(
|
||||
some_schema="not valid JSON!",
|
||||
some_instance="also not valid JSON!",
|
||||
),
|
||||
|
||||
argv=["--output", "pretty", "-i", "some_instance", "some_schema"],
|
||||
|
||||
exit_code=1,
|
||||
)
|
||||
self.assertFalse(stdout)
|
||||
self.assertIn(
|
||||
"(some_schema)===\n\nTraceback (most recent call last):\n",
|
||||
stderr,
|
||||
)
|
||||
self.assertNotIn("some_instance", stderr)
|
||||
|
||||
def test_instance_does_not_exist(self):
|
||||
self.assertOutputs(
|
||||
files=dict(some_schema="{}"),
|
||||
argv=["-i", "nonexisting_instance", "some_schema"],
|
||||
|
||||
exit_code=1,
|
||||
stderr="""\
|
||||
'nonexisting_instance' does not exist.
|
||||
""",
|
||||
)
|
||||
|
||||
def test_instance_does_not_exist_pretty_output(self):
|
||||
self.assertOutputs(
|
||||
files=dict(some_schema="{}"),
|
||||
argv=[
|
||||
"--output", "pretty",
|
||||
"-i", "nonexisting_instance",
|
||||
"some_schema",
|
||||
],
|
||||
|
||||
exit_code=1,
|
||||
stderr="""\
|
||||
===[FileNotFoundError]===(nonexisting_instance)===
|
||||
|
||||
'nonexisting_instance' does not exist.
|
||||
-----------------------------
|
||||
""",
|
||||
)
|
||||
|
||||
def test_schema_does_not_exist(self):
|
||||
self.assertOutputs(
|
||||
argv=["nonexisting_schema"],
|
||||
|
||||
exit_code=1,
|
||||
stderr="'nonexisting_schema' does not exist.\n",
|
||||
)
|
||||
|
||||
def test_schema_does_not_exist_pretty_output(self):
|
||||
self.assertOutputs(
|
||||
argv=["--output", "pretty", "nonexisting_schema"],
|
||||
|
||||
exit_code=1,
|
||||
stderr="""\
|
||||
===[FileNotFoundError]===(nonexisting_schema)===
|
||||
|
||||
'nonexisting_schema' does not exist.
|
||||
-----------------------------
|
||||
""",
|
||||
)
|
||||
|
||||
def test_neither_instance_nor_schema_exist(self):
|
||||
self.assertOutputs(
|
||||
argv=["-i", "nonexisting_instance", "nonexisting_schema"],
|
||||
|
||||
exit_code=1,
|
||||
stderr="'nonexisting_schema' does not exist.\n",
|
||||
)
|
||||
|
||||
def test_neither_instance_nor_schema_exist_pretty_output(self):
|
||||
self.assertOutputs(
|
||||
argv=[
|
||||
"--output", "pretty",
|
||||
"-i", "nonexisting_instance",
|
||||
"nonexisting_schema",
|
||||
],
|
||||
|
||||
exit_code=1,
|
||||
stderr="""\
|
||||
===[FileNotFoundError]===(nonexisting_schema)===
|
||||
|
||||
'nonexisting_schema' does not exist.
|
||||
-----------------------------
|
||||
""",
|
||||
)
|
||||
|
||||
def test_successful_validation(self):
|
||||
self.assertOutputs(
|
||||
files=dict(some_schema="{}", some_instance="{}"),
|
||||
argv=["-i", "some_instance", "some_schema"],
|
||||
stdout="",
|
||||
stderr="",
|
||||
)
|
||||
|
||||
def test_successful_validation_pretty_output(self):
|
||||
self.assertOutputs(
|
||||
files=dict(some_schema="{}", some_instance="{}"),
|
||||
argv=["--output", "pretty", "-i", "some_instance", "some_schema"],
|
||||
stdout="===[SUCCESS]===(some_instance)===\n",
|
||||
stderr="",
|
||||
)
|
||||
|
||||
def test_successful_validation_of_stdin(self):
|
||||
self.assertOutputs(
|
||||
files=dict(some_schema="{}"),
|
||||
stdin=StringIO("{}"),
|
||||
argv=["some_schema"],
|
||||
stdout="",
|
||||
stderr="",
|
||||
)
|
||||
|
||||
def test_successful_validation_of_stdin_pretty_output(self):
|
||||
self.assertOutputs(
|
||||
files=dict(some_schema="{}"),
|
||||
stdin=StringIO("{}"),
|
||||
argv=["--output", "pretty", "some_schema"],
|
||||
stdout="===[SUCCESS]===(<stdin>)===\n",
|
||||
stderr="",
|
||||
)
|
||||
|
||||
def test_successful_validation_of_just_the_schema(self):
|
||||
self.assertOutputs(
|
||||
files=dict(some_schema="{}", some_instance="{}"),
|
||||
argv=["-i", "some_instance", "some_schema"],
|
||||
stdout="",
|
||||
stderr="",
|
||||
)
|
||||
|
||||
def test_successful_validation_of_just_the_schema_pretty_output(self):
|
||||
self.assertOutputs(
|
||||
files=dict(some_schema="{}", some_instance="{}"),
|
||||
argv=["--output", "pretty", "-i", "some_instance", "some_schema"],
|
||||
stdout="===[SUCCESS]===(some_instance)===\n",
|
||||
stderr="",
|
||||
)
|
||||
|
||||
def test_successful_validation_via_explicit_base_uri(self):
|
||||
ref_schema_file = tempfile.NamedTemporaryFile(delete=False) # noqa: SIM115
|
||||
ref_schema_file.close()
|
||||
self.addCleanup(os.remove, ref_schema_file.name)
|
||||
|
||||
ref_path = Path(ref_schema_file.name)
|
||||
ref_path.write_text('{"definitions": {"num": {"type": "integer"}}}')
|
||||
|
||||
schema = f'{{"$ref": "{ref_path.name}#/definitions/num"}}'
|
||||
|
||||
self.assertOutputs(
|
||||
files=dict(some_schema=schema, some_instance="1"),
|
||||
argv=[
|
||||
"-i", "some_instance",
|
||||
"--base-uri", ref_path.parent.as_uri() + "/",
|
||||
"some_schema",
|
||||
],
|
||||
stdout="",
|
||||
stderr="",
|
||||
)
|
||||
|
||||
def test_unsuccessful_validation_via_explicit_base_uri(self):
|
||||
ref_schema_file = tempfile.NamedTemporaryFile(delete=False) # noqa: SIM115
|
||||
ref_schema_file.close()
|
||||
self.addCleanup(os.remove, ref_schema_file.name)
|
||||
|
||||
ref_path = Path(ref_schema_file.name)
|
||||
ref_path.write_text('{"definitions": {"num": {"type": "integer"}}}')
|
||||
|
||||
schema = f'{{"$ref": "{ref_path.name}#/definitions/num"}}'
|
||||
|
||||
self.assertOutputs(
|
||||
files=dict(some_schema=schema, some_instance='"1"'),
|
||||
argv=[
|
||||
"-i", "some_instance",
|
||||
"--base-uri", ref_path.parent.as_uri() + "/",
|
||||
"some_schema",
|
||||
],
|
||||
exit_code=1,
|
||||
stdout="",
|
||||
stderr="1: '1' is not of type 'integer'\n",
|
||||
)
|
||||
|
||||
def test_nonexistent_file_with_explicit_base_uri(self):
|
||||
schema = '{"$ref": "someNonexistentFile.json#definitions/num"}'
|
||||
instance = "1"
|
||||
|
||||
with self.assertRaises(_RefResolutionError) as e:
|
||||
self.assertOutputs(
|
||||
files=dict(
|
||||
some_schema=schema,
|
||||
some_instance=instance,
|
||||
),
|
||||
argv=[
|
||||
"-i", "some_instance",
|
||||
"--base-uri", Path.cwd().as_uri(),
|
||||
"some_schema",
|
||||
],
|
||||
)
|
||||
error = str(e.exception)
|
||||
self.assertIn(f"{os.sep}someNonexistentFile.json'", error)
|
||||
|
||||
def test_invalid_explicit_base_uri(self):
|
||||
schema = '{"$ref": "foo.json#definitions/num"}'
|
||||
instance = "1"
|
||||
|
||||
with self.assertRaises(_RefResolutionError) as e:
|
||||
self.assertOutputs(
|
||||
files=dict(
|
||||
some_schema=schema,
|
||||
some_instance=instance,
|
||||
),
|
||||
argv=[
|
||||
"-i", "some_instance",
|
||||
"--base-uri", "not@UR1",
|
||||
"some_schema",
|
||||
],
|
||||
)
|
||||
error = str(e.exception)
|
||||
self.assertEqual(
|
||||
error, "unknown url type: 'foo.json'",
|
||||
)
|
||||
|
||||
def test_it_validates_using_the_latest_validator_when_unspecified(self):
|
||||
# There isn't a better way now I can think of to ensure that the
|
||||
# latest version was used, given that the call to validator_for
|
||||
# is hidden inside the CLI, so guard that that's the case, and
|
||||
# this test will have to be updated when versions change until
|
||||
# we can think of a better way to ensure this behavior.
|
||||
self.assertIs(Draft202012Validator, _LATEST_VERSION)
|
||||
|
||||
self.assertOutputs(
|
||||
files=dict(some_schema='{"const": "check"}', some_instance='"a"'),
|
||||
argv=["-i", "some_instance", "some_schema"],
|
||||
exit_code=1,
|
||||
stdout="",
|
||||
stderr="a: 'check' was expected\n",
|
||||
)
|
||||
|
||||
def test_it_validates_using_draft7_when_specified(self):
|
||||
"""
|
||||
Specifically, `const` validation applies for Draft 7.
|
||||
"""
|
||||
schema = """
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"const": "check"
|
||||
}
|
||||
"""
|
||||
instance = '"foo"'
|
||||
self.assertOutputs(
|
||||
files=dict(some_schema=schema, some_instance=instance),
|
||||
argv=["-i", "some_instance", "some_schema"],
|
||||
exit_code=1,
|
||||
stdout="",
|
||||
stderr="foo: 'check' was expected\n",
|
||||
)
|
||||
|
||||
def test_it_validates_using_draft4_when_specified(self):
|
||||
"""
|
||||
Specifically, `const` validation *does not* apply for Draft 4.
|
||||
"""
|
||||
schema = """
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"const": "check"
|
||||
}
|
||||
"""
|
||||
instance = '"foo"'
|
||||
self.assertOutputs(
|
||||
files=dict(some_schema=schema, some_instance=instance),
|
||||
argv=["-i", "some_instance", "some_schema"],
|
||||
stdout="",
|
||||
stderr="",
|
||||
)
|
||||
|
||||
|
||||
class TestParser(TestCase):
|
||||
|
||||
FakeValidator = fake_validator()
|
||||
|
||||
def test_find_validator_by_fully_qualified_object_name(self):
|
||||
arguments = cli.parse_args(
|
||||
[
|
||||
"--validator",
|
||||
"jsonschema.tests.test_cli.TestParser.FakeValidator",
|
||||
"--instance", "mem://some/instance",
|
||||
"mem://some/schema",
|
||||
],
|
||||
)
|
||||
self.assertIs(arguments["validator"], self.FakeValidator)
|
||||
|
||||
def test_find_validator_in_jsonschema(self):
|
||||
arguments = cli.parse_args(
|
||||
[
|
||||
"--validator", "Draft4Validator",
|
||||
"--instance", "mem://some/instance",
|
||||
"mem://some/schema",
|
||||
],
|
||||
)
|
||||
self.assertIs(arguments["validator"], Draft4Validator)
|
||||
|
||||
def cli_output_for(self, *argv):
|
||||
stdout, stderr = StringIO(), StringIO()
|
||||
with redirect_stdout(stdout), redirect_stderr(stderr): # noqa: SIM117
|
||||
with self.assertRaises(SystemExit):
|
||||
cli.parse_args(argv)
|
||||
return stdout.getvalue(), stderr.getvalue()
|
||||
|
||||
def test_unknown_output(self):
|
||||
stdout, stderr = self.cli_output_for(
|
||||
"--output", "foo",
|
||||
"mem://some/schema",
|
||||
)
|
||||
self.assertIn("invalid choice: 'foo'", stderr)
|
||||
self.assertFalse(stdout)
|
||||
|
||||
def test_useless_error_format(self):
|
||||
stdout, stderr = self.cli_output_for(
|
||||
"--output", "pretty",
|
||||
"--error-format", "foo",
|
||||
"mem://some/schema",
|
||||
)
|
||||
self.assertIn(
|
||||
"--error-format can only be used with --output plain",
|
||||
stderr,
|
||||
)
|
||||
self.assertFalse(stdout)
|
||||
|
||||
|
||||
class TestCLIIntegration(TestCase):
|
||||
def test_license(self):
|
||||
our_metadata = metadata.metadata("jsonschema")
|
||||
self.assertEqual(our_metadata.get("License-Expression"), "MIT")
|
||||
|
||||
def test_version(self):
|
||||
version = subprocess.check_output(
|
||||
[sys.executable, "-W", "ignore", "-m", "jsonschema", "--version"],
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
version = version.decode("utf-8").strip()
|
||||
self.assertEqual(version, metadata.version("jsonschema"))
|
||||
|
||||
def test_no_arguments_shows_usage_notes(self):
|
||||
output = subprocess.check_output(
|
||||
[sys.executable, "-m", "jsonschema"],
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
output_for_help = subprocess.check_output(
|
||||
[sys.executable, "-m", "jsonschema", "--help"],
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
self.assertEqual(output, output_for_help)
|
المرجع في مشكلة جديدة
حظر مستخدم