def __init__(self, storage: EncryptedQuestionnaireStorage, version: Optional[int] = None): self._storage = storage if version is None: version = self.get_latest_version_number() self.version = version self._metadata: dict[str, Any] = {} # self.metadata is a read-only view over self._metadata self.metadata: Mapping[str, Any] = MappingProxyType(self._metadata) self.response_metadata: Mapping[str, Any] = {} self.list_store = ListStore() self.answer_store = AnswerStore() self.progress_store = ProgressStore() self.submitted_at: Optional[datetime] self.collection_exercise_sid: Optional[str] ( raw_data, self.collection_exercise_sid, version, self.submitted_at, ) = self._storage.get_user_data() if raw_data: self._deserialize(raw_data) if version is not None: self.version = version
def test_list_source_count_in_transform(): placeholder_list = [{ "placeholder": "number_of_people", "transforms": [{ "transform": "add", "arguments": { "lhs": { "source": "list", "identifier": "people" }, "rhs": { "value": 1 }, }, }], }] list_store = ListStore() 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_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_list_source_count_in_transform(mock_renderer): placeholder_list = [ { "placeholder": "number_of_people", "transforms": [ { "transform": "add", "arguments": { "lhs": { "source": "list", "identifier": "people", "selector": "count", }, "rhs": {"value": 1}, }, } ], } ] list_store = ListStore() list_store.add_list_item("people") parser = PlaceholderParser( language="en", answer_store=AnswerStore(), list_store=list_store, metadata={}, response_metadata={}, schema=QuestionnaireSchema({}), renderer=mock_renderer, ) placeholders = parser(placeholder_list) assert placeholders["number_of_people"] == 2
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_titles_for_repeating_section_summary(people_answer_store): schema = load_schema_from_name( "test_repeating_sections_with_hub_and_spoke") section_summary_context = SectionSummaryContext( DEFAULT_LANGUAGE_CODE, schema, people_answer_store, ListStore([ { "items": ["PlwgoG", "UHPLbX"], "name": "people" }, { "items": ["gTrlio"], "name": "visitors" }, ]), ProgressStore(), {}, current_location=Location( section_id="personal-details-section", list_name="people", list_item_id="PlwgoG", ), routing_path=MagicMock(), ) context = section_summary_context() assert context["summary"]["title"] == "Toni Morrison" section_summary_context = SectionSummaryContext( DEFAULT_LANGUAGE_CODE, schema, people_answer_store, ListStore([ { "items": ["PlwgoG", "UHPLbX"], "name": "people" }, { "items": ["gTrlio"], "name": "visitors" }, ]), ProgressStore(), {}, current_location=Location( block_id="personal-summary", section_id="personal-details-section", list_name="people", list_item_id="UHPLbX", ), routing_path=MagicMock(), ) context = section_summary_context() assert context["summary"]["title"] == "Barry Pheloung"
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 = {} response_metadata = {} block = schema.get_block("block1") section_id = schema.get_section_id_for_block_id(block["id"]) transformed_block = transform_variants( block, schema, metadata, response_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, response_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_unique_id_generation(): """ Ensure that every id generated is unique per questionnaire. """ # Mock the app.data_models.list_store.random_string method to return duplicates. with patch( "app.data_models.list_store.random_string", side_effect=["first", "first", "second"], ): store = ListStore() # pylint: disable=protected-access store._lists["test"] = ListModel(name="test", items=["first"]) result = store._generate_identifier() assert result == "second"
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_not_in_payload_when_not_answered(fake_questionnaire_store): routing_path = [ RoutingPath( ["list-collector", "next-interstitial", "another-list-collector-block"], section_id="section-1", ) ] answer_objects = [ {"answer_id": "first-name", "value": "1", "list_item_id": "xJlKBy"}, {"answer_id": "last-name", "value": "1", "list_item_id": "xJlKBy"}, {"answer_id": "first-name", "value": "2", "list_item_id": "RfAGDc"}, {"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"}, ] answers = AnswerStore(answer_objects) list_store = ListStore( existing_items=[{"name": "people", "items": ["xJlKBy", "RfAGDc"]}] ) fake_questionnaire_store.answer_store = answers fake_questionnaire_store.list_store = list_store schema = load_schema_from_name("test_list_collector") output = convert_answers(schema, fake_questionnaire_store, routing_path) data_dict = json_loads(json_dumps(output["data"]["lists"])) assert "primary_person" not in data_dict[0]
def _deserialize(self, data: str) -> None: json_data = json_loads(data) 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.deserialize(json_data.get("LISTS")) self.response_metadata = json_data.get("RESPONSE_METADATA", {})
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.is_repeating_answer = Mock(return_value=False) 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_placeholder_resolves_same_name_items(): list_store = ListStore( [ { "items": ["abc123", "cde456", "fgh789"], "same_name_items": ["abc123", "fgh789"], "name": "people", } ] ) placeholder_list = [ { "placeholder": "answer", "value": { "source": "list", "id_selector": "same_name_items", "identifier": "people", }, }, ] parser = PlaceholderParser( language="en", list_store=list_store, list_item_id="abc123", ) placeholders = parser(placeholder_list) assert placeholders["answer"] == ["abc123", "fgh789"]
def test_multiple_metadata_list_transform_placeholder(mock_renderer): placeholder_list = [ { "placeholder": "dates", "transforms": [ { "transform": "concatenate_list", "arguments": { "list_to_concatenate": [ {"source": "metadata", "identifier": "ref_p_start_date"}, {"source": "metadata", "identifier": "ref_p_end_date"}, ], "delimiter": " ", }, } ], } ] parser = PlaceholderParser( language="en", answer_store=AnswerStore(), list_store=ListStore(), metadata={"ref_p_start_date": "2019-02-11", "ref_p_end_date": "2019-10-11"}, response_metadata={}, schema=QuestionnaireSchema({}), renderer=mock_renderer, ) placeholders = parser(placeholder_list) assert placeholders["dates"] == "2019-02-11 2019-10-11"
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_placeholder_default_value(default_placeholder_value_schema, mock_renderer): placeholder_list = [ { "placeholder": "answer_employee", "transforms": [ { "transform": "format_number", "arguments": { "number": {"source": "answers", "identifier": "employees-no"} }, } ], } ] parser = PlaceholderParser( language="en", answer_store=AnswerStore(), list_store=ListStore(), metadata={}, response_metadata={}, schema=default_placeholder_value_schema, renderer=mock_renderer, ) placeholders = parser(placeholder_list) assert placeholders["answer_employee"] == "0"
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_placeholder_resolves_list_item_value_based_on_first_item_in_list( mock_renderer, ): placeholder_list = [ { "placeholder": "first_person_list_item_id", "value": { "source": "list", "selector": "first", "identifier": "people", }, } ] list_store = ListStore([{"items": ["item-1", "item-2"], "name": "people"}]) parser = PlaceholderParser( language="en", answer_store=AnswerStore(), list_store=list_store, metadata={}, response_metadata={}, schema=QuestionnaireSchema({}), renderer=mock_renderer, ) placeholders = parser(placeholder_list) assert str(placeholders["first_person_list_item_id"]) == list_store["people"].first
def test_first_non_empty_item_transform_placeholder(mock_renderer): placeholder_list = [ { "placeholder": "company_name", "transforms": [ { "transform": "first_non_empty_item", "arguments": { "items": [ {"source": "metadata", "identifier": "trad_as"}, {"source": "metadata", "identifier": "ru_name"}, ] }, } ], } ] parser = PlaceholderParser( language="en", answer_store=AnswerStore(), list_store=ListStore(), metadata={"ru_name": "ru_name"}, response_metadata={}, schema=QuestionnaireSchema({}), renderer=mock_renderer, ) placeholders = parser(placeholder_list) assert placeholders["company_name"] == "ru_name"
def test_mixed_transform_placeholder_value(mock_renderer): placeholder_list = [ { "placeholder": "age", "transforms": [ { "transform": "calculate_date_difference", "arguments": { "first_date": { "source": "answers", "identifier": "date-of-birth-answer", }, "second_date": {"value": "2019-02-02"}, }, } ], } ] parser = PlaceholderParser( language="en", answer_store=AnswerStore( [{"answer_id": "date-of-birth-answer", "value": "1999-01-01"}] ), list_store=ListStore(), metadata={}, response_metadata={}, schema=QuestionnaireSchema({}), renderer=mock_renderer, ) placeholders = parser(placeholder_list) assert placeholders["age"] == "20 years"
def test_checkbox_transform_placeholder(mock_renderer): placeholder_list = [ { "placeholder": "toppings", "transforms": [ { "transform": "concatenate_list", "arguments": { "list_to_concatenate": [ {"source": "answers", "identifier": "checkbox-answer"} ], "delimiter": ", ", }, } ], } ] parser = PlaceholderParser( language="en", answer_store=AnswerStore( [ {"answer_id": "checkbox-answer", "value": ["Ham", "Cheese"]}, ] ), list_store=ListStore(), metadata={}, response_metadata={}, schema=QuestionnaireSchema({}), renderer=mock_renderer, ) placeholders = parser(placeholder_list) assert placeholders["toppings"] == "Ham, Cheese"
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_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_placeholder_resolves_answer_value_based_on_first_item_in_list(): placeholder_list = [ { "placeholder": "answer", "value": { "source": "answers", "identifier": "favourite-drink-answer", "list_item_selector": { "source": "list", "id": "people", "id_selector": "first", }, }, } ] list_store = ListStore([{"items": ["abc123", "123abc"], "name": "people"}]) answer_store = AnswerStore( [ { "answer_id": "favourite-drink-answer", "value": "Coffee", "list_item_id": "abc123", } ] ) parser = PlaceholderParser( language="en", list_store=list_store, answer_store=answer_store ) placeholders = parser(placeholder_list) assert str(placeholders["answer"]) == "Coffee"
def test_placeholder_resolves_same_name_items(mock_renderer): list_store = ListStore( [ { "items": ["abc123", "cde456", "fgh789"], "same_name_items": ["abc123", "fgh789"], "name": "people", } ] ) placeholder_list = [ { "placeholder": "answer", "value": { "source": "list", "selector": "same_name_items", "identifier": "people", }, }, ] parser = PlaceholderParser( language="en", answer_store=AnswerStore(), list_store=list_store, metadata={}, response_metadata={}, schema=QuestionnaireSchema({}), renderer=mock_renderer, list_item_id="abc123", ) placeholders = parser(placeholder_list) assert placeholders["answer"] == ["abc123", "fgh789"]
def test_format_list_answer_transform_placeholder(mock_renderer): placeholder_list = [ { "placeholder": "toppings", "transforms": [ { "transform": "format_list", "arguments": { "list_to_format": { "source": "answers", "identifier": "checkbox-answer", } }, } ], } ] parser = PlaceholderParser( language="en", answer_store=AnswerStore( [{"answer_id": "checkbox-answer", "value": ["Ham", "Cheese"]}] ), list_store=ListStore(), metadata={}, response_metadata={}, schema=QuestionnaireSchema({}), renderer=mock_renderer, ) placeholders = parser(placeholder_list) assert placeholders["toppings"] == "<ul><li>Ham</li><li>Cheese</li></ul>"
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"], 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_from_name("test_list_collector") output = convert_answers( schema, fake_questionnaire_store, routing_path, SUBMITTED_AT ) # Answers not on the routing path del answer_objects[0] del answer_objects[-1] data_dict = json_loads(json_dumps(output["data"]["answers"])) assert sorted(answer_objects, key=lambda x: x["answer_id"]) == sorted( data_dict, key=lambda x: x["answer_id"] )
def test_metadata_transform_placeholder(mock_renderer): placeholder_list = [ { "placeholder": "start_date", "transforms": [ { "transform": "format_date", "arguments": { "date_to_format": { "source": "metadata", "identifier": "ref_p_start_date", }, "date_format": "EEEE d MMMM yyyy", }, } ], } ] parser = PlaceholderParser( language="en", answer_store=AnswerStore(), list_store=ListStore(), metadata={"ref_p_start_date": "2019-02-11"}, response_metadata={}, schema=QuestionnaireSchema({}), renderer=mock_renderer, ) placeholders = parser(placeholder_list) assert placeholders["start_date"] == "Monday 11 February 2019"