aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/jsonschema/tests/test_cli.py
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/jsonschema/tests/test_cli.py')
-rw-r--r--.venv/lib/python3.12/site-packages/jsonschema/tests/test_cli.py907
1 files changed, 907 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/jsonschema/tests/test_cli.py b/.venv/lib/python3.12/site-packages/jsonschema/tests/test_cli.py
new file mode 100644
index 00000000..79d2a158
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/jsonschema/tests/test_cli.py
@@ -0,0 +1,907 @@
+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)
+ 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)
+ 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):
+ output = subprocess.check_output(
+ [sys.executable, "-m", "pip", "show", "jsonschema"],
+ stderr=subprocess.STDOUT,
+ )
+ self.assertIn(b"License: MIT", output)
+
+ 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)