def test_files_with_unicode_content_failing(self, tmpdir): """ These tests should fail with the specified exception """ # To trigger schema exception we must pass in a source file fail_data_2f_yaml = { 'schema': { 'type': 'map', 'mapping': { 'msg': { 'type': 'int', }, } }, 'data': { 'msg': 'Foobar', }, 'errors': ["Value 'Foobar' is not of type 'int'. Path: '/msg'"] } source_f = tmpdir.join(u"2få.json") source_f.write(yaml.safe_dump(fail_data_2f_yaml, allow_unicode=True)) _fail_tests = [ # Test mapping with unicode key and value but wrong type (u"1f.yaml", SchemaError), # Test unicode filename with validation errors. # It is not possible to package a file with unicode characters # like åäö in the filename in some python versions. # Mock a file with åäö during testing to properly simulate this again. (unicode(source_f), SchemaError), # Test unicode data inside seq but wrong type (u"3f.yaml", SchemaError), ] for failing_test, exception_type in _fail_tests: f = self.f(failing_test) with open(f, "r") as stream: yaml_data = yaml.load(stream) data = yaml_data["data"] schema = yaml_data["schema"] errors = yaml_data["errors"] try: print(u"Running test files: {0}".format(f)) c = Core(source_data=data, schema_data=schema) c.validate() except exception_type: pass # OK else: raise AssertionError( u"Exception {0} not raised as expected... FILES: {1} : {2}" .format(exception_type, exception_type)) compare(sorted(c.validation_errors), sorted(errors), prefix=u"Wrong validation errors when parsing files : {0}". format(f))
def test_files_with_unicode_content_success(self, tmpdir): """ These tests should pass with no exception raised """ fail_data_2s_yaml = { 'schema': { 'type': 'map', 'mapping': { 'msg': { 'type': 'int', }, } }, 'data': { 'msg': 123, }, 'errors': [] } source_f = tmpdir.join(u"2så.json") source_f.write(yaml.safe_dump(fail_data_2s_yaml, allow_unicode=True)) _pass_tests = [ # Test mapping with unicode key and value u"1s.yaml", # # Test unicode filename. # It is not possible to package a file with unicode characters # like åäö in the filename in some python versions. # Mock a file with åäö during testing to properly simulate this again. unicode(source_f), # Test sequence with unicode keys u"3s.yaml", ] for passing_test_files in _pass_tests: f = self.f(passing_test_files) with open(f, "r") as stream: yaml_data = yaml.load(stream) data = yaml_data["data"] schema = yaml_data["schema"] try: print(u"Running test files: {0}".format(f)) c = Core(source_data=data, schema_data=schema) c.validate() compare(c.validation_errors, [], prefix="No validation errors should exist...") except Exception as e: print(u"ERROR RUNNING FILES: {0}".format(f)) raise e # This serve as an extra schema validation that tests more complex structures then testrule.py do compare( c.root_rule.schema_str, schema, prefix= u"Parsed rules is not correct, something have changed... files : {0}" .format(f))
def test_cff_core_examples(): for root, dirs, files in os.walk("."): for file in files: if file.endswith(".cff"): filepath = os.path.join(root, file) c = Core(source_file=filepath, schema_files=["CFF-Core/schema.yaml"], yaml_extension="cff") c.validate(raise_exception=True)
def test_validation_error_but_not_raise_exception(self): """ Test that if 'raise_exception=False' when validating that no exception is raised. Currently file 2a.yaml & 2b.yaml is designed to cause exception. """ c = Core(source_file=self.f("cli", "2a.yaml"), schema_files=[self.f("cli", "2b.yaml")]) c.validate(raise_exception=False) assert c.validation_errors == [ "Value '1' is not of type 'str'. Path: '/0'", "Value '2' is not of type 'str'. Path: '/1'", "Value '3' is not of type 'str'. Path: '/2'" ]
def _validate(self): regexp = re.compile( "^cff-version: (['|\"])?(?P<semver>[\d\.]*)(['\"])?\s*$") for line in self.cffstr.split("\n"): matched = re.match(regexp, line) if matched is not None: semver = matched.groupdict()["semver"] schema_urls = { "1.0.1": "https://raw.githubusercontent.com/citation-file-format/schema/1.0.1/CFF-Core/schema.yaml", "1.0.2": "https://raw.githubusercontent.com/citation-file-format/schema/1.0.2/CFF-Core/schema.yaml", "1.0.3": "https://raw.githubusercontent.com/citation-file-format/schema/1.0.3/CFF-Core/schema.yaml", } print() r = requests.get(schema_urls[semver]) r.raise_for_status() self.schema = r.text with tempfile.TemporaryDirectory() as tmpdir: datafile = os.path.join(tmpdir, "data.yaml") schemafile = os.path.join(tmpdir, "schema.yaml") with open(datafile, "w") as f: f.write(self.cffstr) with open(schemafile, "w") as f: f.write(self.schema) c = Core(source_file=datafile, schema_files=[schemafile]) try: c.validate(raise_exception=True) except Exception as e: pass return self
def _validate(self): regexp = re.compile( "^cff-version: (['|\"])?(?P<semver>[\d\.]*)(['\"])?\s*$") semver = None for line in self.cffstr.split("\n"): matched = re.match(regexp, line) if matched is not None: semver = matched.groupdict()["semver"] break if semver is None: raise ValueError( "Unable to identify the schema version. Does the CFF include the 'cff-version' key?" ) schema_url = "https://raw.githubusercontent.com/citation-file-format/" +\ "schema/{0}/CFF-Core/schema.yaml".format(semver) r = requests.get(schema_url) r.raise_for_status() self.schema = r.text with tempfile.TemporaryDirectory() as tmpdir: datafile = os.path.join(tmpdir, "data.yaml") schemafile = os.path.join(tmpdir, "schema.yaml") with open(datafile, "w") as f: f.write(self.cffstr) with open(schemafile, "w") as f: f.write(self.schema) c = Core(source_file=datafile, schema_files=[schemafile]) try: c.validate(raise_exception=True) except Exception as e: pass return self
def test_core_files(self): # These tests should pass with no exception raised pass_tests = [ # All tests for keyword assert "test_assert.yaml", # All tests for keyword default "test_default.yaml", # All tests for keyword desc "test_desc.yaml", # All tests for keyword enum "test_enum.yaml", # All tests for keyword example "test_example.yaml", # All tests for keyword extensions "test_extensions.yaml", # All tests for keyword func "test_func.yaml", # All tests for keyword ident "test_ident.yaml", # All tests for keyword include "test_include.yaml", # All tests for keyword length "test_length.yaml", # All tests for keyword mapping "test_mapping.yaml", # All tests for keyword matching "test_matching.yaml", # All tests for keyword name "test_name.yaml", # All tests for keyword pattern "test_pattern.yaml", # All tests for keyword range "test_range.yaml", # All tests for keyword required "test_required.yaml", # All tests for keyword schema "test_schema.yaml", # All tests for keyword sequence "test_sequence.yaml", # All tests for keyword unique "test_unique.yaml", # All tests for keyword version "test_version.yaml", # All test cases for Multiple sequence checks "test_sequence_multi.yaml", # All test cases for merging "test_merge.yaml", # All test cases for yaml anchors "test_anchor.yaml", # All tests for TYPE: any "test_type_any.yaml", # All tests for TYPE: bool "test_type_bool.yaml", # All tests for TYPE: date "test_type_date.yaml", # All tests for TYPE: enum "test_type_enum.yaml", # All tests for TYPE: float "test_type_float.yaml", # All tests for TYPE: int "test_type_int.yaml", # All tests for TYPE: map "test_type_map.yaml", # All tests for TYPE: none "test_type_none.yaml", # All tests for TYPE: number "test_type_number.yaml", # All tests for TYPE: scalar "test_type_scalar.yaml", # All tests for TYPE: seq "test_type_seq.yaml", # All tests for TYPE: str "test_type_str.yaml", # All tests for TYPE: symbol "test_type_symbol.yaml", # All tests for TYPE: text "test_type_text.yaml", # All tests for TYPE: timestamp "test_type_timestamp.yaml", ] _fail_tests = [ # All tests for keyword assert ("test_assert.yaml", SchemaError), # All tests for keyword default ("test_default.yaml", SchemaError), # All tests for keyword desc ("test_desc.yaml", SchemaError), # All tests for keyword enum ("test_enum.yaml", SchemaError), # All tests for keyword example ("test_example.yaml", SchemaError), # All tests for keyword extensions ("test_extensions.yaml", SchemaError), # All tests for keyword func ("test_func.yaml", SchemaError), # All tests for keyword ident ("test_ident.yaml", SchemaError), # All tests for keyword include ("test_include.yaml", SchemaError), # All tests for keyword length ("test_length.yaml", SchemaError), # All tests for keyword mapping ("test_mapping.yaml", SchemaError), # All tests for keyword matching ("test_matching.yaml", SchemaError), # All tests for keyword name ("test_name.yaml", SchemaError), # All tests for keyword pattern ("test_pattern.yaml", SchemaError), # All tests for keyword range ("test_range.yaml", SchemaError), # All tests for keyword required ("test_required.yaml", SchemaError), # All tests for keyword schema ("test_schema.yaml", SchemaError), # All tests for keyword sequence ("test_sequence.yaml", SchemaError), # All tests for keyword unique ("test_unique.yaml", SchemaError), # All tests for keyword version ("test_version.yaml", SchemaError), # All test cases for Multiple sequence checks ("test_sequence_multi.yaml", SchemaError), # All test cases for merging ("test_merge.yaml", SchemaError), # All test cases for yaml anchors ("test_anchor.yaml", SchemaError), # All tests for TYPE: any ("test_type_any.yaml", SchemaError), # All tests for TYPE: bool ("test_type_bool.yaml", SchemaError), # All tests for TYPE: date ("test_type_date.yaml", SchemaError), # All tests for TYPE: float ("test_type_float.yaml", SchemaError), # All tests for TYPE: int ("test_type_int.yaml", SchemaError), # All tests for TYPE: map ("test_type_map.yaml", SchemaError), # All tests for TYPE: none ("test_type_none.yaml", SchemaError), # All tests for TYPE: number ("test_type_number.yaml", SchemaError), # All tests for TYPE: scalar ("test_type_scalar.yaml", SchemaError), # All tests for TYPE: seq ("test_type_seq.yaml", SchemaError), # All tests for TYPE: str ("test_type_str.yaml", SchemaError), # All tests for TYPE: symbol ("test_type_symbol.yaml", SchemaError), # All tests for TYPE: text ("test_type_text.yaml", SchemaError), # All tests for TYPE: timestamp ("test_type_timestamp.yaml", SchemaError), ] # Add override magic to make it easier to test a specific file if "S" in os.environ: pass_tests = [os.environ["S"]] _fail_tests = [] elif "F" in os.environ: pass_tests = [] _fail_tests = [(os.environ["F"], SchemaError)] for passing_test_file in pass_tests: f = self.f(os.path.join("success", passing_test_file)) with open(f, "r") as stream: yaml_data = yaml.load_all(stream) for document_index, document in enumerate(yaml_data): data = document["data"] schema = document["schema"] try: print("Running test files: {0}".format(f)) c = Core(source_data=data, schema_data=schema, strict_rule_validation=True, allow_assertions=True) c.validate() compare(c.validation_errors, [], prefix="No validation errors should exist...") except Exception as e: print("ERROR RUNNING FILES: {0} : {1}:{2}".format( f, document_index, document.get('name', 'UNKNOWN'))) raise e # This serve as an extra schema validation that tests more complex structures then testrule.py do compare( c.root_rule.schema_str, schema, prefix= "Parsed rules is not correct, something have changed... files : {0} : {1}" .format(f, document_index)) for failing_test, exception_type in _fail_tests: f = self.f(os.path.join("fail", failing_test)) with open(f, "r") as stream: yaml_data = yaml.load_all(stream) for document_index, document in enumerate(yaml_data): data = document["data"] schema = document["schema"] errors = document.get("errors", []) try: print("Running test files: {0}".format(f)) c = Core(source_data=data, schema_data=schema, strict_rule_validation=True, allow_assertions=True) c.validate() except exception_type as e: pass else: print("ERROR RUNNING FILES: {0} : {1}:{2}".format( f, document_index, document.get('name', 'UNKNOWN'))) raise AssertionError( "Exception {0} not raised as expected... FILES: {1} : {2} : {3}:{4}" .format(exception_type, exception_type, failing_test, document_index, document.get('name', 'UNKNOWN'))) compare( sorted(c.validation_errors), sorted(errors), prefix= "Wrong validation errors when parsing files : {0} : {1} : {2}" .format(f, document_index, document.get('name', 'UNKNOWN')))
def test_multi_file_support(self): """ This should test that multiple files is supported correctly """ pass_tests = [ # Test that include directive can be used at top level of the schema ([ self.f("partial_schemas", "1s-schema.yaml"), self.f("partial_schemas", "1s-partials.yaml"), ], self.f("partial_schemas", "1s-data.yaml"), { 'sequence': [{ 'include': 'fooone' }], 'type': 'seq', }), # # This test that include directive works inside sequence # ([self.f("33a.yaml"), self.f("33b.yaml")], self.f("33c.yaml"), {'sequence': [{'include': 'fooone'}], 'type': 'seq'}), # This test recursive schemas ([ self.f("partial_schemas", "2s-schema.yaml"), self.f("partial_schemas", "2s-partials.yaml"), ], self.f("partial_schemas", "2s-data.yaml"), { 'sequence': [{ 'include': 'fooone' }], 'type': 'seq', }), # This tests that you can include a partial schema alongside other rules in a map ([ self.f("partial_schemas", "7s-schema.yaml"), ], self.f("partial_schemas", "7s-data.yaml"), { 'type': 'map', 'mapping': { 'foo': { 'type': 'str', 'required': True }, 'bar': { 'include': 'bar' } } }) ] failing_tests = [ # Test include inside partial schema ([ self.f("partial_schemas", "1f-schema.yaml"), self.f("partial_schemas", "1f-partials.yaml") ], self.f("partial_schemas", "1f-data.yaml"), SchemaError, [ "Cannot find partial schema with name 'fooonez'. Existing partial schemas: 'bar, fooone, foothree, footwo'. Path: '/0'" ]), ([self.f('partial_schemas', '2f-schema.yaml')], self.f('partial_schemas', '2f-data.yaml'), SchemaError, ["Value 'True' is not of type 'str'. Path: '/0'"]), ([self.f('partial_schemas', '3f-schema.yaml')], self.f('partial_schemas', '3f-data.yaml'), SchemaError, ["Value 'True' is not of type 'str'. Path: ''"]), ([self.f('partial_schemas', '4f-schema.yaml')], self.f('partial_schemas', '4f-data.yaml'), SchemaError, ["Value 'True' is not of type 'str'. Path: '/0/foo/0/bar'"]), ([self.f('partial_schemas', '5f-schema.yaml')], self.f('partial_schemas', '5f-data.yaml'), SchemaError, ["Value 'True' is not of type 'str'. Path: '/0/0/0/0'"]), ([self.f('partial_schemas', '6f-schema.yaml')], self.f('partial_schemas', '6f-data.yaml'), SchemaError, ["Value 'True' is not of type 'str'. Path: '/foo/bar/qwe/ewq'"]) ] for passing_test in pass_tests: try: c = Core(source_file=passing_test[1], schema_files=passing_test[0]) c.validate() compare(c.validation_errors, [], prefix="No validation errors should exist...") except Exception as e: print("ERROR RUNNING FILE: {0} : {1}".format( passing_test[0], passing_test[1])) raise e # This serve as an extra schema validation that tests more complex structures then testrule.py do compare( c.root_rule.schema_str, passing_test[2], prefix="Parsed rules is not correct, something have changed..." ) for failing_test in failing_tests: with pytest.raises(failing_test[2], msg="Test files: {0} : {1}".format( ", ".join(failing_test[0]), failing_test[1])): c = Core(schema_files=failing_test[0], source_file=failing_test[1]) c.validate() if not c.validation_errors: raise AssertionError("No validation_errors was raised...") compare( sorted(c.validation_errors), sorted(failing_test[3]), prefix="Wrong validation errors when parsing files : {0} : {1}" .format( failing_test[0], failing_test[1], ), )