diff --git a/stats/dashboard.py b/stats/dashboard.py index 8e16cf917b2..6cc2019201d 100644 --- a/stats/dashboard.py +++ b/stats/dashboard.py @@ -1242,8 +1242,17 @@ def humanitarian(self): return { 'is_humanitarian': is_humanitarian, 'is_humanitarian_by_attrib': is_humanitarian_by_attrib, - 'contains_humanitarian_scope': 1 if (self._version() in ['2.02', '2.03']) and self.element.xpath('humanitarian-scope/@type') and self.element.xpath('humanitarian-scope/@code') else 0, - 'uses_humanitarian_clusters_vocab': 1 if (self._version() in ['2.02', '2.03']) and self.element.xpath('sector/@vocabulary="10"') else 0 + 'contains_humanitarian_scope': 1 if ( + is_humanitarian and + self._version() in ['2.02', '2.03'] and + all_true_and_not_empty(self.element.xpath('humanitarian-scope/@type')) and + all_true_and_not_empty(self.element.xpath('humanitarian-scope/@code')) + ) else 0, + 'uses_humanitarian_clusters_vocab': 1 if ( + is_humanitarian and + self._version() in ['2.02', '2.03'] and + self.element.xpath('sector/@vocabulary="10"') + ) else 0 } def _transaction_type_code(self, transaction): diff --git a/stats/tests/test_humanitarian.py b/stats/tests/test_humanitarian.py index ceb3936b08c..fbb0c33b26e 100644 --- a/stats/tests/test_humanitarian.py +++ b/stats/tests/test_humanitarian.py @@ -569,14 +569,14 @@ def test_humanitarian_attrib_false_sector_false(version, hum_attrib_val_true, hu @pytest.mark.parametrize('hum_attrib_val', ['1', 'true']) def test_humanitarian_elements_valid_version(version, hum_attrib_val): """ - Tests that humanitarian elements are detected at supported versions. + Detect that an activity containing a humanitarian-scope element (with required non-empty attributes) counts as humanitarian. """ activity_stats = MockActivityStats(version) activity_stats.element = etree.fromstring(''' - + '''.format(hum_attrib_val)) @@ -597,7 +597,7 @@ def test_humanitarian_elements_invalid_version(version, hum_attrib_val): activity_stats.element = etree.fromstring(''' - + '''.format(version, hum_attrib_val)) @@ -608,77 +608,160 @@ def test_humanitarian_elements_invalid_version(version, hum_attrib_val): @pytest.mark.parametrize('version', ['2.02', '2.03']) -def test_humanitarian_scope_valid(version): +@pytest.mark.parametrize('hum_attrib_val', ['1', 'true']) +def test_humanitarian_scope_invalid(version, hum_attrib_val): """ - Detect that an activity contains a humanitarian-scope element and required attributes. + Detect that even if an activity (at an expected version) contains a humanitarian-scope element, it must include the required attributes to count as humanitarian. """ activity_stats = MockActivityStats(version) activity_stats.element = etree.fromstring(''' - - + + - ''') - assert activity_stats.humanitarian()['contains_humanitarian_scope'] == 1 + '''.format(hum_attrib_val)) + assert activity_stats.humanitarian()['is_humanitarian'] == 1 + assert activity_stats.humanitarian()['contains_humanitarian_scope'] == 0 @pytest.mark.parametrize('version', ['2.02', '2.03']) -def test_humanitarian_scope_invalid(version): +@pytest.mark.parametrize('hum_attrib_val', ['1', 'true']) +def test_humanitarian_scope_invalid_empty_values(version, hum_attrib_val): """ - Detect that an activity contains a humanitarian-scope element without required attributes. + Detect that even if the humanitarian-scope (at an expected version) element is present (with required attributes), there must be non-empty data within the @type and @code attributes for it to count as humanitarian. """ activity_stats = MockActivityStats(version) activity_stats.element = etree.fromstring(''' - - + + + '''.format(hum_attrib_val)) + assert activity_stats.humanitarian()['is_humanitarian'] == 1 + assert activity_stats.humanitarian()['contains_humanitarian_scope'] == 0 + + +@pytest.mark.parametrize('version', ['1.01', '1.02', '1.03', '1.04', '1.05', '2.01', '2.02', '2.03', 'unknown version']) +def test_humanitarian_scope_but_not_humanitarian_no_attrib(version): + """ + Detect that even if an activity (of any version) contains the humanitarian-scope element, the humanitarian attribute must be present and marked as true to count. + """ + + activity_stats = MockActivityStats(version) + + activity_stats.element = etree.fromstring(''' + + + ''') + + assert activity_stats.humanitarian()['is_humanitarian'] == 0 + assert activity_stats.humanitarian()['is_humanitarian_by_attrib'] == 0 + assert activity_stats.humanitarian()['contains_humanitarian_scope'] == 0 + assert activity_stats.humanitarian()['uses_humanitarian_clusters_vocab'] == 0 + + +@pytest.mark.parametrize('version', ['1.01', '1.02', '1.03', '1.04', '1.05', '2.01', '2.02', '2.03', 'unknown version']) +@pytest.mark.parametrize('hum_attrib_val_false', ['0', 'false', 'True', 'False', '']) +def test_humanitarian_scope_but_humanitarian_is_false(version, hum_attrib_val_false): + """ + Detect that even if an activity (at any version) contains a humanitarian-scope element, the humanitarian attribute must be present and marked as true to count. + """ + + activity_stats = MockActivityStats(version) + + activity_stats.element = etree.fromstring(''' + + + + '''.format(hum_attrib_val_false)) + + assert activity_stats.humanitarian()['is_humanitarian'] == 0 + assert activity_stats.humanitarian()['is_humanitarian_by_attrib'] == 0 assert activity_stats.humanitarian()['contains_humanitarian_scope'] == 0 + assert activity_stats.humanitarian()['uses_humanitarian_clusters_vocab'] == 0 @pytest.mark.parametrize('version', ['2.02', '2.03']) -def test_humanitarian_clusters_valid(version): +@pytest.mark.parametrize('hum_attrib_val', ['1', 'true']) +def test_humanitarian_clusters_valid(version, hum_attrib_val): """ Detect that an activity contains a sector defined by the 'Humanitarian Global Clusters' sector vocabulary. """ activity_stats = MockActivityStats(version) + activity_stats.element = etree.fromstring(''' + + + + '''.format(hum_attrib_val)) + assert activity_stats.humanitarian()['is_humanitarian'] == 1 + assert activity_stats.humanitarian()['uses_humanitarian_clusters_vocab'] == 1 + + +@pytest.mark.parametrize('version', ['2.02', '2.03']) +def test_humanitarian_clusters_invalid_no_attrib(version): + """ + Detect that even if an activity contains a sector defined by the 'Humanitarian Global Clusters' sector vocabulary, the humanitarian attribute must be present and marked as true to count. + """ + activity_stats = MockActivityStats(version) + activity_stats.element = etree.fromstring(''' ''') - assert activity_stats.humanitarian()['uses_humanitarian_clusters_vocab'] == 1 + assert activity_stats.humanitarian()['is_humanitarian'] == 0 + assert activity_stats.humanitarian()['uses_humanitarian_clusters_vocab'] == 0 + + +@pytest.mark.parametrize('version', ['2.02', '2.03']) +@pytest.mark.parametrize('hum_attrib_val_false', ['0', 'false', 'True', 'False', '']) +def test_humanitarian_clusters_invalid_humanitarian_is_false(version, hum_attrib_val_false): + """ + Detect that even if an activity contains a sector defined by the 'Humanitarian Global Clusters' sector vocabulary, the humanitarian attribute must be present and marked as true to count. + """ + activity_stats = MockActivityStats(version) + + activity_stats.element = etree.fromstring(''' + + + + '''.format(hum_attrib_val_false)) + assert activity_stats.humanitarian()['is_humanitarian'] == 0 + assert activity_stats.humanitarian()['uses_humanitarian_clusters_vocab'] == 0 @pytest.mark.parametrize('version', ['1.01', '1.02', '1.03', '1.04', '1.05', '2.01', 'unknown version']) -def test_humanitarian_clusters_version_1(version): +@pytest.mark.parametrize('hum_attrib_val', ['1', 'true']) +def test_humanitarian_clusters_version_1(version, hum_attrib_val): """ Detect that a pre-2.02 activity containing a sector defined by the 'Humanitarian Global Clusters' sector vocabulary is not detected. """ activity_stats = MockActivityStats(version) activity_stats.element = etree.fromstring(''' - + - ''') + '''.format(hum_attrib_val)) + assert activity_stats.humanitarian()['is_humanitarian'] == 0 assert activity_stats.humanitarian()['uses_humanitarian_clusters_vocab'] == 0 @pytest.mark.parametrize('version', ['1.01', '1.02', '1.03', '1.04', '1.05', '2.01', '2.02', '2.03', 'unknown version']) +@pytest.mark.parametrize('hum_attrib_val', ['1', 'true']) @pytest.mark.parametrize('sector_vocabulary_code', ['', '1', 'internal vocabulary']) -def test_humanitarian_clusters_invalid(version, sector_vocabulary_code): +def test_humanitarian_clusters_invalid(version, hum_attrib_val, + sector_vocabulary_code): """ Detect that an activity does not contain a sector defined by the 'Humanitarian Global Clusters' sector vocabulary. """ activity_stats = MockActivityStats(version) activity_stats.element = etree.fromstring(''' - - + + - '''.format(sector_vocabulary_code)) + '''.format(hum_attrib_val, sector_vocabulary_code)) assert activity_stats.humanitarian()['uses_humanitarian_clusters_vocab'] == 0 -