| 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 [] |
|
|
| @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: |
| 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): |
| |
| |
| |
| |
| |
| 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): |
| 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) |
|
|