def test_evaluate_when_rule_raises_if_bad_when_condition(self): when = {"when": [{"condition": "not set"}]} answer_store = AnswerStore() with self.assertRaises(Exception): evaluate_when_rules( when["when"], get_schema(), {}, answer_store, ListStore(), None )
def test_routing_ignores_answers_not_on_path(self): when = { 'when': [{ 'id': 'some-answer', 'condition': 'equals', 'value': 'some value' }] } answer_store = AnswerStore({}) answer_store.add_or_update( Answer( answer_id='some-answer', value='some value', group_instance=0, )) routing_path = [Location('test', 0, 'test_block_id')] with patch('app.questionnaire.rules._get_answers_on_path', return_value=answer_store): self.assertTrue( evaluate_when_rules(when['when'], get_schema_mock(), {}, answer_store, 0, None)) with patch('app.questionnaire.rules._is_answer_on_path', return_value=False): self.assertFalse( evaluate_when_rules(when['when'], get_schema_mock(), {}, answer_store, 0, None, routing_path=routing_path))
def test_evaluate_when_rules_condition_is_not_met(self): # Given answer_1 = Answer( answer_id='my_answers', answer_instance=0, group_instance=0, value=10, ) answer_2 = Answer( answer_id='my_answers', answer_instance=1, group_instance=0, value=20, ) answer_store = AnswerStore({}) answer_store.add(answer_1) answer_store.add(answer_2) when = { 'id': 'next-question', 'when': [ { 'id': 'my_answers', 'condition': 'not set', 'value': '2' } ] } # When with self.assertRaises(Exception) as err: evaluate_when_rules(when['when'], get_schema_mock(), None, answer_store, 0) self.assertEqual('Multiple answers (2) found evaluating when rule for answer (my_answers)', str(err.exception))
def test_id_when_rule_uses_passed_in_group_instance_if_present(self): # pylint: disable=no-self-use when = [{'id': 'Some Id', 'group_instance': 0, 'condition': 'greater than', 'value': 0}] answer_store = AnswerStore({}) with patch('app.questionnaire.rules.get_answer_store_value', return_value=False) as patch_val: evaluate_when_rules(when, get_schema_mock(), {}, answer_store, 3) # passed in group instance ignored if present in when patch_val.assert_called_with('Some Id', answer_store, 0)
def test_id_when_rule_uses_passed_in_group_instance_if_present(self): when = [{ 'id': 'Some Id', 'group_instance': 0, 'condition': 'greater than', 'value': 0 }] answer_store = AnswerStore({}) with patch('app.questionnaire.rules.get_answer_store_value', return_value=False) as patch_val: evaluate_when_rules( when, get_schema_mock(), {}, answer_store, 3, None) # passed in group instance ignored if present in when self.assertEqual(patch_val.call_args[0][3], 0)
def test_primary_person_checks_location(self): answer_store = AnswerStore() list_store = ListStore(existing_items=[{ "name": "people", "primary_person": "abcdef", "items": ["abcdef", "12345"], }]) current_location = RelationshipLocation( section_id="some-section", block_id="some-block", list_item_id="abcdef", to_list_item_id="12345", ) when_rules = [{ "list": "people", "id_selector": "primary_person", "condition": "equals", "comparison": { "source": "location", "id": "list_item_id" }, }] self.assertTrue( evaluate_when_rules( when_rules=when_rules, schema=get_schema(), metadata={}, answer_store=answer_store, list_store=list_store, current_location=current_location, ))
def test_evaluate_when_rule_raises_exception_if_invalid(self): """If there isn't an id, meta key, or a type with value answer_count when attempting to get the value of the when condition, an exception is thrown""" when = { 'when': [{ 'type': 'answer_countinvalid', 'answer_ids': ['id'], 'condition': 'equals', 'value': 1, }] } answer_store = AnswerStore({}) with self.assertRaises(Exception) as err: evaluate_when_rules(when['when'], get_schema_mock(), {}, answer_store, 0, None) self.assertEqual('The when rule is invalid', str(err.exception))
def test_primary_person_returns_false_on_invalid_id(self): answer_store = AnswerStore() list_store = ListStore(existing_items=[{ "name": "people", "primary_person": "abcdef", "items": ["abcdef", "12345"], }]) current_location = Location(section_id="some-section", block_id="some-block") when_rules = [{ "list": "people", "id_selector": "primary_person", "condition": "equals", "comparison": { "source": "location", "id": "invalid-location-id" }, }] self.assertFalse( evaluate_when_rules( when_rules, get_schema(), {}, answer_store, list_store, current_location=current_location, ))
def test_answer_count_when_rule_equal_2(self): """Assert that an `answer_count` can be used in a when block and the value is correctly matched """ answer_group_id = 'repeated-answer' when = [{ 'type': 'answer_count', 'answer_ids': [answer_group_id], 'condition': 'equals', 'value': 2, }] answer_store = AnswerStore({}) answer_store.add_or_update( Answer( answer_id=answer_group_id, group_instance=0, group_instance_id='group-1-0', value=10, )) answer_store.add_or_update( Answer( answer_id=answer_group_id, group_instance=1, group_instance_id='group-1-1', value=20, )) self.assertTrue( evaluate_when_rules(when, get_schema_mock(), {}, answer_store, 0, None))
def test_evaluate_not_set_when_rules_should_return_true(self): when = {'when': [{'id': 'my_answers', 'condition': 'not set'}]} answer_store = AnswerStore({}) self.assertTrue( evaluate_when_rules(when['when'], get_schema_mock(), {}, answer_store, 0, None))
def test_evaluate_when_rule_with_invalid_list_item_id(self): when = { "when": [{ "id": "my_answer", "condition": "equals", "value": "an answer" }] } answer_store = AnswerStore() answer_store.add_or_update( Answer(answer_id="my_answer", value="an answer", list_item_id="abc123")) current_location = Location(section_id="some-section", block_id="some-block", list_item_id="123abc") schema = Mock(get_schema()) schema.get_list_item_id_for_answer_id = Mock(return_value="123abc") self.assertFalse( evaluate_when_rules( when_rules=when["when"], schema=schema, metadata={}, answer_store=answer_store, list_store=ListStore(), current_location=current_location, ))
def test_evaluate_when_rule_fetches_answer_using_list_item_id(self): when = { "when": [{"id": "my_answer", "condition": "equals", "value": "an answer"}] } list_item_id = "abc123" answer_store = AnswerStore() answer_store.add_or_update( Answer(answer_id="my_answer", value="an answer", list_item_id=list_item_id) ) current_location = Location( section_id="some-section", block_id="some-block", list_item_id=list_item_id ) schema = Mock(get_schema()) schema.is_repeating_answer = Mock(return_value=True) self.assertTrue( evaluate_when_rules( when_rules=when["when"], schema=schema, metadata={}, answer_store=answer_store, list_store=ListStore(), current_location=current_location, ) )
def test_when_rule_returns_first_item_in_list(self): answer_store = AnswerStore() list_store = ListStore( existing_items=[{"name": "people", "items": ["abcdef", "12345"]}] ) current_location = Location( section_id="some-section", block_id="some-block", list_name="people", list_item_id="abcdef", ) when_rules = [ { "list": "people", "id_selector": "first", "condition": "equals", "comparison": {"source": "location", "id": "list_item_id"}, } ] self.assertTrue( evaluate_when_rules( when_rules=when_rules, schema=get_schema(), metadata={}, answer_store=answer_store, list_store=list_store, current_location=current_location, ) )
def test_repeating_group_comparison_with_itself(self): """Assert that an `answer_count` can be used in a when block and the value is correctly matched """ answer_group_id = 'repeated-answer' when = [{ 'id': answer_group_id, 'condition': 'equals', 'comparison_id': 'other' }] answer_store = AnswerStore({}) answer_store.add_or_update( Answer( answer_id=answer_group_id, group_instance=0, group_instance_id='group-1-0', value=2, )) answer_store.add_or_update( Answer( answer_id=answer_group_id, group_instance=1, group_instance_id='group-1-1', value=20, )) answer_store.add_or_update( Answer( answer_id='other', group_instance=0, group_instance_id='group-1-0', value=0, )) answer_store.add_or_update( Answer( answer_id='other', group_instance=1, group_instance_id='group-1-1', value=20, )) self.assertTrue( evaluate_when_rules(when, get_schema_mock(), {}, answer_store, 1, 'group-1-1')) self.assertFalse( evaluate_when_rules(when, get_schema_mock(), {}, answer_store, 0, 'group-1-0'))
def test_routing_ignores_answers_not_on_path(self): when = { "when": [{ "id": "some-answer", "condition": "equals", "value": "some value" }] } answer_store = AnswerStore() answer_store.add_or_update( Answer(answer_id="some-answer", value="some value")) routing_path = [ Location(section_id="some-section", block_id="test_block_id") ] current_location = Location(section_id="some-section", block_id="some-block") self.assertTrue( evaluate_when_rules( when_rules=when["when"], schema=get_schema(), metadata={}, answer_store=answer_store, list_store=ListStore(), current_location=current_location, )) current_location = Location(section_id="some-section", block_id="some-block") with patch("app.questionnaire.rules._is_answer_on_path", return_value=False): self.assertFalse( evaluate_when_rules( when_rules=when["when"], schema=get_schema(), metadata={}, answer_store=answer_store, list_store=ListStore(), current_location=current_location, routing_path_block_ids=routing_path, ))
def test_evaluate_not_set_when_rules_should_return_true(self): when = { 'when': [ { 'id': 'my_answers', 'condition': 'not set' } ] } answer_store = AnswerStore() self.assertTrue(evaluate_when_rules(when, {}, answer_store, 0))
def test_id_when_rule_answer_count_equal_0(self): """Assert that an `answer_count` can be used in a when block and the correct value is fetched. """ answer_group_id = 'repeated-answer' when = [{ 'answer_count': answer_group_id, 'condition': 'equals', 'value': 0, }] answer_store = AnswerStore({}) self.assertTrue(evaluate_when_rules(when, get_schema_mock(), {}, answer_store, 0))
def test_answer_count_when_rule_not_equal(self): # pylint: disable=no-self-use """Assert that an `answer_count` can be used in a when block and the False is returned when the values do not match. """ answer_group_id = 'repeated-answer' when = [{ 'answer_count': answer_group_id, 'condition': 'equals', 'value': 1, }] answer_store = AnswerStore({}) self.assertFalse(evaluate_when_rules(when, get_schema_mock(), {}, answer_store, 0))
def _is_section_enabled(self, section): if "enabled" not in section: return True for condition in section["enabled"]: if evaluate_when_rules( condition["when"], self._schema, self._metadata, self._answer_store, self._list_store, ): return True return False
def test_answer_count_when_rule_not_equal(self): """Assert that an `answer_count` can be used in a when block and the False is returned when the values do not match. """ answer_group_id = 'repeated-answer' when = [{ 'type': 'answer_count', 'answer_ids': [answer_group_id], 'condition': 'equals', 'value': 1, }] answer_store = AnswerStore({}) self.assertFalse( evaluate_when_rules(when, get_schema_mock(), {}, answer_store, 0, None))
def test_evaluate_not_set_when_rules_should_return_true(self): when = {"when": [{"id": "my_answers", "condition": "not set"}]} answer_store = AnswerStore() current_location = Location(section_id="some-section", block_id="some-block") self.assertTrue( evaluate_when_rules( when_rules=when["when"], schema=get_schema(), metadata={}, answer_store=answer_store, list_store=ListStore(), current_location=current_location, ))
def get_title_from_titles(metadata, schema, answer_store, titles, group_instance, group_instance_id=None): """returns a title from titles available by evaluating the when rules , if all fail returns default""" for when, value in ((title['when'], title['value']) for title in titles if 'when' in title): if evaluate_when_rules(when, schema, metadata, answer_store, group_instance, group_instance_id=group_instance_id): return value return titles[-1]['value']
def test_list_rules_equals(self): answer_store = AnswerStore() list_store = ListStore(existing_items=[{"name": "people", "items": ["abcdef"]}]) when_rules = [{"list": "people", "condition": "equals", "value": 1}] current_location = Location(section_id="some-section", block_id="some-block") self.assertTrue( evaluate_when_rules( when_rules=when_rules, schema=get_schema(), metadata={}, answer_store=answer_store, list_store=list_store, current_location=current_location, ) )
def test_routing_answer_not_on_path_when_in_a_repeat(self): when = { "when": [ {"id": "some-answer", "condition": "equals", "value": "some value"} ] } answer_store = AnswerStore() answer = Answer(answer_id="some-answer", value="some value") answer_store.add_or_update(answer) routing_path = [ Location( section_id="some-section", block_id="test_block_id", list_name="people", list_item_id="abc123", ) ] current_location = Location( section_id="some-section", block_id="some-block", list_name="people", list_item_id="abc123", ) with patch( "app.questionnaire.rules.get_answer_for_answer_id", return_value=answer ): with patch( "app.questionnaire.rules._is_answer_on_path", return_value=False ): self.assertFalse( evaluate_when_rules( when_rules=when["when"], schema=get_schema(), metadata={}, answer_store=answer_store, list_store=ListStore(), current_location=current_location, routing_path_block_ids=routing_path, ) )
def test_answer_count_when_rule_id_takes_precident(self): """Assert that if somehow, both `id` and `answer_count` are present in a when clause the `id` takes precident and no errors are thrown. """ answer_group_id = 'repeated-answer' ref_id = 'just-a-regular-answer' when = [{ 'id': ref_id, 'answer_count': answer_group_id, 'condition': 'equals', 'value': 10, }] answer_store = AnswerStore({}) answer_store.add(Answer( answer_id=ref_id, group_instance=0, value=10, )) self.assertTrue(evaluate_when_rules(when, get_schema_mock(), {}, answer_store, 0))
def get_question(block_schema, answer_store, list_store, metadata, schema, location): """ Taking question variants into account, return the question which was displayed to the user """ list_item_id = location.list_item_id for variant in block_schema.get("question_variants", []): display_variant = evaluate_when_rules( variant.get("when"), schema, metadata, answer_store, list_store, location, ) if display_variant: return Question(variant["question"], answer_store, schema, list_item_id).serialize() return Question(block_schema["question"], answer_store, schema, list_item_id).serialize()
def test_answer_count_when_rule_equal_1(self): """Assert that an `answer_count` can be used in a when block and the correct value is fetched. """ answer_group_id = 'repeated-answer' when = [{ 'type': 'answer_count', 'answer_ids': [answer_group_id], 'condition': 'equals', 'value': 1, }] answer_store = AnswerStore({}) answer_store.add( Answer( answer_id=answer_group_id, group_instance=0, value=10, )) self.assertTrue( evaluate_when_rules(when, get_schema_mock(), {}, answer_store, 0, None))
def _choose_variant( block, schema, metadata, answer_store, list_store, variants_key, single_key, current_location, ): if block.get(single_key): return block[single_key] for variant in block.get(variants_key, []): when_rules = variant.get("when", []) if evaluate_when_rules( when_rules, schema, metadata, answer_store, list_store, current_location=current_location, ): return variant[single_key]
def test_when_rule_comparing_answer_values(self): answers = { "low": Answer(answer_id="low", value=1), "medium": Answer(answer_id="medium", value=5), "high": Answer(answer_id="high", value=10), "list_answer": Answer(answer_id="list_answer", value=["a", "abc", "cba"]), "other_list_answer": Answer(answer_id="other_list_answer", value=["x", "y", "z"]), "other_list_answer_2": Answer(answer_id="other_list_answer_2", value=["a", "abc", "cba"]), "text_answer": Answer(answer_id="small_string", value="abc"), "other_text_answer": Answer(answer_id="other_string", value="xyz"), } # An answer that won't be added to the answer store. missing_answer = Answer(answer_id="missing", value=1) param_list = [ (answers["medium"], "equals", answers["medium"], True), (answers["medium"], "equals", answers["low"], False), (answers["medium"], "greater than", answers["low"], True), (answers["medium"], "greater than", answers["high"], False), (answers["medium"], "less than", answers["high"], True), (answers["medium"], "less than", answers["low"], False), (answers["medium"], "equals", missing_answer, False), (answers["list_answer"], "contains", answers["text_answer"], True), (answers["list_answer"], "contains", answers["other_text_answer"], False), ( answers["list_answer"], "not contains", answers["other_text_answer"], True, ), (answers["list_answer"], "not contains", answers["text_answer"], False), ( answers["list_answer"], "contains any", answers["other_list_answer_2"], True, ), ( answers["list_answer"], "contains any", answers["other_list_answer"], False, ), ( answers["list_answer"], "contains all", answers["other_list_answer"], False, ), ( answers["list_answer"], "contains all", answers["other_list_answer_2"], True, ), (answers["text_answer"], "equals any", answers["list_answer"], True), (answers["text_answer"], "equals any", answers["other_list_answer"], False), ( answers["text_answer"], "not equals any", answers["other_list_answer"], True, ), (answers["text_answer"], "not equals any", answers["list_answer"], False), ] for lhs, comparison, rhs, expected_result in param_list: # Given with self.subTest(lhs=lhs, comparison=comparison, rhs=rhs, expected_result=expected_result): answer_store = AnswerStore() for answer in answers.values(): answer_store.add_or_update(answer) when = [{ "id": lhs.answer_id, "condition": comparison, "comparison": { "id": rhs.answer_id, "source": "answers" }, }] current_location = Location(section_id="some-section", block_id="some-block") self.assertEqual( evaluate_when_rules( when_rules=when, schema=get_schema(), metadata={}, answer_store=answer_store, list_store=ListStore(), current_location=current_location, routing_path_block_ids=None, ), expected_result, )
def test_evaluate_when_rule_raises_if_bad_when_condition(self): when = {'when': [{'condition': 'not set'}]} answer_store = AnswerStore({}) with self.assertRaises(Exception): evaluate_when_rules(when['when'], get_schema_mock(), {}, answer_store, 0, None)