From 9fa237fbe0b86b3de1cd478492bc7e3ebefa0b69 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Thu, 13 Mar 2014 14:45:08 -0700 Subject: [PATCH 1/6] Write test for auto-validating manifest at root of repo --- pre_commit/clientlib/validate_manifest.py | 4 ++-- tests/clientlib/validate_manifest_test.py | 14 ++++++++++++++ tests/conftest.py | 10 ++++++++++ tests/git_test.py | 21 +-------------------- 4 files changed, 27 insertions(+), 22 deletions(-) create mode 100644 tests/conftest.py diff --git a/pre_commit/clientlib/validate_manifest.py b/pre_commit/clientlib/validate_manifest.py index 035114e3..8fe71480 100644 --- a/pre_commit/clientlib/validate_manifest.py +++ b/pre_commit/clientlib/validate_manifest.py @@ -8,6 +8,7 @@ import os.path import yaml import pre_commit.constants as C +from pre_commit import git class InvalidManifestError(ValueError): pass @@ -69,8 +70,7 @@ def run(argv): args = parser.parse_args(argv) if args.filename is None: - # TODO: filename = git.get_root() + C.MANIFEST_FILE - raise NotImplementedError + filename = os.path.join(git.get_root(), C.MANIFEST_FILE) else: filename = args.filename diff --git a/tests/clientlib/validate_manifest_test.py b/tests/clientlib/validate_manifest_test.py index 7996525d..cef68d70 100644 --- a/tests/clientlib/validate_manifest_test.py +++ b/tests/clientlib/validate_manifest_test.py @@ -3,7 +3,9 @@ import __builtin__ import jsonschema import pytest import mock +from plumbum import local +import pre_commit.constants as C from pre_commit.clientlib.validate_manifest import check_is_valid_manifest from pre_commit.clientlib.validate_manifest import InvalidManifestError from pre_commit.clientlib.validate_manifest import run @@ -48,6 +50,18 @@ def test_returns_0_for_valid_manifest(): assert ret == 0 +def test_uses_default_manifest_file_at_root_of_git(empty_git_dir): + local.path(C.MANIFEST_FILE).write(""" +hooks: + - + id: foo + name: Foo + entry: foo + """) + ret = run([]) + assert ret == 0 + + @pytest.mark.parametrize(('manifest', 'expected_exception_type'), ( ( """ diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 00000000..68613e1a --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,10 @@ + +import pytest +from plumbum import local + + +@pytest.yield_fixture +def empty_git_dir(tmpdir): + with local.cwd(tmpdir.strpath): + local['git']['init']() + yield tmpdir.strpath \ No newline at end of file diff --git a/tests/git_test.py b/tests/git_test.py index c566b1f3..cb0331e4 100644 --- a/tests/git_test.py +++ b/tests/git_test.py @@ -1,36 +1,17 @@ -import contextlib import os -import pytest from plumbum import local from pre_commit import git - -@contextlib.contextmanager -def in_dir(dir): - old_path = local.cwd.getpath() - local.cwd.chdir(dir) - try: - yield - finally: - local.cwd.chdir(old_path) - -@pytest.yield_fixture -def empty_git_dir(tmpdir): - with in_dir(tmpdir.strpath): - local['git']['init']() - yield tmpdir.strpath - - def test_get_root(empty_git_dir): assert git.get_root() == empty_git_dir foo = local.path('foo') foo.mkdir() - with in_dir(foo): + with local.cwd(foo): assert git.get_root() == empty_git_dir From 28857c9a741dc2488539f04b3a9584d1fa9be105 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Thu, 13 Mar 2014 15:47:02 -0700 Subject: [PATCH 2/6] Consolidated file validation --- pre_commit/clientlib/validate_base.py | 51 ++++++++++++++++++ pre_commit/clientlib/validate_manifest.py | 51 +++++++----------- pre_commit/constants.py | 2 +- tests/clientlib/validate_base_test.py | 63 +++++++++++++++++++++++ tests/clientlib/validate_manifest_test.py | 56 ++++++-------------- 5 files changed, 149 insertions(+), 74 deletions(-) create mode 100644 pre_commit/clientlib/validate_base.py create mode 100644 tests/clientlib/validate_base_test.py diff --git a/pre_commit/clientlib/validate_base.py b/pre_commit/clientlib/validate_base.py new file mode 100644 index 00000000..cef5eaec --- /dev/null +++ b/pre_commit/clientlib/validate_base.py @@ -0,0 +1,51 @@ + +import jsonschema +import jsonschema.exceptions +import os.path +import yaml + +from pre_commit import git + + +def get_validator( + default_filename, + json_schema, + exception_type, + additional_validation_strategy=lambda obj: None, +): + """Returns a function which will validate a yaml file for correctness + + Args: + default_filename - Default filename to look for if none is specified + json_schema - JSON schema to validate file with + exception_type - Error type to raise on failure + additional_validation_strategy - Strategy for additional validation of + the object read from the file. The function should either raise + exception_type on failure. + """ + + def validate(filename=None): + filename = filename or os.path.join(git.get_root(), default_filename) + + if not os.path.exists(filename): + raise exception_type('File {0} does not exist'.format(filename)) + + file_contents = open(filename, 'r').read() + + try: + obj = yaml.load(file_contents) + except Exception as e: + raise exception_type( + 'File {0} is not a valid yaml file'.format(filename), e, + ) + + try: + jsonschema.validate(obj, json_schema) + except jsonschema.exceptions.ValidationError as e: + raise exception_type( + 'File {0} is not a valid file'.format(filename), e, + ) + + additional_validation_strategy(obj) + + return validate \ No newline at end of file diff --git a/pre_commit/clientlib/validate_manifest.py b/pre_commit/clientlib/validate_manifest.py index 8fe71480..3dda7884 100644 --- a/pre_commit/clientlib/validate_manifest.py +++ b/pre_commit/clientlib/validate_manifest.py @@ -2,13 +2,9 @@ from __future__ import print_function import argparse -import jsonschema -import jsonschema.exceptions -import os.path -import yaml import pre_commit.constants as C -from pre_commit import git +from pre_commit.clientlib.validate_base import get_validator class InvalidManifestError(ValueError): pass @@ -38,12 +34,8 @@ MANIFEST_JSON_SCHEMA = { } -def check_is_valid_manifest(file_contents): - file_objects = yaml.load(file_contents) - - jsonschema.validate(file_objects, MANIFEST_JSON_SCHEMA) - - for hook_config in file_objects['hooks']: +def additional_manifest_check(obj): + for hook_config in obj['hooks']: language = hook_config.get('language') if language is not None and not any( @@ -58,6 +50,14 @@ def check_is_valid_manifest(file_contents): ) +validate_manifest = get_validator( + C.MANIFEST_FILE, + MANIFEST_JSON_SCHEMA, + InvalidManifestError, + additional_manifest_check, +) + + def run(argv): parser = argparse.ArgumentParser() parser.add_argument( @@ -69,29 +69,14 @@ def run(argv): ) args = parser.parse_args(argv) - if args.filename is None: - filename = os.path.join(git.get_root(), C.MANIFEST_FILE) - else: - filename = args.filename - - if not os.path.exists(filename): - print('File {0} does not exist'.format(filename)) - return 1 - - file_contents = open(filename, 'r').read() - try: - yaml.load(file_contents) - except Exception as e: - print('File {0} is not a valid yaml file'.format(filename)) - print(str(e)) - return 1 - - try: - check_is_valid_manifest(file_contents) - except (jsonschema.exceptions.ValidationError, InvalidManifestError) as e: - print('File {0} is not a valid manifest file'.format(filename)) - print(str(e)) + validate_manifest(args.filename) + except InvalidManifestError as e: + print(e.args[0]) + # If we have more than one exception argument print the stringified + # version + if len(e.args) > 1: + print(str(e.args[1])) return 1 return 0 \ No newline at end of file diff --git a/pre_commit/constants.py b/pre_commit/constants.py index ecf02bcf..a406fc22 100644 --- a/pre_commit/constants.py +++ b/pre_commit/constants.py @@ -1,5 +1,5 @@ -PRE_COMMIT_FILE = '.pre-commit-config.yaml' +CONFIG_FILE = '.pre-commit-config.yaml' PRE_COMMIT_DIR = '.pre-commit-files' diff --git a/tests/clientlib/validate_base_test.py b/tests/clientlib/validate_base_test.py new file mode 100644 index 00000000..0572430b --- /dev/null +++ b/tests/clientlib/validate_base_test.py @@ -0,0 +1,63 @@ + +import __builtin__ + +import os.path +import mock +import pytest + +from pre_commit import git +from pre_commit.clientlib.validate_base import get_validator + + +class AdditionalValidatorError(ValueError): pass + + +@pytest.fixture +def noop_validator(): + return get_validator('example_manifest.yaml', {}, ValueError) + + +@pytest.fixture +def array_validator(): + return get_validator('', {'type': 'array'}, ValueError) + + +@pytest.fixture +def additional_validator(): + def raises_always(obj): + raise AdditionalValidatorError + + return get_validator( + 'example_manifest.yaml', + {}, + ValueError, + additional_validation_strategy=raises_always, + ) + + +def test_raises_for_non_existent_file(noop_validator): + with pytest.raises(ValueError): + noop_validator('file_that_does_not_exist.yaml') + + +def test_raises_for_invalid_yaml_file(noop_validator): + with pytest.raises(ValueError): + noop_validator('tests/data/non_parseable_yaml_file.yaml') + + +def test_defaults_to_backup_filename(noop_validator): + with mock.patch.object(__builtin__, 'open', side_effect=open) as mock_open: + noop_validator() + mock_open.assert_called_once_with( + os.path.join(git.get_root(), 'example_manifest.yaml'), 'r', + ) + + +def test_raises_for_failing_schema(array_validator): + with pytest.raises(ValueError): + array_validator('tests/data/non_parseable_yaml_file.yaml') + + +def test_raises_when_additional_validation_fails(additional_validator): + with pytest.raises(AdditionalValidatorError): + additional_validator() \ No newline at end of file diff --git a/tests/clientlib/validate_manifest_test.py b/tests/clientlib/validate_manifest_test.py index cef68d70..b870ade1 100644 --- a/tests/clientlib/validate_manifest_test.py +++ b/tests/clientlib/validate_manifest_test.py @@ -1,14 +1,12 @@ import __builtin__ -import jsonschema import pytest import mock from plumbum import local import pre_commit.constants as C -from pre_commit.clientlib.validate_manifest import check_is_valid_manifest -from pre_commit.clientlib.validate_manifest import InvalidManifestError -from pre_commit.clientlib.validate_manifest import run +from pre_commit.clientlib.validate_manifest import run, InvalidManifestError, \ + additional_manifest_check @pytest.yield_fixture @@ -40,7 +38,7 @@ def test_returns_1_for_valid_yaml_file_but_invalid_manifest(print_mock): ret = run(['--filename', invalid_manifest]) assert ret == 1 print_mock.assert_any_call( - 'File {0} is not a valid manifest file'.format(invalid_manifest) + 'File {0} is not a valid file'.format(invalid_manifest) ) @@ -62,39 +60,17 @@ hooks: assert ret == 0 -@pytest.mark.parametrize(('manifest', 'expected_exception_type'), ( - ( - """ -hooks: - - - id: foo - entry: foo - """, - jsonschema.exceptions.ValidationError, - ), - ( - """ -hooks: - - - id: foo - name: Foo - language: Not a Language lol - entry: foo - """, - InvalidManifestError, - ), +def test_additional_manifest_check_raises_for_bad_language(): + with pytest.raises(InvalidManifestError): + additional_manifest_check( + {'hooks': [{'id': 'foo', 'language': 'not valid'}]} + ) + + +@pytest.mark.parametrize(('obj'), ( + {'hooks': [{}]}, + {'hooks': [{'language': 'python'}]}, + {'hooks': [{'language': 'python>2.6'}]}, )) -def test_check_invalid_manifests(manifest, expected_exception_type): - with pytest.raises(expected_exception_type): - check_is_valid_manifest(manifest) - - -def test_valid_manifest_is_valid(): - check_is_valid_manifest(""" -hooks: - - - id: foo - name: Foo - entry: foo - language: python>2.6 - """) +def test_additional_manifest_check_is_ok_with_missing_language(obj): + additional_manifest_check(obj) \ No newline at end of file From af7e23aae5eeb2503779efa858e57d7f22120360 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Thu, 13 Mar 2014 15:52:38 -0700 Subject: [PATCH 3/6] Add manifest file. --- manifest.yaml | 8 ++++++++ pre_commit/clientlib/validate_manifest.py | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 manifest.yaml diff --git a/manifest.yaml b/manifest.yaml new file mode 100644 index 00000000..77c0add8 --- /dev/null +++ b/manifest.yaml @@ -0,0 +1,8 @@ + +hooks: + - + id: validate_manifest + name: Validate Manifest + description: This validator validates a pre-commit hooks manifest file + entry: validate-manifest + language: python \ No newline at end of file diff --git a/pre_commit/clientlib/validate_manifest.py b/pre_commit/clientlib/validate_manifest.py index 3dda7884..188e292b 100644 --- a/pre_commit/clientlib/validate_manifest.py +++ b/pre_commit/clientlib/validate_manifest.py @@ -61,8 +61,8 @@ validate_manifest = get_validator( def run(argv): parser = argparse.ArgumentParser() parser.add_argument( - '--filename', - required=False, default=None, + 'filename', + nargs='?', default=None, help='Manifest filename. Defaults to {0} at root of git repo'.format( C.MANIFEST_FILE, ) From e5f4c6160875b13158598326a5f39cd333923ed5 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Thu, 13 Mar 2014 16:03:15 -0700 Subject: [PATCH 4/6] Remove unnecessary object level at top of manifest --- example_manifest.yaml | 48 +++++++++++------------ manifest.yaml | 13 +++--- pre_commit/clientlib/validate_manifest.py | 32 ++++++--------- tests/clientlib/validate_manifest_test.py | 27 ++++++------- 4 files changed, 54 insertions(+), 66 deletions(-) diff --git a/example_manifest.yaml b/example_manifest.yaml index 426b8545..53ef2801 100644 --- a/example_manifest.yaml +++ b/example_manifest.yaml @@ -1,31 +1,29 @@ # Hooks are set up as follows -# hooks: -# - -# id: hook_id -# name: 'Readable name' -# entry: my_hook_executable +# - +# id: hook_id +# name: 'Readable name' +# entry: my_hook_executable # -# # Optional -# description: 'Longer description of the hook' +# # Optional +# description: 'Longer description of the hook' # -# # Optional, for now 'python[optional version]', 'ruby #.#.#', 'node' -# language: 'python' +# # Optional, for now 'python[optional version]', 'ruby #.#.#', 'node' +# language: 'python' # -# # Optional, defaults to zero -# expected_return_value: 0 +# # Optional, defaults to zero +# expected_return_value: 0 -hooks: - - - id: my_hook - name: My Simple Hook - description: This is my simple hook that does blah - entry: my-simple-hook.py - language: python - expected_return_value: 0 - - - id: my_grep_based_hook - name: My Bash Based Hook - description: This is a hook that uses grep to validate some stuff - entry: ./my_grep_based_hook.sh - expected_return_value: 1 +- + id: my_hook + name: My Simple Hook + description: This is my simple hook that does blah + entry: my-simple-hook.py + language: python + expected_return_value: 0 +- + id: my_grep_based_hook + name: My Bash Based Hook + description: This is a hook that uses grep to validate some stuff + entry: ./my_grep_based_hook.sh + expected_return_value: 1 diff --git a/manifest.yaml b/manifest.yaml index 77c0add8..51509c59 100644 --- a/manifest.yaml +++ b/manifest.yaml @@ -1,8 +1,7 @@ -hooks: - - - id: validate_manifest - name: Validate Manifest - description: This validator validates a pre-commit hooks manifest file - entry: validate-manifest - language: python \ No newline at end of file +- + id: validate_manifest + name: Validate Manifest + description: This validator validates a pre-commit hooks manifest file + entry: validate-manifest + language: python \ No newline at end of file diff --git a/pre_commit/clientlib/validate_manifest.py b/pre_commit/clientlib/validate_manifest.py index 188e292b..7f11ff0c 100644 --- a/pre_commit/clientlib/validate_manifest.py +++ b/pre_commit/clientlib/validate_manifest.py @@ -11,31 +11,25 @@ class InvalidManifestError(ValueError): pass MANIFEST_JSON_SCHEMA = { - 'type': 'object', - 'properties': { - 'hooks': { - 'type': 'array', - 'minItems': 1, - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'name': {'type': 'string'}, - 'description': {'type': 'string'}, - 'entry': {'type': 'string'}, - 'language': {'type': 'string'}, - 'expected_return_value': {'type': 'number'}, - }, - 'required': ['id', 'name', 'entry'], - }, + 'type': 'array', + 'minItems': 1, + 'items': { + 'type': 'object', + 'properties': { + 'id': {'type': 'string'}, + 'name': {'type': 'string'}, + 'description': {'type': 'string'}, + 'entry': {'type': 'string'}, + 'language': {'type': 'string'}, + 'expected_return_value': {'type': 'number'}, }, + 'required': ['id', 'name', 'entry'], }, - 'required': ['hooks'], } def additional_manifest_check(obj): - for hook_config in obj['hooks']: + for hook_config in obj: language = hook_config.get('language') if language is not None and not any( diff --git a/tests/clientlib/validate_manifest_test.py b/tests/clientlib/validate_manifest_test.py index b870ade1..73a71035 100644 --- a/tests/clientlib/validate_manifest_test.py +++ b/tests/clientlib/validate_manifest_test.py @@ -17,7 +17,7 @@ def print_mock(): def test_run_returns_1_for_non_existent_module(print_mock): non_existent_filename = 'file_that_does_not_exist' - ret = run(['--filename', non_existent_filename]) + ret = run([non_existent_filename]) assert ret == 1 print_mock.assert_called_once_with( 'File {0} does not exist'.format(non_existent_filename), @@ -26,7 +26,7 @@ def test_run_returns_1_for_non_existent_module(print_mock): def test_run_returns_1_for_non_yaml_file(print_mock): non_parseable_filename = 'tests/data/non_parseable_yaml_file.yaml' - ret = run(['--filename', non_parseable_filename]) + ret = run([non_parseable_filename]) assert ret == 1 print_mock.assert_any_call( 'File {0} is not a valid yaml file'.format(non_parseable_filename), @@ -35,7 +35,7 @@ def test_run_returns_1_for_non_yaml_file(print_mock): def test_returns_1_for_valid_yaml_file_but_invalid_manifest(print_mock): invalid_manifest = 'tests/data/valid_yaml_but_invalid_manifest.yaml' - ret = run(['--filename', invalid_manifest]) + ret = run([invalid_manifest]) assert ret == 1 print_mock.assert_any_call( 'File {0} is not a valid file'.format(invalid_manifest) @@ -44,17 +44,16 @@ def test_returns_1_for_valid_yaml_file_but_invalid_manifest(print_mock): def test_returns_0_for_valid_manifest(): valid_manifest = 'example_manifest.yaml' - ret = run(['--filename', valid_manifest]) + ret = run([valid_manifest]) assert ret == 0 def test_uses_default_manifest_file_at_root_of_git(empty_git_dir): local.path(C.MANIFEST_FILE).write(""" -hooks: - - - id: foo - name: Foo - entry: foo +- + id: foo + name: Foo + entry: foo """) ret = run([]) assert ret == 0 @@ -62,15 +61,13 @@ hooks: def test_additional_manifest_check_raises_for_bad_language(): with pytest.raises(InvalidManifestError): - additional_manifest_check( - {'hooks': [{'id': 'foo', 'language': 'not valid'}]} - ) + additional_manifest_check([{'id': 'foo', 'language': 'not valid'}]) @pytest.mark.parametrize(('obj'), ( - {'hooks': [{}]}, - {'hooks': [{'language': 'python'}]}, - {'hooks': [{'language': 'python>2.6'}]}, + [{}], + [{'language': 'python'}], + [{'language': 'python>2.6'}], )) def test_additional_manifest_check_is_ok_with_missing_language(obj): additional_manifest_check(obj) \ No newline at end of file From 74923ef2524cfd5efdbfe0c1d44822e51a5f5eeb Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Thu, 13 Mar 2014 16:15:41 -0700 Subject: [PATCH 5/6] Updated tests for validate manifest --- tests/clientlib/validate_base_test.py | 6 ++- tests/clientlib/validate_manifest_test.py | 61 ++++------------------- tests/data/array_yaml_file.yaml | 2 + 3 files changed, 17 insertions(+), 52 deletions(-) create mode 100644 tests/data/array_yaml_file.yaml diff --git a/tests/clientlib/validate_base_test.py b/tests/clientlib/validate_base_test.py index 0572430b..5da0b110 100644 --- a/tests/clientlib/validate_base_test.py +++ b/tests/clientlib/validate_base_test.py @@ -55,7 +55,11 @@ def test_defaults_to_backup_filename(noop_validator): def test_raises_for_failing_schema(array_validator): with pytest.raises(ValueError): - array_validator('tests/data/non_parseable_yaml_file.yaml') + array_validator('tests/data/valid_yaml_but_invalid_manifest.yaml') + + +def test_passes_array_schema(array_validator): + array_validator('tests/data/array_yaml_file.yaml') def test_raises_when_additional_validation_fails(additional_validator): diff --git a/tests/clientlib/validate_manifest_test.py b/tests/clientlib/validate_manifest_test.py index 73a71035..7c941b0e 100644 --- a/tests/clientlib/validate_manifest_test.py +++ b/tests/clientlib/validate_manifest_test.py @@ -1,62 +1,21 @@ -import __builtin__ import pytest -import mock -from plumbum import local -import pre_commit.constants as C -from pre_commit.clientlib.validate_manifest import run, InvalidManifestError, \ - additional_manifest_check - - -@pytest.yield_fixture -def print_mock(): - with mock.patch.object(__builtin__, 'print', autospec=True) as print_mock_obj: - yield print_mock_obj - - -def test_run_returns_1_for_non_existent_module(print_mock): - non_existent_filename = 'file_that_does_not_exist' - ret = run([non_existent_filename]) - assert ret == 1 - print_mock.assert_called_once_with( - 'File {0} does not exist'.format(non_existent_filename), - ) - - -def test_run_returns_1_for_non_yaml_file(print_mock): - non_parseable_filename = 'tests/data/non_parseable_yaml_file.yaml' - ret = run([non_parseable_filename]) - assert ret == 1 - print_mock.assert_any_call( - 'File {0} is not a valid yaml file'.format(non_parseable_filename), - ) - - -def test_returns_1_for_valid_yaml_file_but_invalid_manifest(print_mock): - invalid_manifest = 'tests/data/valid_yaml_but_invalid_manifest.yaml' - ret = run([invalid_manifest]) - assert ret == 1 - print_mock.assert_any_call( - 'File {0} is not a valid file'.format(invalid_manifest) - ) +from pre_commit.clientlib.validate_manifest import additional_manifest_check +from pre_commit.clientlib.validate_manifest import InvalidManifestError +from pre_commit.clientlib.validate_manifest import run def test_returns_0_for_valid_manifest(): - valid_manifest = 'example_manifest.yaml' - ret = run([valid_manifest]) - assert ret == 0 + assert run(['example_manifest.yaml']) == 0 -def test_uses_default_manifest_file_at_root_of_git(empty_git_dir): - local.path(C.MANIFEST_FILE).write(""" -- - id: foo - name: Foo - entry: foo - """) - ret = run([]) - assert ret == 0 +def test_returns_0_for_our_manifest(): + assert run([]) == 0 + + +def test_returns_1_for_failing(): + assert run(['tests/data/valid_yaml_but_invalid_manifest.yaml']) == 1 def test_additional_manifest_check_raises_for_bad_language(): diff --git a/tests/data/array_yaml_file.yaml b/tests/data/array_yaml_file.yaml new file mode 100644 index 00000000..f97ce0d8 --- /dev/null +++ b/tests/data/array_yaml_file.yaml @@ -0,0 +1,2 @@ +- foo +- bar \ No newline at end of file From fdf05b0fa93c350d2cd030e451b0e26ed7393209 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Thu, 13 Mar 2014 16:28:45 -0700 Subject: [PATCH 6/6] Add better tests for manifest json schema --- tests/clientlib/validate_manifest_test.py | 32 ++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/tests/clientlib/validate_manifest_test.py b/tests/clientlib/validate_manifest_test.py index 7c941b0e..1f15945b 100644 --- a/tests/clientlib/validate_manifest_test.py +++ b/tests/clientlib/validate_manifest_test.py @@ -1,8 +1,11 @@ +import jsonschema +import jsonschema.exceptions import pytest from pre_commit.clientlib.validate_manifest import additional_manifest_check from pre_commit.clientlib.validate_manifest import InvalidManifestError +from pre_commit.clientlib.validate_manifest import MANIFEST_JSON_SCHEMA from pre_commit.clientlib.validate_manifest import run @@ -29,4 +32,31 @@ def test_additional_manifest_check_raises_for_bad_language(): [{'language': 'python>2.6'}], )) def test_additional_manifest_check_is_ok_with_missing_language(obj): - additional_manifest_check(obj) \ No newline at end of file + additional_manifest_check(obj) + + +def is_valid_according_to_schema(obj, schema): + try: + jsonschema.validate(obj, schema) + return True + except jsonschema.exceptions.ValidationError: + return False + + +@pytest.mark.parametrize(('manifest_obj', 'expected'), ( + ([], False), + ([{'id': 'a', 'name': 'b', 'entry': 'c'}], True), + ( + [{ + 'id': 'a', + 'name': 'b', + 'entry': 'c', + 'language': 'python', + 'expected_return_value': 0, + }], + True, + ), +)) +def test_is_valid_according_to_schema(manifest_obj, expected): + ret = is_valid_according_to_schema(manifest_obj, MANIFEST_JSON_SCHEMA) + assert ret is expected \ No newline at end of file