-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
452 additions
and
441 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,94 +1,53 @@ | ||
from trove.derive._base import IndexcardDeriver | ||
from unittest import mock | ||
|
||
from tests import factories | ||
from ._inputs import DERIVER_TEST_INPUTS | ||
from ._inputs import DERIVER_TEST_DOCS | ||
|
||
|
||
class BaseIndexcardDeriverTest(SimpleTestCase): | ||
SHOULD_SKIP = object() # for deriver inputs that should be skipped | ||
|
||
####### override these things ####### | ||
|
||
# formatter key, as registered in setup.py | ||
deriver_iri = None | ||
class BaseIndexcardDeriverTest: | ||
|
||
# dictionary with the same keys as `DERIVER_TEST_INPUTS`, mapping to values | ||
# that `assert_formatter_outputs_equal` will understand | ||
expected_outputs: dict = {} | ||
####### | ||
# implement these things: | ||
|
||
def assert_formatter_outputs_equal(self, actual_output, expected_output): | ||
"""raise AssertionError if the two outputs aren't equal | ||
# a subclass of IndexcardDeriver | ||
deriver_class: type | ||
|
||
@param actual_output (str): return value of the formatter's `.format()` method | ||
@param expected_output: corresponding value from this class's `expected_outputs` dictionary | ||
""" | ||
raise NotImplementedError | ||
# dictionary with the same keys as `DERIVER_TEST_DOCS` and values that | ||
# are either `SHOULD_SKIP` (above) or strings that will be passed as | ||
# `expected_text` to `derived_texts_equal` | ||
expected_outputs: dict | ||
|
||
####### don't override anything else ####### | ||
# (optional override, for when equality isn't so easy) | ||
def derived_texts_equal(self, expected_text: str, actual_text: str) -> bool: | ||
return (expected_text == actual_text) | ||
|
||
@classmethod | ||
def setUpClass(cls): | ||
assert DERIVER_TEST_INPUTS.keys() == cls.expected_outputs.keys(), f'check the test class\'s `expected_outputs` matches {__name__}.DERIVER_TEST_INPUTS' | ||
####### | ||
# don't override anything else | ||
|
||
def setUp(self): | ||
pass | ||
def test_should_skip(self): | ||
for _input_key, _deriver, _expected_output in self._iter_test_cases(): | ||
self.assertEqual( | ||
bool(_expected_output is SHOULD_SKIP), | ||
_deriver.should_skip(), | ||
) | ||
|
||
def test_outputs_for_inputs(self): | ||
for _input_key, _expected_output in self.expected_outputs.items(): | ||
_input = DERIVER_TEST_INPUTS[_input_key] | ||
with self.subTest(input_key=_input_key): | ||
_actual_output = self._derive(_input) | ||
self.assertEqual(_expected_output, _actual_output) | ||
|
||
@pytest.fixture(scope='class') | ||
def source_config(self, source, formatter_test_input, class_scoped_django_db): | ||
return factories.SourceConfigFactory( | ||
label=formatter_test_input['source_config_label'], | ||
source=source, | ||
) | ||
|
||
@pytest.fixture(scope='class') | ||
def suid(self, source_config, formatter_test_input, class_scoped_django_db): | ||
return factories.SourceUniqueIdentifierFactory( | ||
id=formatter_test_input['suid_id'], | ||
identifier=formatter_test_input['suid_value'], | ||
source_config=source_config, | ||
) | ||
|
||
@pytest.fixture(scope='class') | ||
def normalized_datum(self, suid, source, formatter_test_input, class_scoped_django_db): | ||
return factories.NormalizedDataFactory( | ||
raw=factories.RawDatumFactory( | ||
**formatter_test_input['raw_datum_kwargs'], | ||
suid=suid, | ||
), | ||
**formatter_test_input['normalized_datum_kwargs'], | ||
source__source=source, | ||
) | ||
|
||
def test_formatter(self, formatter, normalized_datum, expected_output): | ||
actual_output = formatter.format(normalized_datum) | ||
self.assert_formatter_outputs_equal(actual_output, expected_output) | ||
def test_derive_card_as_text(self): | ||
for _input_key, _deriver, _expected_output in self._iter_test_cases(): | ||
if _expected_output is not SHOULD_SKIP: | ||
_output = _deriver.derive_card_as_text() | ||
self.assertTrue(self.derived_texts_equal(_expected_output, _output)) | ||
|
||
def test_save_formatted_records(self, normalized_datum, expected_output): | ||
saved_records = FormattedMetadataRecord.objects.save_formatted_records( | ||
suid=normalized_datum.raw.suid, | ||
record_formats=[self.deriver_iri], | ||
normalized_datum=normalized_datum, | ||
) | ||
if expected_output is None: | ||
assert len(saved_records) == 0 | ||
else: | ||
assert len(saved_records) == 1 | ||
actual_output = saved_records[0].formatted_metadata | ||
self.assert_formatter_outputs_equal(actual_output, expected_output) | ||
|
||
|
||
@pytest.fixture(scope='module', params=FORMATTER_TEST_INPUTS.keys()) | ||
def _test_key(request): | ||
return request.param | ||
|
||
|
||
@pytest.fixture(scope='module') | ||
def formatter_test_input(_test_key): | ||
return FORMATTER_TEST_INPUTS[_test_key] | ||
def _get_deriver(self, input_doc): | ||
_mock_indexcard_rdf = mock.Mock() | ||
_mock_indexcard_rdf.as_rdf_tripledict.return_value = input_doc | ||
return self.deriver_class(_mock_indexcard_rdf) | ||
|
||
def _iter_test_cases(self): | ||
for _input_key, _input_doc in DERIVER_TEST_DOCS.items(): | ||
_expected_output = self.expected_outputs.get(_input_key) | ||
if _expected_output is None: | ||
raise NotImplementedError(f'{self.__class__.__qualname__}.expected_outputs["{_input_key}"]') | ||
with self.subTest(input_key=_input_key): | ||
yield (_input_key, self._get_deriver(_input_doc), _expected_output) |
Oops, something went wrong.