def test_choose_content_to_display(content_variant_schema): schema = QuestionnaireSchema(content_variant_schema) answer_store = AnswerStore({}) answer_store.add_or_update(Answer(answer_id="age-answer", value="18")) metadata = {} block = schema.get_block("block1") section_id = schema.get_section_id_for_block_id(block["id"]) content_to_display = choose_content_to_display( schema.get_block("block1"), schema, metadata, answer_store, ListStore({}), Location(section_id=section_id, block_id=block["id"]), ) assert content_to_display[0]["title"] == "You are over 16" answer_store = AnswerStore({}) content_to_display = choose_content_to_display( schema.get_block("block1"), schema, metadata, answer_store, ListStore({}), Location(section_id=section_id, block_id=block["id"]), ) assert content_to_display[0]["title"] == "You are ageless"
def test_choose_question_to_display(question_variant_schema): schema = QuestionnaireSchema(question_variant_schema) answer_store = AnswerStore({}) answer_store.add_or_update(Answer(answer_id="when-answer", value="yes")) metadata = {} block = schema.get_block("block1") section_id = schema.get_section_id_for_block_id(block["id"]) question_to_display = choose_question_to_display( schema.get_block("block1"), schema, metadata, answer_store, ListStore({}), Location(section_id=section_id, block_id=block["id"]), ) assert question_to_display["title"] == "Question 1, Yes" answer_store = AnswerStore({}) question_to_display = choose_question_to_display( schema.get_block("block1"), schema, metadata, answer_store, ListStore({}), Location(section_id=section_id, block_id=block["id"]), ) assert question_to_display["title"] == "Question 1, No"
def test_transform_variants_with_question_variants(question_variant_schema): schema = QuestionnaireSchema(question_variant_schema) answer_store = AnswerStore({}) answer_store.add_or_update(Answer(answer_id="when-answer", value="no")) metadata = {} block = schema.get_block("block1") section_id = schema.get_section_id_for_block_id(block["id"]) transformed_block = transform_variants( block, schema, metadata, answer_store, ListStore({}), Location(section_id=section_id, block_id=block["id"]), ) compare_transformed_block(block, transformed_block, "Question 1, No") answer_store.add_or_update(Answer(answer_id="when-answer", value="yes")) transformed_block = transform_variants( block, schema, metadata, answer_store, ListStore({}), Location(section_id=section_id, block_id=block["id"]), ) compare_transformed_block(block, transformed_block, "Question 1, Yes")
def test_unique_id_generation(): """ Ensure that every id generated is unique per questionnaire. """ # Mock the app.data_model.list_store.random_string method to return duplicates. with patch( "app.data_model.list_store.random_string", side_effect=["first", "first", "second"], ): list_store = ListStore() # pylint: disable=protected-access list_store._lists["test"] = ListModel(name="test", items=["first"]) result = list_store._generate_identifier() assert result == "second"
def test_do_not_go_to_next_question_for_multiple_answers(self): # Given goto_rule = { "id": "next-question", "when": [ { "id": "my_answer", "condition": "equals", "value": "Yes" }, { "id": "my_other_answer", "condition": "equals", "value": "2" }, ], } answer_store = AnswerStore() answer_store.add_or_update(Answer(answer_id="my_answer", value="No")) current_location = Location(section_id="some-section", block_id="some-block") self.assertFalse( evaluate_goto( goto_rule=goto_rule, schema=get_schema(), metadata={}, answer_store=answer_store, list_store=ListStore(), current_location=current_location, ))
def fake_list_store(): serialised = [ {"name": "people", "primary_person": "abcdef", "items": ["abcdef", "xyzabc"]}, {"name": "pets", "items": ["tuvwxy"]}, ] return ListStore.deserialise(serialised)
def test_do_not_go_to_next_question_for_date_answer(self): goto_rule = { "id": "next-question", "when": [{ "id": "date-answer", "condition": "equals", "date_comparison": { "value": "2018-01" }, }], } answer_store = AnswerStore({}) answer_store.add_or_update( Answer(answer_id="date-answer", value="2018-02-01")) current_location = Location(section_id="some-section", block_id="some-block") self.assertFalse( evaluate_goto( goto_rule=goto_rule, schema=get_schema_mock(), metadata={}, answer_store=answer_store, list_store=ListStore(), current_location=current_location, ))
def setUp(self): super().setUp() self.schema = load_schema_from_name("test_section_summary") self.answer_store = AnswerStore() self.list_store = ListStore() self.progress_store = ProgressStore() self.block_type = "SectionSummary"
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_context_for_driving_question_summary_empty_list(): schema = load_schema_from_name("test_list_collector_driving_question") current_location = Location(block_id="summary", section_id="section") list_collector_summary_context = ListCollectorSummaryContext( DEFAULT_LANGUAGE_CODE, schema, AnswerStore([{"answer_id": "anyone-usually-live-at-answer", "value": "No"}]), ListStore(), ProgressStore(), {}, ) context = list_collector_summary_context.get_list_summaries(current_location) expected = [ { "add_link": "/questionnaire/anyone-usually-live-at/", "add_link_text": "Add someone to this household", "empty_list_text": "There are no householders", "title": "Household members", "list_name": "people", } ] assert context == expected
def _deserialise(self, data): json_data = json.loads(data, use_decimal=True) self.progress_store = ProgressStore(json_data.get("PROGRESS")) self.set_metadata(json_data.get("METADATA", {})) self.answer_store = AnswerStore(json_data.get("ANSWERS")) self.list_store = ListStore.deserialise(json_data.get("LISTS")) self.collection_metadata = json_data.get("COLLECTION_METADATA", {})
def test_meta_comparison_missing(self): # Given goto_rule = { "id": "next-question", "when": [{ "condition": "equals", "meta": "variant_flags.does_not_exist.does_not_exist", "value": True, }], } answer_store = AnswerStore() answer_store.add_or_update(Answer(answer_id="my_answer", value="Yes")) metadata = {"varient_flags": {"sexual_identity": True}} current_location = Location(section_id="some-section", block_id="some-block") self.assertFalse( evaluate_goto( goto_rule=goto_rule, schema=get_schema(), metadata=metadata, answer_store=answer_store, list_store=ListStore(), current_location=current_location, ))
def test_renders_text_plural_from_list(): renderer = PlaceholderRenderer(language="en", list_store=ListStore(), schema=Mock()) rendered_text = renderer.render_placeholder( { "text_plural": { "forms": { "one": "Yes, {number_of_people} person lives here", "other": "Yes, {number_of_people} people live here", }, "count": { "source": "list", "identifier": "household" }, }, "placeholders": [{ "placeholder": "number_of_people", "value": { "source": "list", "identifier": "household" }, }], }, None, ) assert rendered_text == "Yes, 0 people live here"
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_evaluate_goto_returns_true_when_answer_value_not_equals_any_match_values( self): goto = { "id": "next-question", "when": [{ "id": "my_answers", "condition": "not equals any", "values": ["answer1", "answer2"], }], } answer_store = AnswerStore() answer_store.add_or_update( Answer(answer_id="my_answers", value="answer3")) current_location = Location(section_id="some-section", block_id="some-block") self.assertTrue( evaluate_goto( goto_rule=goto, schema=get_schema(), metadata={}, answer_store=answer_store, list_store=ListStore(), current_location=current_location, ))
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_default_answers_not_present_when_not_answered( fake_questionnaire_store): """Test that default values aren't submitted downstream when an answer with a default value is not present in the answer store.""" schema = load_schema("test_view_submitted_response") answer_objects = [ { "answer_id": "test-currency", "value": "12" }, { "answer_id": "square-kilometres", "value": "345" }, { "answer_id": "test-decimal", "value": "67.89" }, ] fake_questionnaire_store.answer_store = AnswerStore(answer_objects) fake_questionnaire_store.list_store = ListStore() routing_path = [ RoutingPath(["radio", "test-number-block"], section_id="default-section") ] output = convert_answers(schema, fake_questionnaire_store, routing_path) data = json.loads(json.dumps(output["data"]["answers"], for_json=True)) answer_ids = {answer["answer_id"] for answer in data} assert "radio-answer" not in answer_ids
def test_should_not_go_to_next_question_when_second_condition_fails(self): # Given goto_rule = { "id": "next-question", "when": [ { "id": "my_answer", "condition": "equals", "value": "Yes" }, { "condition": "equals", "meta": "sexual_identity", "value": False }, ], } answer_store = AnswerStore() answer_store.add_or_update(Answer(answer_id="my_answer", value="Yes")) metadata = {"sexual_identity": True} current_location = Location(section_id="some-section", block_id="some-block") self.assertFalse( evaluate_goto( goto_rule=goto_rule, schema=get_schema(), metadata=metadata, answer_store=answer_store, list_store=ListStore(), current_location=current_location, ))
def test_list_source_count(): placeholder_list = [{ "placeholder": "number_of_people", "value": { "source": "list", "identifier": "people" }, }] list_store = ListStore() list_store.add_list_item("people") list_store.add_list_item("people") parser = PlaceholderParser(language="en", list_store=list_store) placeholders = parser(placeholder_list) assert placeholders["number_of_people"] == 2
def test_evaluate_goto_returns_false_when_checkbox_question_not_answered( self): goto_contains = { "id": "next-question", "when": [{ "id": "my_answers", "condition": "contains", "value": "answer1" }], } goto_not_contains = { "id": "next-question", "when": [{ "id": "my_answers", "condition": "not contains", "value": "answer1" }], } answer_store = AnswerStore() current_location = Location(section_id="some-section", block_id="some-block") self.assertFalse( evaluate_goto( goto_rule=goto_contains, schema=get_schema(), metadata={}, answer_store=answer_store, list_store=ListStore(), current_location=current_location, )) self.assertFalse( evaluate_goto( goto_rule=goto_not_contains, schema=get_schema(), metadata={}, answer_store=answer_store, list_store=ListStore(), current_location=current_location, ))
def __init__(self, storage, version=None): self._storage = storage if version is None: version = self.get_latest_version_number() self.version = version self._metadata = {} # self.metadata is a read-only view over self._metadata self.metadata = MappingProxyType(self._metadata) self.collection_metadata = {} self.list_store = ListStore() self.answer_store = AnswerStore() self.progress_store = ProgressStore() raw_data, version = self._storage.get_user_data() if raw_data: self._deserialise(raw_data) if version is not None: self.version = version
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 get_view_submission(schema): session_data = get_session_store().session_data if _is_submission_viewable(schema.json, session_data.submitted_time): submitted_data = current_app.eq["storage"].get_by_key( SubmittedResponse, session_data.tx_id ) if submitted_data: metadata_context = build_metadata_context_for_survey_completed(session_data) pepper = current_app.eq["secret_store"].get_secret_by_name( "EQ_SERVER_SIDE_STORAGE_ENCRYPTION_USER_PEPPER" ) encrypter = StorageEncryption( current_user.user_id, current_user.user_ik, pepper ) submitted_data = encrypter.decrypt_data(submitted_data.data) # for backwards compatibility # submitted data used to be base64 encoded before encryption try: submitted_data = base64url_decode(submitted_data.decode()).decode() except ValueError: pass submitted_data = json.loads(submitted_data) answer_store = AnswerStore(submitted_data.get("answers")) list_store = ListStore(submitted_data.get("lists")) progress_store = ProgressStore(submitted_data.get("progress")) metadata = submitted_data.get("metadata") language_code = get_session_store().session_data.language_code questionnaire_summary_context = QuestionnaireSummaryContext( language_code, schema, answer_store, list_store, progress_store, metadata, ) context = questionnaire_summary_context(answers_are_editable=False) return render_template( template="view-submission", metadata=metadata_context, content=context, survey_id=schema.json["survey_id"], ) return redirect(url_for("post_submission.get_thank_you"))
def test_transform_variants_list_collector(list_collector_variant_schema): schema = QuestionnaireSchema(list_collector_variant_schema) answer_store = AnswerStore({}) answer_store.add_or_update(Answer(answer_id="when-answer", value="no")) metadata = {} block = schema.get_block("block1") section_id = schema.get_section_id_for_block_id(block["id"]) transformed_block = transform_variants( block, schema, metadata, answer_store, ListStore({}), Location(section_id=section_id, block_id=block["id"]), ) compare_transformed_block(block["add_block"], transformed_block["add_block"], "Add, No") compare_transformed_block(block["remove_block"], transformed_block["remove_block"], "Remove, No") compare_transformed_block(block["edit_block"], transformed_block["edit_block"], "Edit, No") answer_store.add_or_update(Answer(answer_id="when-answer", value="yes")) transformed_block = transform_variants( block, schema, metadata, answer_store, ListStore({}), Location(section_id=section_id, block_id=block["id"]), ) compare_transformed_block(block["add_block"], transformed_block["add_block"], "Add, Yes") compare_transformed_block(block["remove_block"], transformed_block["remove_block"], "Remove, Yes") compare_transformed_block(block["edit_block"], transformed_block["edit_block"], "Edit, Yes")
def test_list_item_conversion_empty_list(fake_questionnaire_store): """ Test that the list store is populated with an empty list for lists which do not have answers yet.""" routing_path = [ RoutingPath( [ "list-collector", "next-interstitial", "another-list-collector-block", "group-summary", ], section_id="section-1", ) ] answer_objects = [ { "answer_id": "last-name", "value": "2", "list_item_id": "RfAGDc" }, { "answer_id": "anyone-else", "value": "No" }, { "answer_id": "another-anyone-else", "value": "No" }, { "answer_id": "extraneous-answer", "value": "Bad", "list_item_id": "123" }, ] fake_questionnaire_store.answer_store = AnswerStore(answer_objects) fake_questionnaire_store.list_store = ListStore() schema = load_schema("test_list_collector") output = convert_answers(schema, fake_questionnaire_store, routing_path) # Answers not on the routing path del answer_objects[0] del answer_objects[-1] data_dict = json.loads(json.dumps(output["data"]["answers"], for_json=True)) assert sorted(answer_objects, key=lambda x: x["answer_id"]) == sorted( data_dict, key=lambda x: x["answer_id"])
def test_delete_list_item_id_does_not_raise(): store = ListStore() store.add_list_item("people") try: store.delete_list_item("people", "123456") except ValueError: # Not necessary, but keeps it explicit. pytest.fail("Deleting a non-existant list item raised an error")
def test_full_routing_path_with_repeating_sections(self): schema = load_schema_from_name( "test_repeating_sections_with_hub_and_spoke") list_store = ListStore([{ "items": ["abc123", "123abc"], "name": "people", "primary_person": "abc123", }]) router = Router(schema, self.answer_store, list_store, self.progress_store, self.metadata) routing_path = router.full_routing_path() expected_path = [ RoutingPath( [ "primary-person-list-collector", "list-collector", "next-interstitial", "another-list-collector-block", "visitors-block", ], section_id="section", list_name=None, list_item_id=None, ), RoutingPath( [ "proxy", "date-of-birth", "confirm-dob", "sex", "personal-summary" ], section_id="personal-details-section", list_name="people", list_item_id="abc123", ), RoutingPath( [ "proxy", "date-of-birth", "confirm-dob", "sex", "personal-summary" ], section_id="personal-details-section", list_name="people", list_item_id="123abc", ), ] self.assertEqual(routing_path, expected_path)
def test_repr(): test_list = ListModel("people", ["primaryperson"], primary_person="primaryperson") serialised = [ { "name": "people", "primary_person": "primaryperson", "items": ["123", "primaryperson"], } ] list_store = ListStore.deserialise(serialised) assert "primary_person=primaryperson" in repr(test_list) assert "items=['primaryperson']" in repr(test_list) assert "primaryperson" in repr(list_store)
def setUp(self): super().setUp() self.schema = load_schema_from_name("test_summary") self.answer_store = AnswerStore() self.list_store = ListStore() self.progress_store = ProgressStore() self.block_type = "Summary" self.rendered_block = { "parent_id": "summary-group", "id": "summary", "type": "Summary", "collapsible": True, } self.current_location = Location(section_id="default-section", block_id="summary")
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, ))