diff --git a/requirements.txt b/requirements.txt index 44816cb..cf50894 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -e git+https://github.com/OpenDataServices/flatten-tool.git@v0.5.0#egg=flattentool --e git+https://github.com/OpenDataServices/lib-cove.git@e1a6132fecdc2000ed03d82da9c2cc4dae3bd442#egg=libcove +-e git+https://github.com/OpenDataServices/lib-cove.git@fe0ec370280e2986e6d47dff458a08313acceaef#egg=libcove -e . diff --git a/requirements_dev.txt b/requirements_dev.txt index 827c65e..213e078 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -1,5 +1,5 @@ -e git+https://github.com/OpenDataServices/flatten-tool.git@v0.5.0#egg=flattentool --e git+https://github.com/OpenDataServices/lib-cove.git@e1a6132fecdc2000ed03d82da9c2cc4dae3bd442#egg=libcove +-e git+https://github.com/OpenDataServices/lib-cove.git@fe0ec370280e2986e6d47dff458a08313acceaef#egg=libcove -e . pytest flake8 diff --git a/tests/test_api.py b/tests/test_api.py index 1da6aaa..6c33b9a 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -4,6 +4,42 @@ from libcovebods.api import bods_json_output +BADFILE_RESULTS = [ + ({'message': "'entityType' is missing but required. Check that the field is included and correctly spelled.", 'message_safe': 'entityType is missing but required. Check that the field is included and correctly spelled.', 'message_type': 'required', 'path_no_number': ''}, [{'path': '21'}]), # noqa + ({'message': "'exact' should be a number. Check that the value is not null, and doesn’t contain any characters other than 0-9 and dot ('.'). Number values should not be in quotes. ", 'message_safe': 'exact should be a number. Check that the value is not null, and doesn’t contain any characters other than 0-9 and dot (.). Number values should not be in quotes. ', 'message_type': 'number', 'path_no_number': 'interests/share/exact'}, [{'path': '16/interests/0/share/exact', 'value': 'not a number'}]), # noqa + ({'message': "'exclusiveMinimum' should be a JSON boolean, 'true' or 'false'.", 'message_safe': 'exclusiveMinimum should be a JSON boolean, true or false.', 'message_type': 'boolean', 'path_no_number': 'interests/share/exclusiveMinimum'}, [{'path': '19/interests/0/share/exclusiveMinimum', 'value': 'not a bool'}]), # noqa + ({'message': "'interestedParty' is missing but required. Check that the field is included and correctly spelled.", 'message_safe': 'interestedParty is missing but required. Check that the field is included and correctly spelled.', 'message_type': 'required', 'path_no_number': ''}, [{'path': '16'}, {'path': '17'}, {'path': '18'}, {'path': '19'}, {'path': '20'}]), # noqa + ({'message': "'interests' should be a JSON array. Check that value(s) appear within square brackets, [...]", 'message_safe': 'interests should be a JSON array. Check that value(s) appear within square brackets, [...]', 'message_type': 'array', 'path_no_number': 'interests'}, [{'path': '17/interests'}]), # noqa + ({'message': "'interests/0' should be a JSON object", 'message_safe': 'interests/0 should be a JSON object', 'message_type': 'object', 'path_no_number': 'interests'}, [{'path': '18/interests/0', 'value': 'not an object'}]), # noqa + ({'message': "'missingPersonType' is a dependency of 'missingPersonReason'", 'message_safe': ''missingPersonType' is a dependency of 'missingPersonReason'', 'message_type': 'dependencies', 'path_no_number': ''}, [{'path': '14'}]), # noqa + ({'message': "'motivation' contains an unrecognised value. Check the related codelist for allowed code values.", 'message_safe': 'motivation contains an unrecognised value. Check the related codelist for allowed code values.', 'message_type': 'enum', 'path_no_number': 'annotations/motivation'}, [{'path': '20/annotations/0/motivation', 'value': 'not on open list'}]), # noqa + ({'message': "'not a date' does not match '^([\\\\+-]?\\\\d{4}(?!\\\\d{2}\\x08))((-?)((0[1-9]|1[0-2])(\\\\3([12]\\\\d|0[1-9]|3[01]))?|W([0-4]\\\\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\\\\d|[12]\\\\d{2}|3([0-5]\\\\d|6[1-6])))([T\\\\s]((([01]\\\\d|2[0-3])((:?)[0-5]\\\\d)?|24\\\\:?00)([\\\\.,]\\\\d+(?!:))?)?(\\\\17[0-5]\\\\d([\\\\.,]\\\\d+)?)?([zZ]|([\\\\+-])([01]\\\\d|2[0-3]):?([0-5]\\\\d)?)?)?)?$'", 'message_safe': 'birthDate does not match the regex ^([\\+-]?\\d{4}(?!\\d{2}\x08))((-?)((0[1-9]|1[0-2])(\\3([12]\\d|0[1-9]|3[01]))?|W([0-4]\\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\\d|[12]\\d{2}|3([0-5]\\d|6[1-6])))([T\\s]((([01]\\d|2[0-3])((:?)[0-5]\\d)?|24\\:?00)([\\.,]\\d+(?!:))?)?(\\17[0-5]\\d([\\.,]\\d+)?)?([zZ]|([\\+-])([01]\\d|2[0-3]):?([0-5]\\d)?)?)?)?$', 'message_type': 'pattern', 'path_no_number': 'birthDate'}, [{'path': '12/birthDate', 'value': 'not a date'}]), # noqa + ({'message': "'personType' contains an unrecognised value. Check the related codelist for allowed code values.", 'message_safe': 'personType contains an unrecognised value. Check the related codelist for allowed code values.', 'message_type': 'enum', 'path_no_number': 'personType'}, [{'path': '11/personType', 'value': 'bad person type'}]), # noqa + ({'message': "'replacesStatements' should be a JSON array. Check that value(s) appear within square brackets, [...]", 'message_safe': 'replacesStatements should be a JSON array. Check that value(s) appear within square brackets, [...]', 'message_type': 'array', 'path_no_number': 'replacesStatements'}, [{'path': '9/replacesStatements', 'value': 'not an array'}]), # noqa + ({'message': "'statementID' is missing but required. Check that the field is included and correctly spelled.", 'message_safe': 'statementID is missing but required. Check that the field is included and correctly spelled.', 'message_type': 'required', 'path_no_number': ''}, [{'path': '2'}, {'path': '7'}, {'path': '8'}, {'path': '9'}, {'path': '10'}]), # noqa + ({'message': "'statementID' should be a string. Check that the value is not null, and has quotes at the start and end. Escape any quotes in the value with '\\'", 'message_safe': 'statementID should be a string. Check that the value is not null, and has quotes at the start and end. Escape any quotes in the value with \\', 'message_type': 'string', 'path_no_number': 'statementID'}, [{'path': '4/statementID', 'value': 100}]), # noqa + ({'message': "'statementType' contains an unrecognised value. Check the related codelist for allowed code values.", 'message_safe': 'statementType contains an unrecognised value. Check the related codelist for allowed code values.', 'message_type': 'enum', 'path_no_number': 'statementType'}, [{'path': '1/statementType', 'value': 'bad statement type'}, {'path': '3/statementType'}]), # noqa + ({'message': "'statementType' is missing but required. Check that the field is included and correctly spelled.", 'message_safe': 'statementType is missing but required. Check that the field is included and correctly spelled.', 'message_type': 'required', 'path_no_number': ''}, [{'path': '0'}]), # noqa + ({'message': "'subject' is missing but required. Check that the field is included and correctly spelled.", 'message_safe': 'subject is missing but required. Check that the field is included and correctly spelled.', 'message_type': 'required', 'path_no_number': ''}, [{'path': '16'}, {'path': '17'}, {'path': '18'}, {'path': '19'}, {'path': '20'}]), # noqa + ({'message': "'too long long long long long long long long long long long long long long long long' is too long", 'message_safe': 'replacesStatements/0 is too long. It should not exceed 64 characters.', 'message_type': 'maxLength', 'path_no_number': 'replacesStatements'}, [{'path': '8/replacesStatements/0', 'value': 'too long long long long long long long long long long long long long long long long'}]), # noqa + ({'message': "'tooshort' is too short", 'message_safe': 'replacesStatements/0 is too short. It should be at least 32 characters.', 'message_type': 'minLength', 'path_no_number': 'replacesStatements'}, [{'path': '7/replacesStatements/0', 'value': 'tooshort'}]), # noqa + ({'message': "'tooshort' is too short", 'message_safe': 'statementID is too short. It should be at least 32 characters.', 'message_type': 'minLength', 'path_no_number': 'statementID'}, [{'path': '5/statementID', 'value': 'tooshort'}]), # noqa + ({'message': '-1 is less than the minimum of 0', 'message_safe': 'minimum is too small. The minimum allowed value is 0.', 'message_type': 'minimum', 'path_no_number': 'interests/share/minimum'}, [{'path': '16/interests/0/share/minimum', 'value': -1}]), # noqa + ({'message': '101 is greater than the maximum of 100', 'message_safe': 'maximum is too large. The maximum allowed value is 100.', 'message_type': 'maximum', 'path_no_number': 'interests/share/maximum'}, [{'path': '16/interests/0/share/maximum', 'value': 101}]), # noqa + ({'message': 'Date is not in the correct format. The correct format is YYYY-MM-DD.', 'message_safe': 'Date is not in the correct format. The correct format is YYYY-MM-DD.', 'message_type': 'date', 'path_no_number': 'statementDate'}, [{'path': '10/statementDate', 'value': 'not a date'}]), # noqa + ({'message': 'Date is not in the correct format. The correct format is YYYY-MM-DDThh:mm:ssZ.', 'message_safe': 'Date is not in the correct format. The correct format is YYYY-MM-DDT00:00:00Z.', 'message_type': 'date-time', 'path_no_number': 'source/retrievedAt'}, [{'path': '13/source/retrievedAt', 'value': 'not a date-time'}]), # noqa + ({'message': 'Invalid uri found', 'message_safe': 'Invalid uri found', 'message_type': 'uri', 'path_no_number': 'uri'}, [{'path': '21/uri', 'value': 'not a uri'}]), # noqa + ({'message': "{'motivation': 'not on open list'} is not valid under any of the given schemas", 'message_safe': '{'motivation': 'not on open list'} is not valid under any of the given schemas', 'message_type': 'anyOf', 'path_no_number': 'annotations'}, [{'path': '20/annotations/0'}]), # noqa + ({'message': '{} is not valid under any of the given schemas', 'message_safe': '{} is not valid under any of the given schemas', 'message_type': 'anyOf', 'path_no_number': 'identifiers'}, [{'path': '15/identifiers/0'}]), # noqa +] + + +def unpack_validation_error(validation_error_result): + validation_error, data = validation_error_result + validation_error_data = json.loads(validation_error) + return validation_error_data, data + + def test_basic_1(): cove_temp_folder = tempfile.mkdtemp(prefix='lib-cove-bods-tests-', dir=tempfile.gettempdir()) @@ -153,11 +189,6 @@ def test_basic_statement_id_and_type_errors(): assert results['statistics']['count_ownership_or_control_statement_interested_party_with_person'] == 1 assert results['statistics']['count_ownership_or_control_statement_interested_party_with_entity'] == 0 - def unpack_validation_error(validation_error_result): - validation_error, data = validation_error_result - validation_error_data = json.loads(validation_error) - return validation_error_data, data - validation_error_data, data = unpack_validation_error(results['validation_errors'][0]) assert "'shortID' is too short" in validation_error_data['message'] assert data[0]['path'] == '1/statementID' @@ -168,12 +199,12 @@ def unpack_validation_error(validation_error_result): assert data[0]['path'] == '0' assert data[1]['path'] == '2' - validation_error_data, data = unpack_validation_error(results['validation_errors'][2]) + validation_error_data, data = unpack_validation_error(results['validation_errors'][3]) assert "'statementType' is missing but required" in validation_error_data['message'] assert data[0]['path'] == '3' - validation_error_data, data = unpack_validation_error(results['validation_errors'][3]) - assert "Invalid code found in 'statementType'" in validation_error_data['message'] + validation_error_data, data = unpack_validation_error(results['validation_errors'][2]) + assert "'statementType' contains an unrecognised value. Check the related codelist for allowed code values." in validation_error_data['message'] # noqa assert data[0]['path'] == '4/statementType' assert data[0]['value'] == 'test' @@ -374,3 +405,28 @@ def test_basic_bad_identifier_scheme(): assert results['additional_checks'][0]['type'] == 'entity_identifier_scheme_not_known' assert results['additional_checks'][0]['scheme'] == 'GB-COH-THIS-SCHEME-IS-NOT-REAL-I-JUST-MADE-IT-UP-MWAHAHAHAHA' assert results['additional_checks'][0]['entity_statement'] == '1dc0e987-5c57-4a1c-b3ad-61353b66a9b7' + + +def test_badfile_all_validation_errors(): + + cove_temp_folder = tempfile.mkdtemp(prefix='lib-cove-bods-tests-', dir=tempfile.gettempdir()) + json_filename = os.path.join(os.path.dirname( + os.path.realpath(__file__)), 'fixtures', 'api', 'badfile_all_validation_errors.json' + ) + + results = bods_json_output(cove_temp_folder, json_filename) + + assert results['validation_errors_count'] == 39 + assert results['additional_fields_count'] == 1 + assert results['additional_checks_count'] == 9 + assert results['file_type'] == 'json' + + for (i, (expected_error, expected_values)) in enumerate(BADFILE_RESULTS): + error, values = unpack_validation_error(results['validation_errors'][i]) + assert error['message'] == expected_error['message'] + assert error['message_safe'] == expected_error['message_safe'] + assert error['message_type'] == expected_error['message_type'] + assert error['path_no_number'] == expected_error['path_no_number'] + + for j, value in enumerate(expected_values): + assert value['path'] == expected_values[j]['path']