From 4a65df50c8111763ee7dcd0be1125b91dd965701 Mon Sep 17 00:00:00 2001 From: "John N. Milner" Date: Tue, 13 Feb 2018 22:27:37 -0500 Subject: [PATCH 1/3] Switch to pytest; warn against `./manage.py test` --- .travis.yml | 2 +- dependencies/pip/external_services.txt | 2 +- dependencies/pip/requirements.txt | 2 +- kobo/settings.py | 6 ++++++ pytest.ini | 2 ++ 5 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 pytest.ini diff --git a/.travis.yml b/.travis.yml index ada78945b6..4e296e8ae4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ before_script: script: - gulp copy - npm run build - - coverage run --source='hub,kpi,kobo' --omit='*/tests/*,*/migrations/*,*/management/commands/*' manage.py test + - coverage run --source='hub,kpi,kobo' --omit='*/tests/*,*/migrations/*,*/management/commands/*' pytest - npm run test after_script: - coverage xml && python-codacy-coverage -r coverage.xml diff --git a/dependencies/pip/external_services.txt b/dependencies/pip/external_services.txt index 5c8c12f994..fe290abbd3 100644 --- a/dependencies/pip/external_services.txt +++ b/dependencies/pip/external_services.txt @@ -72,7 +72,7 @@ pygments==2.1.3 pymongo==3.3.0 pyopenssl==16.1.0 pyquery==1.4.0 -pytest-django==3.0.0 +pytest-django==3.1.2 pytest==3.0.3 # via pytest-django python-dateutil==2.6.0 python-digest==1.7 diff --git a/dependencies/pip/requirements.txt b/dependencies/pip/requirements.txt index a13fdce872..9505bfc1c6 100644 --- a/dependencies/pip/requirements.txt +++ b/dependencies/pip/requirements.txt @@ -70,7 +70,7 @@ pygments==2.1.3 pymongo==3.3.0 pyopenssl==16.1.0 pyquery==1.4.0 -pytest-django==3.0.0 +pytest-django==3.1.2 pytest==3.0.3 # via pytest-django python-dateutil==2.6.0 python-digest==1.7 diff --git a/kobo/settings.py b/kobo/settings.py index e4d678da75..4e7a79198f 100644 --- a/kobo/settings.py +++ b/kobo/settings.py @@ -107,6 +107,12 @@ 'hub.middleware.OtherFormBuilderRedirectMiddleware', ) +# Warn developers to use `pytest` instead of `./manage.py test` +class DoNotUseRunner(object): + def __init__(self, *args, **kwargs): + raise NotImplementedError('Please run tests with `pytest` instead') +TEST_RUNNER = __name__ + '.DoNotUseRunner' + # used in kpi.models.sitewide_messages MARKITUP_FILTER = ('markdown.markdown', {'safe_mode': False}) diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000000..c28205b2db --- /dev/null +++ b/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +testpaths = kobo kpi From 653a5cf41e11efaabbcf905c605b400824781826 Mon Sep 17 00:00:00 2001 From: "John N. Milner" Date: Tue, 13 Feb 2018 23:41:51 -0500 Subject: [PATCH 2/3] Gracefully handle missing translations in matrixes Fixes #1565 --- kpi/tests/test_asset_content.py | 119 ++++++++++++++++-- .../kobomatrix_handler.py | 13 +- 2 files changed, 115 insertions(+), 17 deletions(-) diff --git a/kpi/tests/test_asset_content.py b/kpi/tests/test_asset_content.py index b4c0d0c099..73bdd9c13d 100644 --- a/kpi/tests/test_asset_content.py +++ b/kpi/tests/test_asset_content.py @@ -490,6 +490,47 @@ def kobomatrix_content_with_custom_fields(): return _content +def reverse_str(s): + return ''.join(reversed(s)) + + +def kobomatrix_content_with_translations(): + _content = kobomatrix_content() + for _s in ['survey', 'choices']: + _sheet = _content[_s] + for _row in _sheet: + try: + _label = _row['label'] + except KeyError: + continue + _row['label::English'] = _label + _row['label::' + reverse_str('English')] = reverse_str(_label) + del _row['label'] + return _content + + +def kobomatrix_content_with_missing_translations(): + _content = kobomatrix_content_with_translations() + for _s in ['survey', 'choices']: + _sheet = _content[_s] + found_first_translation = False + for _row in _sheet: + try: + _label = _row['label::English'] + except KeyError: + continue + if not found_first_translation: + # leave the first translation alone + found_first_translation = True + continue + _row['label::' + reverse_str('English')] = None + return _content + + +def _span_display_none(item): + return '{}'.format(item) + + def test_kobomatrix_content(): content = _compile_asset_content(kobomatrix_content()) pattern = ['w7', 'w1', 'w2', 'w2', 'w2', ''] @@ -557,29 +598,83 @@ def test_kobomatrix_content(): '**Number**', ] - def _span(item): - return '{}'.format(item) - assert _labls[7:11] == ['##### Car', - _span('car-Possess?'), - _span('car-Necessary?'), - _span('car-Number'), + _span_display_none('car-Possess?'), + _span_display_none('car-Necessary?'), + _span_display_none('car-Number'), ] assert _labls[13:17] == ['##### Bike', - _span('bike-Possess?'), - _span('bike-Necessary?'), - _span('bike-Number'), + _span_display_none('bike-Possess?'), + _span_display_none('bike-Necessary?'), + _span_display_none('bike-Number'), ] assert _labls[19:23] == ['##### TV', - _span('tv-Possess?'), - _span('tv-Necessary?'), - _span('tv-Number'), + _span_display_none('tv-Possess?'), + _span_display_none('tv-Necessary?'), + _span_display_none('tv-Number'), ] assert _reqds == [None, False, False, False, False, None] + ( [None, False, True, True, True, None] * 3 ) +def test_kobomatrix_labels_with_translations(): + content = _compile_asset_content( + kobomatrix_content_with_translations()) + labels = [r.get('label', [None]) for r in content['survey']] + + expected_labels = [ + '**It\xe9ms**', + '**Possess?**', + '**Necessary?**', + '**Number**' + ] + assert labels[1:5] == [[l, reverse_str(l)] for l in expected_labels] + + def _make_expected_labels(row): + labels = [['##### ' + row, '##### ' + reverse_str(row)]] + for col in ['Possess?', 'Necessary?', 'Number']: + labels.append([ + _span_display_none(row.lower() + '-' + col), + _span_display_none(row.lower() + '-' + reverse_str(col)) + ]) + return labels + + assert labels[7:11] == _make_expected_labels('Car') + assert labels[13:17] == _make_expected_labels('Bike') + assert labels[19:23] == _make_expected_labels('TV') + + +def test_kobomatrix_labels_with_missing_translations(): + content = _compile_asset_content( + kobomatrix_content_with_missing_translations()) + labels = [r.get('label', [None]) for r in content['survey']] + assert labels[1:5] == [ + ['**It\xe9ms**', '**sm\xe9tI**'], + ['**Possess?**', None], + ['**Necessary?**', None], + ['**Number**', None] + ] + assert labels[7:11] == [ + ['##### Car', '##### raC'], + [_span_display_none('car-Possess?'), None], + [_span_display_none('car-Necessary?'), None], + [_span_display_none('car-Number'), None] + ] + assert labels[13:17] == [ + ['##### Bike', None], + [_span_display_none('bike-Possess?'), None], + [_span_display_none('bike-Necessary?'), None], + [_span_display_none('bike-Number'), None] + ] + assert labels[19:23] == [ + ['##### TV', None], + [_span_display_none('tv-Possess?'), None], + [_span_display_none('tv-Necessary?'), None], + [_span_display_none('tv-Number'), None] + ] + + def test_xpath_fields_in_kobomatrix_are_preserved(): _content = kobomatrix_content_with_custom_fields() (r0, r1, r2, r3, r4) = _content['survey'] diff --git a/kpi/utils/xlsform_preprocessors/kobomatrix_handler.py b/kpi/utils/xlsform_preprocessors/kobomatrix_handler.py index c778ef0aa6..42dedebff0 100644 --- a/kpi/utils/xlsform_preprocessors/kobomatrix_handler.py +++ b/kpi/utils/xlsform_preprocessors/kobomatrix_handler.py @@ -112,7 +112,7 @@ def finish(self): def _format_all_labels(self, labels, template): return [ - template.format(_l) for _l in labels + template.format(_l) if _l is not None else None for _l in labels ] def _header(self, name, items_label, cols, @@ -173,13 +173,16 @@ def _make_row(col): _appearance.append('horizontal-compact') else: _appearance.append('no-label') + _labels = [] + for _label in col.get('label'): + if _label is not None: + _labels.append('-'.join([_item_name, _label])) + else: + _labels.append(None) out = {'type': _type, 'name': '_'.join([_base_name, col['name']]), 'appearance': ' '.join(_appearance), - 'label': self._format_all_labels([ - '-'.join([_item_name, _label]) - for _label in col.get('label') - ], self.span_wrap), + 'label': self._format_all_labels(_labels, self.span_wrap), 'required': col.get('required', False), } for key in ['relevant', 'constraint', 'required']: From d4d75618ede8155f75f5a812ad38771393aa5394 Mon Sep 17 00:00:00 2001 From: "John N. Milner" Date: Thu, 15 Feb 2018 12:19:31 -0500 Subject: [PATCH 3/3] Update Docker test script to use `pytest` --- docker/run_tests.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/run_tests.bash b/docker/run_tests.bash index dea6329a8a..e03b24ceb8 100755 --- a/docker/run_tests.bash +++ b/docker/run_tests.bash @@ -3,5 +3,5 @@ set -e source /etc/profile -python manage.py test +pytest npm run test