Ejemplo n.º 1
0
    def test_should_not_be_changed(self):
        # Given
        storage = Mock()
        data = {
            'METADATA':
            'test',
            'ANSWERS': [{
                'value': None,
                'group_id': 'group',
                'answer_id': 'answer',
                'block_id': 'block',
                'group_instance': 0,
                'answer_instance': 0
            }],
            'COMPLETED_BLOCKS': [Location('group', 'instance', 'block')]
        }
        storage.get_user_data = Mock(
            return_value=json.dumps(data, default=lambda o: o.__dict__))
        store = QuestionnaireStore(storage)

        # When
        changed = store.has_changed()

        # Then
        self.assertFalse(changed)
 def test_questionnaire_store_removes_completed_location(self):
     # Given
     expected = get_basic_input()
     store = QuestionnaireStore(self.storage)
     location = Location.from_dict(expected['COMPLETED_BLOCKS'][0])
     store.completed_blocks = [location]
     # When
     store.remove_completed_blocks(location=location)
     # Then
     self.assertEqual(store.completed_blocks, [])
Ejemplo n.º 3
0
    def setUp(self):
        super().setUp()
        self._application_context = self._application.app_context()
        self._application_context.push()

        storage = Mock()
        data = {'METADATA': 'test', 'ANSWERS': [], 'COMPLETED_BLOCKS': []}
        storage.get_user_data = Mock(
            return_value=(json.dumps(data), QuestionnaireStore.LATEST_VERSION))

        self.question_store = QuestionnaireStore(storage)
 def test_questionnaire_store_removes_completed_location_from_many(self):
     store = QuestionnaireStore(self.storage)
     location = Location('first-test-group', 0, 'a-test-block')
     location2 = Location('second-test-group', 0, 'a-test-block')
     store.completed_blocks = [
         location,
         location2,
     ]
     # When
     store.remove_completed_blocks(location=location)
     # Then
     self.assertEqual(store.completed_blocks, [location2])
 def test_questionnaire_store_raises_on_invalid_group_remove_completed_blocks_call(
         self):
     store = QuestionnaireStore(self.storage)
     location = Location('first-test-group', 0, 'a-test-block')
     location2 = Location('second-test-group', 0, 'a-test-block')
     store.completed_blocks = [
         location,
         location2,
     ]
     # When / Then
     with self.assertRaises(KeyError):
         store.remove_completed_blocks(block_id='a-test-block')
def fake_questionnaire_store(fake_metadata, fake_collection_metadata):
    user_answer = Answer(answer_id="GHI", value=0, list_item_id=None)

    storage = MagicMock()
    storage.get_user_data = MagicMock(return_value=("{}", 1))
    storage.add_or_update = MagicMock()

    store = QuestionnaireStore(storage)

    store.answer_store = AnswerStore()
    store.answer_store.add_or_update(user_answer)
    store.metadata = fake_metadata
    store.collection_metadata = fake_collection_metadata

    return store
    def test_questionnaire_store_errors_on_invalid_object(self):
        # Given
        class NotSerializable():
            pass

        expected = get_basic_input()
        store = QuestionnaireStore(self.storage)
        store.metadata = NotSerializable()
        store.answer_store.answers = expected['ANSWERS']
        store.completed_blocks = [
            Location.from_dict(expected['COMPLETED_BLOCKS'][0])
        ]

        # When / Then
        self.assertRaises(TypeError, store.add_or_update)
    def test_questionnaire_store_loads_json(self):
        # Given
        expected = get_basic_input()
        self.input_data = json.dumps(expected)
        # When
        store = QuestionnaireStore(self.storage)
        # Then
        self.assertEqual(store.metadata.copy(), expected["METADATA"])
        self.assertEqual(store.collection_metadata,
                         expected["COLLECTION_METADATA"])
        self.assertEqual(store.answer_store, AnswerStore(expected["ANSWERS"]))

        expected_completed_block_ids = expected["PROGRESS"][0]["block_ids"][0]

        self.assertEqual(
            len(
                store.progress_store.get_completed_block_ids(
                    "a-test-section", "abc123")),
            1,
        )
        self.assertEqual(
            store.progress_store.get_completed_block_ids(
                "a-test-section", "abc123")[0],
            expected_completed_block_ids,
        )
    def test_questionnaire_store_ignores_extra_json(self):
        # Given
        expected = get_basic_input()
        expected[
            "NOT_A_LEGAL_TOP_LEVEL_KEY"] = "woop_woop_thats_the_sound_of_the_police"
        self.input_data = json.dumps(expected)
        # When
        store = QuestionnaireStore(self.storage)
        # Then
        self.assertEqual(store.metadata.copy(), expected["METADATA"])
        self.assertEqual(store.collection_metadata,
                         expected["COLLECTION_METADATA"])
        self.assertEqual(store.answer_store, AnswerStore(expected["ANSWERS"]))

        expected_completed_block_ids = expected["PROGRESS"][0]["block_ids"][0]

        self.assertEqual(
            len(
                store.progress_store.get_completed_block_ids(
                    "a-test-section", "abc123")),
            1,
        )
        self.assertEqual(
            store.progress_store.get_completed_block_ids(
                "a-test-section", "abc123")[0],
            expected_completed_block_ids,
        )
Ejemplo n.º 10
0
def get_questionnaire_store(user_id, user_ik):
    # Sets up a single QuestionnaireStore instance throughout app.
    store = g.get('_questionnaire_store')
    if store is None:
        storage = get_storage(user_id, user_ik)
        store = g._questionnaire_store = QuestionnaireStore(storage)

    return store
 def test_questionnaire_store_raises_on_invalid_location_remove_completed_blocks_call(
         self):
     store = QuestionnaireStore(self.storage)
     location = Location('first-test-group', 0, 'a-test-block')
     location2 = Location('second-test-group', 0, 'a-test-block')
     store.completed_blocks = [
         location,
         location2,
     ]
     # When / Then
     with self.assertRaises(TypeError):
         store.remove_completed_blocks(
             location={
                 'group_id': 'a-group',
                 'group_instance': 0,
                 'block-id': 'a-block-id'
             })
    def test_questionnaire_store_updates_storage(self):
        # Given
        expected = get_basic_input()
        store = QuestionnaireStore(self.storage)
        store.set_metadata(expected["METADATA"])
        store.answer_store = AnswerStore(expected["ANSWERS"])
        store.collection_metadata = expected["COLLECTION_METADATA"]
        store.progress_store = ProgressStore(expected["PROGRESS"])

        # When
        store.save()  # See setUp - populates self.output_data

        # Then
        self.assertEqual(expected, json.loads(self.output_data))
    def test_questionnaire_store_updates_storage(self):
        # Given
        expected = get_basic_input()
        store = QuestionnaireStore(self.storage)
        store.set_metadata(expected['METADATA'])
        store.answer_store = AnswerStore(expected['ANSWERS'])
        store.collection_metadata = expected['COLLECTION_METADATA']
        store.completed_blocks = [
            Location.from_dict(expected['COMPLETED_BLOCKS'][0])
        ]

        # When
        store.add_or_update()  # See setUp - populates self.output_data

        # Then
        self.assertEqual(expected, json.loads(self.output_data))
Ejemplo n.º 14
0
def get_questionnaire_store(user_id, user_ik):
    # Sets up a single QuestionnaireStore instance throughout app.
    store = g.get('_questionnaire_store')
    if store is None:
        pepper = current_app.config[
            'EQ_SERVER_SIDE_STORAGE_ENCRYPTION_USER_PEPPER']
        storage = EncryptedQuestionnaireStorage(current_app.eq['database'],
                                                user_id, user_ik, pepper)
        store = g._questionnaire_store = QuestionnaireStore(storage)

    return store
def get_questionnaire_store(user_id, user_ik):
    from app.storage.encrypted_questionnaire_storage import EncryptedQuestionnaireStorage

    # Sets up a single QuestionnaireStore instance per request.
    store = g.get('_questionnaire_store')
    if store is None:
        pepper = current_app.eq['secret_store'].get_secret_by_name('EQ_SERVER_SIDE_STORAGE_ENCRYPTION_USER_PEPPER')
        storage = EncryptedQuestionnaireStorage(user_id, user_ik, pepper, stateless_updates_enabled=EQ_STATELESS_QUESTIONNAIRE_STORE_WRITES)
        store = g._questionnaire_store = QuestionnaireStore(storage)

    return store
 def test_questionnaire_store_missing_keys(self):
     # Given
     expected = get_basic_input()
     del expected['COMPLETED_BLOCKS']
     self.input_data = json.dumps(expected)
     # When
     store = QuestionnaireStore(self.storage)
     # Then
     self.assertEqual(store.metadata, expected['METADATA'])
     self.assertEqual(store.answer_store.answers, expected['ANSWERS'])
     self.assertEqual(len(store.completed_blocks), 0)
    def test_questionnaire_store_deletes(self):
        # Given
        expected = get_basic_input()
        store = QuestionnaireStore(self.storage)
        store.set_metadata(expected["METADATA"])
        store.collection_metadata = expected["COLLECTION_METADATA"]
        store.answer_store = AnswerStore(expected["ANSWERS"])
        store.progress_store = ProgressStore(expected["PROGRESS"])

        # When
        store.delete()  # See setUp - populates self.output_data

        # Then
        self.assertNotIn("a-test-section", store.progress_store)
        self.assertEqual(store.metadata.copy(), {})
        self.assertEqual(len(store.answer_store), 0)
        self.assertEqual(store.collection_metadata, {})
Ejemplo n.º 18
0
    def setUp(self):
        self.app = create_app()
        self.app.config['SERVER_NAME'] = "test"
        self.app_context = self.app.app_context()
        self.app_context.push()

        storage = Mock()
        data = {'METADATA': 'test', 'ANSWERS': [], 'COMPLETED_BLOCKS': []}
        storage.get_user_data = Mock(
            return_value=json.dumps(data, default=lambda o: o.__dict__))

        self.question_store = QuestionnaireStore(storage)
 def test_questionnaire_store_loads_json(self):
     # Given
     expected = get_basic_input()
     self.input_data = json.dumps(expected)
     # When
     store = QuestionnaireStore(self.storage)
     # Then
     self.assertEqual(store.metadata, expected['METADATA'])
     self.assertEqual(store.answer_store.answers, expected['ANSWERS'])
     expected_location = expected['COMPLETED_BLOCKS'][0]
     self.assertEqual(len(store.completed_blocks), 1)
     self.assertEqual(store.completed_blocks[0],
                      Location.from_dict(location_dict=expected_location))
 def test_questionnaire_store_missing_keys(self):
     # Given
     expected = get_basic_input()
     del expected["PROGRESS"]
     self.input_data = json.dumps(expected)
     # When
     store = QuestionnaireStore(self.storage)
     # Then
     self.assertEqual(store.metadata.copy(), expected["METADATA"])
     self.assertEqual(store.collection_metadata,
                      expected["COLLECTION_METADATA"])
     self.assertEqual(store.answer_store, AnswerStore(expected["ANSWERS"]))
     self.assertEqual(store.progress_store.serialise(), [])
Ejemplo n.º 21
0
def get_questionnaire_store(user_id, user_ik):
    from app.storage.encrypted_questionnaire_storage import (
        EncryptedQuestionnaireStorage, )

    # Sets up a single QuestionnaireStore instance per request.
    store = g.get("_questionnaire_store")
    if store is None:
        pepper = current_app.eq["secret_store"].get_secret_by_name(
            "EQ_SERVER_SIDE_STORAGE_ENCRYPTION_USER_PEPPER")
        storage = EncryptedQuestionnaireStorage(user_id, user_ik, pepper)
        store = g._questionnaire_store = QuestionnaireStore(storage)

    return store
 def test_questionnaire_store_loads_answers_as_dict(self):
     # Given
     expected = get_input_answers_dict()
     self.input_data = json.dumps(expected)
     # When
     store = QuestionnaireStore(self.storage, 3)
     # Then
     self.assertEqual(store.metadata.copy(), expected['METADATA'])
     self.assertEqual(store.collection_metadata,
                      expected['COLLECTION_METADATA'])
     self.assertEqual(store.answer_store, AnswerStore(expected['ANSWERS']))
     expected_location = expected['COMPLETED_BLOCKS'][0]
     self.assertEqual(len(store.completed_blocks), 1)
     self.assertEqual(store.completed_blocks[0],
                      Location.from_dict(location_dict=expected_location))
 def test_questionnaire_store_ignores_extra_json(self):
     # Given
     expected = get_basic_input()
     expected[
         'NOT_A_LEGAL_TOP_LEVEL_KEY'] = 'woop_woop_thats_the_sound_of_the_police'
     self.input_data = json.dumps(expected)
     # When
     store = QuestionnaireStore(self.storage)
     # Then
     self.assertEqual(store.metadata, expected['METADATA'])
     self.assertEqual(store.answer_store.answers, expected['ANSWERS'])
     expected_location = expected['COMPLETED_BLOCKS'][0]
     self.assertEqual(len(store.completed_blocks), 1)
     self.assertEqual(store.completed_blocks[0],
                      Location.from_dict(location_dict=expected_location))
Ejemplo n.º 24
0
def get_questionnaire_store(user_id, user_ik):
    from app.storage.encrypted_questionnaire_storage import EncryptedQuestionnaireStorage
    from app.utilities.schema import load_schema_from_metadata

    # Sets up a single QuestionnaireStore instance per request.
    store = g.get('_questionnaire_store')
    if store is None:
        pepper = current_app.eq['secret_store'].get_secret_by_name(
            'EQ_SERVER_SIDE_STORAGE_ENCRYPTION_USER_PEPPER')
        storage = EncryptedQuestionnaireStorage(user_id, user_ik, pepper)
        store = g._questionnaire_store = QuestionnaireStore(storage)

    if store.metadata:  # When creating the questionnaire storage, there is no metadata for upgrading
        schema = load_schema_from_metadata(store.metadata)
        store.ensure_latest_version(schema)

    return store
    def test_questionnaire_store_deletes(self):
        # Given
        expected = get_basic_input()
        store = QuestionnaireStore(self.storage)
        store.set_metadata(expected['METADATA'])
        store.collection_metadata = expected['COLLECTION_METADATA']
        store.answer_store.answers = expected['ANSWERS']
        store.completed_blocks = [
            Location.from_dict(expected['COMPLETED_BLOCKS'][0])
        ]

        # When
        store.delete()  # See setUp - populates self.output_data

        # Then
        self.assertEqual(store.completed_blocks, [])
        self.assertEqual(store.metadata.copy(), {})
        self.assertEqual(store.answer_store.count(), 0)
        self.assertEqual(store.collection_metadata, {})
    def test_questionnaire_store_errors_on_invalid_object(self):
        # Given
        class NotSerializable:
            pass

        non_serializable_metadata = {"test": NotSerializable()}

        expected = get_basic_input()
        store = QuestionnaireStore(self.storage)
        store.set_metadata(non_serializable_metadata)
        store.collection_metadata = expected["COLLECTION_METADATA"]
        store.answer_store = AnswerStore(expected["ANSWERS"])
        store.progress_store = ProgressStore(expected["PROGRESS"])

        # When / Then
        self.assertRaises(TypeError, store.save)
    def test_questionnaire_store_errors_on_invalid_object(self):
        # Given
        class NotSerializable:
            pass

        non_serializable_metadata = {'test': NotSerializable()}

        expected = get_basic_input()
        store = QuestionnaireStore(self.storage)
        store.set_metadata(non_serializable_metadata)
        store.collection_metadata = expected['COLLECTION_METADATA']
        store.answer_store = AnswerStore(expected['ANSWERS'])
        store.completed_blocks = [
            Location.from_dict(expected['COMPLETED_BLOCKS'][0])
        ]

        # When / Then
        self.assertRaises(TypeError, store.add_or_update)
Ejemplo n.º 28
0
class TestQuestionnaire(IntegrationTestCase):  # pylint: disable=too-many-public-methods
    def setUp(self):
        super().setUp()
        self._application_context = self._application.app_context()
        self._application_context.push()

        storage = Mock()
        data = {'METADATA': 'test', 'ANSWERS': [], 'COMPLETED_BLOCKS': []}
        storage.get_user_data = Mock(
            return_value=(json.dumps(data), QuestionnaireStore.LATEST_VERSION))

        self.question_store = QuestionnaireStore(storage)

    def tearDown(self):
        self._application_context.pop()

    def test_update_questionnaire_store_with_form_data(self):

        schema = load_schema_from_params('test', '0112')

        location = Location('rsi', 0, 'total-retail-turnover')

        form_data = {
            'total-retail-turnover-answer': '1000',
        }

        with self._application.test_request_context():
            update_questionnaire_store_with_form_data(self.question_store,
                                                      location, form_data,
                                                      schema)

        self.assertEqual(self.question_store.completed_blocks, [location])

        self.assertIn(
            {
                'group_instance_id': None,
                'group_instance': 0,
                'answer_id': 'total-retail-turnover-answer',
                'answer_instance': 0,
                'value': '1000'
            }, self.question_store.answer_store.answers)

    def test_update_questionnaire_store_with_default_value(self):

        schema = load_schema_from_params('test', 'default')

        location = Location('group', 0, 'number-question')

        # No answer given so will use schema defined default
        form_data = {'answer': None}

        with self._application.test_request_context():
            update_questionnaire_store_with_form_data(self.question_store,
                                                      location, form_data,
                                                      schema)

        self.assertEqual(self.question_store.completed_blocks, [location])

        self.assertIn(
            {
                'group_instance_id': None,
                'group_instance': 0,
                'answer_id': 'answer',
                'answer_instance': 0,
                'value': 0
            }, self.question_store.answer_store.answers)

    def test_update_questionnaire_store_with_answer_data(self):
        schema = load_schema_from_params('census', 'household')

        location = Location('who-lives-here', 0, 'household-composition')

        answers = [
            Answer(group_instance=0,
                   answer_id='first-name',
                   answer_instance=0,
                   value='Joe'),
            Answer(group_instance=0,
                   answer_id='middle-names',
                   answer_instance=0,
                   value=''),
            Answer(group_instance=0,
                   answer_id='last-name',
                   answer_instance=0,
                   value='Bloggs'),
            Answer(group_instance=0,
                   answer_id='first-name',
                   answer_instance=1,
                   value='Bob'),
            Answer(group_instance=0,
                   answer_id='middle-names',
                   answer_instance=1,
                   value=''),
            Answer(group_instance=0,
                   answer_id='last-name',
                   answer_instance=1,
                   value='Seymour')
        ]

        with self._application.test_request_context():
            update_questionnaire_store_with_answer_data(
                self.question_store, location, answers, schema)

        self.assertEqual(self.question_store.completed_blocks, [location])

        for answer in answers:
            self.assertIn(answer.__dict__,
                          self.question_store.answer_store.answers)

    def test_remove_empty_household_members_from_answer_store(self):
        schema = load_schema_from_params('census', 'household')

        answers = [
            Answer(group_instance=0,
                   answer_id='first-name',
                   answer_instance=0,
                   value=''),
            Answer(group_instance=0,
                   answer_id='middle-names',
                   answer_instance=0,
                   value=''),
            Answer(group_instance=0,
                   answer_id='last-name',
                   answer_instance=0,
                   value=''),
            Answer(group_instance=0,
                   answer_id='first-name',
                   answer_instance=1,
                   value=''),
            Answer(group_instance=0,
                   answer_id='middle-names',
                   answer_instance=1,
                   value=''),
            Answer(group_instance=0,
                   answer_id='last-name',
                   answer_instance=1,
                   value='')
        ]

        for answer in answers:
            self.question_store.answer_store.add_or_update(answer)

        remove_empty_household_members_from_answer_store(
            self.question_store.answer_store, schema)

        for answer in answers:
            self.assertIsNone(self.question_store.answer_store.find(answer))

    def test_remove_empty_household_members_values_entered_are_stored(self):
        schema = load_schema_from_params('census', 'household')

        answered = [
            Answer(group_instance=0,
                   group_instance_id='group-0',
                   answer_id='first-name',
                   answer_instance=0,
                   value='Joe'),
            Answer(group_instance=0,
                   group_instance_id='group-0',
                   answer_id='middle-names',
                   answer_instance=0,
                   value=''),
            Answer(group_instance=0,
                   group_instance_id='group-0',
                   answer_id='last-name',
                   answer_instance=0,
                   value='Bloggs')
        ]

        unanswered = [
            Answer(group_instance=0,
                   group_instance_id='group-0',
                   answer_id='first-name',
                   answer_instance=1,
                   value=''),
            Answer(group_instance=0,
                   group_instance_id='group-0',
                   answer_id='middle-names',
                   answer_instance=1,
                   value=''),
            Answer(group_instance=0,
                   group_instance_id='group-0',
                   answer_id='last-name',
                   answer_instance=1,
                   value='')
        ]

        answers = []
        answers.extend(answered)
        answers.extend(unanswered)

        for answer in answers:
            self.question_store.answer_store.add_or_update(answer)

        remove_empty_household_members_from_answer_store(
            self.question_store.answer_store, schema)

        for answer in answered:
            self.assertIsNotNone(self.question_store.answer_store.find(answer))

        for answer in unanswered:
            self.assertIsNone(self.question_store.answer_store.find(answer))

    def test_remove_empty_household_members_partial_answers_are_stored(self):
        schema = load_schema_from_params('census', 'household')

        answered = [
            Answer(group_instance=0,
                   group_instance_id='group-0',
                   answer_id='first-name',
                   answer_instance=0,
                   value='Joe'),
            Answer(group_instance=0,
                   group_instance_id='group-0',
                   answer_id='middle-names',
                   answer_instance=0,
                   value=''),
            Answer(group_instance=0,
                   group_instance_id='group-0',
                   answer_id='last-name',
                   answer_instance=0,
                   value='Bloggs')
        ]

        partially_answered = [
            Answer(group_instance=0,
                   group_instance_id='group-0',
                   answer_id='first-name',
                   answer_instance=1,
                   value=''),
            Answer(group_instance=0,
                   group_instance_id='group-0',
                   answer_id='middle-names',
                   answer_instance=1,
                   value=''),
            Answer(group_instance=0,
                   group_instance_id='group-0',
                   answer_id='last-name',
                   answer_instance=1,
                   value='Last name only'),
            Answer(group_instance=0,
                   group_instance_id='group-0',
                   answer_id='first-name',
                   answer_instance=2,
                   value='First name only'),
            Answer(group_instance=0,
                   group_instance_id='group-0',
                   answer_id='middle-names',
                   answer_instance=2,
                   value=''),
            Answer(group_instance=0,
                   group_instance_id='group-0',
                   answer_id='last-name',
                   answer_instance=2,
                   value='')
        ]

        answers = []
        answers.extend(answered)
        answers.extend(partially_answered)

        for answer in answers:
            self.question_store.answer_store.add_or_update(answer)

        remove_empty_household_members_from_answer_store(
            self.question_store.answer_store, schema)

        for answer in answered:
            self.assertIsNotNone(self.question_store.answer_store.find(answer))

        for answer in partially_answered:
            self.assertIsNotNone(self.question_store.answer_store.find(answer))

    def test_remove_empty_household_members_middle_name_only_not_stored(self):
        schema = load_schema_from_params('census', 'household')

        unanswered = [
            Answer(group_instance=0,
                   answer_id='first-name',
                   answer_instance=0,
                   value=''),
            Answer(group_instance=0,
                   answer_id='middle-names',
                   answer_instance=0,
                   value='should not be saved'),
            Answer(group_instance=0,
                   answer_id='last-name',
                   answer_instance=0,
                   value='')
        ]

        for answer in unanswered:
            self.question_store.answer_store.add_or_update(answer)

        remove_empty_household_members_from_answer_store(
            self.question_store.answer_store, schema)

        for answer in unanswered:
            self.assertIsNone(self.question_store.answer_store.find(answer))

    def test_given_introduction_page_when_get_page_title_then_defaults_to_survey_title(
            self):
        # Given
        schema = load_schema_from_params('test', 'final_confirmation')

        # When
        page_title = get_page_title_for_location(
            schema, Location('final-confirmation', 0, 'introduction'), {},
            AnswerStore())

        # Then
        self.assertEqual(page_title, 'Final confirmation to submit')

    def test_given_interstitial_page_when_get_page_title_then_group_title_and_survey_title(
            self):
        # Given
        schema = load_schema_from_params('test', 'interstitial_page')

        # When
        page_title = get_page_title_for_location(
            schema, Location('favourite-foods', 0, 'breakfast-interstitial'),
            {}, AnswerStore())

        # Then
        self.assertEqual(page_title, 'Favourite food - Interstitial Pages')

    def test_given_questionnaire_page_when_get_page_title_then_question_title_and_survey_title(
            self):
        # Given
        schema = load_schema_from_params('test', 'final_confirmation')

        # When
        page_title = get_page_title_for_location(
            schema, Location('final-confirmation', 0, 'breakfast'), {},
            AnswerStore())

        # Then
        self.assertEqual(
            page_title,
            'What is your favourite breakfast food - Final confirmation to submit'
        )

    def test_given_questionnaire_page_when_get_page_title_with_titles_object(
            self):

        # Given
        schema = load_schema_from_params('test', 'titles')

        # When
        page_title = get_page_title_for_location(
            schema, Location('group', 0, 'single-title-block'), {},
            AnswerStore())

        # Then
        self.assertEqual(
            page_title, 'How are you feeling?? - Multiple Question Title Test')

    def test_given_jinja_variable_question_title_when_get_page_title_then_replace_with_ellipsis(
            self):
        # Given
        schema = load_schema_from_params('census', 'household')

        # When
        page_title = get_page_title_for_location(
            schema,
            Location('who-lives-here-relationship', 0,
                     'household-relationships'), {}, AnswerStore())

        # Then
        self.assertEqual(
            page_title,
            'How is … related to the people below? - 2017 Census Test')

    def test_updating_questionnaire_store_removes_completed_block_for_min_dependencies(
            self):

        schema = load_schema_from_params('test', 'dependencies_min_value')

        min_answer_location = Location('group', 0, 'min-block')
        dependent_location = Location('group', 0, 'dependent-block')

        min_answer_data = {
            'min-answer': '10',
        }

        dependent_data = {
            'dependent-1': '10',
        }

        with self._application.test_request_context():
            update_questionnaire_store_with_form_data(self.question_store,
                                                      min_answer_location,
                                                      min_answer_data, schema)

        with self._application.test_request_context():
            update_questionnaire_store_with_form_data(self.question_store,
                                                      dependent_location,
                                                      dependent_data, schema)

        self.assertIn(min_answer_location,
                      self.question_store.completed_blocks)
        self.assertIn(dependent_location, self.question_store.completed_blocks)

        min_answer_data = {
            'min-answer': '9',
        }

        with self._application.test_request_context():
            update_questionnaire_store_with_form_data(self.question_store,
                                                      min_answer_location,
                                                      min_answer_data, schema)

        self.assertNotIn(dependent_location,
                         self.question_store.completed_blocks)

    def test_updating_questionnaire_store_removes_completed_block_for_max_dependencies(
            self):

        schema = load_schema_from_params('test', 'dependencies_max_value')

        max_answer_location = Location('group', 0, 'max-block')
        dependent_location = Location('group', 0, 'dependent-block')

        max_answer_data = {
            'max-answer': '10',
        }

        dependent_data = {
            'dependent-1': '10',
        }

        with self._application.test_request_context():
            update_questionnaire_store_with_form_data(self.question_store,
                                                      max_answer_location,
                                                      max_answer_data, schema)

        with self._application.test_request_context():
            update_questionnaire_store_with_form_data(self.question_store,
                                                      dependent_location,
                                                      dependent_data, schema)

        self.assertIn(max_answer_location,
                      self.question_store.completed_blocks)
        self.assertIn(dependent_location, self.question_store.completed_blocks)

        max_answer_data = {
            'max-answer': '11',
        }

        with self._application.test_request_context():
            update_questionnaire_store_with_form_data(self.question_store,
                                                      max_answer_location,
                                                      max_answer_data, schema)

        self.assertNotIn(dependent_location,
                         self.question_store.completed_blocks)

    def test_updating_questionnaire_store_removes_completed_block_for_calculation_dependencies(
            self):

        schema = load_schema_from_params('test', 'dependencies_calculation')

        calculation_answer_location = Location('group', 0, 'total-block')
        dependent_location = Location('group', 0, 'breakdown-block')

        calculation_answer_data = {
            'total-answer': '100',
        }

        dependent_data = {
            'breakdown-1': '10',
            'breakdown-2': '20',
            'breakdown-3': '30',
            'breakdown-4': '40'
        }

        with self._application.test_request_context():
            update_questionnaire_store_with_form_data(
                self.question_store, calculation_answer_location,
                calculation_answer_data, schema)

        with self._application.test_request_context():
            update_questionnaire_store_with_form_data(self.question_store,
                                                      dependent_location,
                                                      dependent_data, schema)

        self.assertIn(calculation_answer_location,
                      self.question_store.completed_blocks)
        self.assertIn(dependent_location, self.question_store.completed_blocks)

        calculation_answer_data = {
            'total-answer': '99',
        }

        with self._application.test_request_context():
            update_questionnaire_store_with_form_data(
                self.question_store, calculation_answer_location,
                calculation_answer_data, schema)

        self.assertNotIn(dependent_location,
                         self.question_store.completed_blocks)

    def test_updating_questionnaire_store_specific_group(self):
        schema = load_schema_from_params('test', 'repeating_household_routing')
        answers = [
            Answer(group_instance=0,
                   group_instance_id='group-0',
                   answer_id='first-name',
                   answer_instance=0,
                   value='Joe'),
            Answer(group_instance=0,
                   group_instance_id='group-0',
                   answer_id='last-name',
                   answer_instance=0,
                   value='Bloggs'),
            Answer(group_instance=0,
                   group_instance_id='group-0',
                   answer_id='date-of-birth-answer',
                   answer_instance=0,
                   value='2016-03-12'),
            Answer(group_instance=1,
                   group_instance_id='group-1',
                   answer_id='date-of-birth-answer',
                   answer_instance=0,
                   value='2018-01-01')
        ]

        for answer in answers:
            self.question_store.answer_store.add_or_update(answer)

        answer_form_data = {'date-of-birth-answer': None}
        location = Location('household-member-group', 1, 'date-of-birth')
        with self._application.test_request_context():
            update_questionnaire_store_with_form_data(self.question_store,
                                                      location,
                                                      answer_form_data, schema)

        self.assertIsNone(self.question_store.answer_store.find(answers[3]))
        for answer in answers[:2]:
            self.assertIsNotNone(self.question_store.answer_store.find(answer))

    def test_build_view_context_for_question(self):
        # Given
        g.schema = schema = load_schema_from_params('test', 'titles')
        block = g.schema.get_block('single-title-block')
        full_routing_path = [
            Location('group', 0, 'single-title-block'),
            Location('group', 0, 'who-is-answer-block'),
            Location('group', 0, 'multiple-question-versions-block'),
            Location('group', 0, 'Summary')
        ]
        current_location = Location('group', 0, 'single-title-block')
        schema_context = _get_schema_context(full_routing_path,
                                             current_location, {}, {},
                                             AnswerStore(), g.schema)

        # When
        with self._application.test_request_context():
            question_view_context = build_view_context('Question', {},
                                                       schema,
                                                       AnswerStore(),
                                                       schema_context,
                                                       block,
                                                       current_location,
                                                       form=None)

        # Then
        self.assertEqual(
            question_view_context['question_titles']['single-title-question'],
            'How are you feeling??')

    def test_build_view_context_for_calculation_summary(self):
        # Given
        schema = load_schema_from_params('test', 'calculated_summary')
        block = schema.get_block('currency-total-playback')
        metadata = {
            'tx_id': '12345678-1234-5678-1234-567812345678',
            'collection_exercise_sid': '789',
            'form_type': 'calculated_summary',
            'eq_id': 'test',
        }
        answers = [
            {
                'answer_instance': 0,
                'group_instance': 0,
                'answer_id': 'first-number-answer',
                'value': 1
            },
            {
                'answer_instance': 0,
                'group_instance': 0,
                'answer_id': 'second-number-answer',
                'value': 2
            },
            {
                'answer_instance': 0,
                'group_instance': 0,
                'answer_id': 'third-number-answer',
                'value': 4
            },
            {
                'answer_instance': 0,
                'group_instance': 0,
                'answer_id': 'fourth-number-answer',
                'value': 6
            },
        ]
        schema_context = {
            'answers': answers,
            'group_instance': 0,
            'metadata': metadata
        }
        current_location = Location('group', 0, 'currency-total-playback')

        # When
        with self._application.test_request_context():
            view_context = build_view_context(block['type'],
                                              metadata,
                                              schema,
                                              AnswerStore(answers),
                                              schema_context,
                                              block,
                                              current_location,
                                              form=None)

        # Then
        self.assertTrue('summary' in view_context)
        self.assertTrue('calculated_question' in view_context['summary'])
        self.assertEqual(
            view_context['summary']['title'],
            'We calculate the total of currency values entered to be £13.00. Is this correct? (With Fourth)'
        )

    def test_answer_non_repeating_dependency_repeating_validate_all_of_block_and_group_removed(
            self):
        """ load a schema with a non repeating independent answer and a repeating one that depends on it
        validate that when the independent variable is set a call is made to remove all instances of
        the dependant variables
        """
        # Given
        schema = load_schema_from_params(
            'test', 'titles_repeating_non_repeating_dependency')
        colour_answer_location = Location('colour-group', 0,
                                          'favourite-colour')
        colour_answer = {'fav-colour-answer': 'blue'}

        # When
        with self._application.test_request_context():
            with patch(
                    'app.data_model.questionnaire_store.QuestionnaireStore.remove_completed_blocks'
            ) as patch_remove:
                update_questionnaire_store_with_form_data(
                    self.question_store, colour_answer_location, colour_answer,
                    schema)

        # Then
        patch_remove.assert_called_with(group_id='repeating-group',
                                        block_id='repeating-block-3')

    def test_remove_completed_by_group_and_block(self):
        for i in range(10):
            self.question_store.completed_blocks.append(
                Location('group1', i, 'block1'))

        self.question_store.completed_blocks.append(
            Location('group2', 0, 'block2'))

        self.question_store.remove_completed_blocks(group_id='group1',
                                                    block_id='block1')

        self.assertEqual(len(self.question_store.completed_blocks), 1)
        self.assertEqual(self.question_store.completed_blocks[0],
                         Location('group2', 0, 'block2'))

    def test_remove_completed_by_group_and_block_does_not_error_if_no_matching_blocks(
            self):
        for i in range(10):
            self.question_store.completed_blocks.append(
                Location('group1', i, 'block1'))

        self.question_store.completed_blocks.append(
            Location('group2', 0, 'block2'))

        self.question_store.remove_completed_blocks(group_id='group1',
                                                    block_id='block2')
        self.question_store.remove_completed_blocks(group_id='group2',
                                                    block_id='block1')
    def test_questionnaire_store_raises_when_writing_to_metadata(self):
        store = QuestionnaireStore(self.storage)

        with self.assertRaises(TypeError):
            store.metadata['no'] = 'writing'
class TestQuestionnaire(IntegrationTestCase):
    def setUp(self):
        super().setUp()
        self._application_context = self._application.app_context()
        self._application_context.push()

        storage = Mock()
        data = {'METADATA': 'test', 'ANSWERS': [], 'COMPLETED_BLOCKS': []}
        storage.get_user_data = Mock(
            return_value=(json.dumps(data), QuestionnaireStore.LATEST_VERSION))

        self.question_store = QuestionnaireStore(storage)

    def tearDown(self):
        self._application_context.pop()

    def test_given_introduction_page_when_get_page_title_then_defaults_to_survey_title(
            self):
        # Given
        schema = load_schema_from_params('test', 'final_confirmation')

        # When
        page_title = get_page_title_for_location(
            schema, Location('final-confirmation', 0, 'introduction'), {},
            AnswerStore())

        # Then
        self.assertEqual(page_title, 'Final confirmation to submit')

    def test_given_interstitial_page_when_get_page_title_then_group_title_and_survey_title(
            self):
        # Given
        schema = load_schema_from_params('test', 'interstitial_page')

        # When
        page_title = get_page_title_for_location(
            schema, Location('favourite-foods', 0, 'breakfast-interstitial'),
            {}, AnswerStore())

        # Then
        self.assertEqual(page_title, 'Favourite food - Interstitial Pages')

    def test_given_questionnaire_page_when_get_page_title_then_question_title_and_survey_title(
            self):
        # Given
        schema = load_schema_from_params('test', 'final_confirmation')

        # When
        page_title = get_page_title_for_location(
            schema, Location('final-confirmation', 0, 'breakfast'), {},
            AnswerStore())

        # Then
        self.assertEqual(
            page_title,
            'What is your favourite breakfast food - Final confirmation to submit'
        )

    def test_given_questionnaire_page_when_get_page_title_with_titles_object(
            self):

        # Given
        schema = load_schema_from_params('test', 'titles')

        # When
        page_title = get_page_title_for_location(
            schema, Location('group', 0, 'single-title-block'), {},
            AnswerStore())

        # Then
        self.assertEqual(
            page_title, 'How are you feeling?? - Multiple Question Title Test')

    def test_given_jinja_variable_question_title_when_get_page_title_then_replace_with_ellipsis(
            self):
        # Given
        schema = load_schema_from_params('test', 'relationship_household')

        # When
        page_title = get_page_title_for_location(
            schema,
            Location('who-lives-here-relationship', 0,
                     'household-relationships'), {}, AnswerStore())

        # Then
        self.assertEqual(
            page_title,
            'How is … related to the people below? - Household relationship')

    def test_build_view_context_for_question(self):
        # Given
        g.schema = schema = load_schema_from_params('test', 'titles')
        block = g.schema.get_block('single-title-block')
        full_routing_path = [
            Location('group', 0, 'single-title-block'),
            Location('group', 0, 'who-is-answer-block'),
            Location('group', 0, 'multiple-question-versions-block'),
            Location('group', 0, 'Summary')
        ]
        current_location = Location('group', 0, 'single-title-block')
        schema_context = _get_schema_context(full_routing_path,
                                             current_location, {}, {},
                                             AnswerStore(), g.schema)

        # When
        with self._application.test_request_context():
            question_view_context = build_view_context('Question', {},
                                                       schema,
                                                       AnswerStore(),
                                                       schema_context,
                                                       block,
                                                       current_location,
                                                       form=None)

        # Then
        self.assertEqual(
            question_view_context['question_titles']['single-title-question'],
            'How are you feeling??')

    def test_build_view_context_for_calculation_summary(self):
        # Given
        schema = load_schema_from_params('test', 'calculated_summary')
        block = schema.get_block('currency-total-playback')
        metadata = {
            'tx_id': '12345678-1234-5678-1234-567812345678',
            'collection_exercise_sid': '789',
            'form_type': 'calculated_summary',
            'eq_id': 'test',
        }
        answers = [
            {
                'answer_instance': 0,
                'group_instance': 0,
                'answer_id': 'first-number-answer',
                'value': 1
            },
            {
                'answer_instance': 0,
                'group_instance': 0,
                'answer_id': 'second-number-answer',
                'value': 2
            },
            {
                'answer_instance': 0,
                'group_instance': 0,
                'answer_id': 'third-number-answer',
                'value': 4
            },
            {
                'answer_instance': 0,
                'group_instance': 0,
                'answer_id': 'fourth-number-answer',
                'value': 6
            },
        ]
        schema_context = {
            'answers': answers,
            'group_instance': 0,
            'metadata': metadata
        }
        current_location = Location('group', 0, 'currency-total-playback')

        # When
        with self._application.test_request_context():
            view_context = build_view_context(block['type'],
                                              metadata,
                                              schema,
                                              AnswerStore(answers),
                                              schema_context,
                                              block,
                                              current_location,
                                              form=None)

        # Then
        self.assertTrue('summary' in view_context)
        self.assertTrue('calculated_question' in view_context['summary'])
        self.assertEqual(
            view_context['summary']['title'],
            'We calculate the total of currency values entered to be £13.00. Is this correct? (With Fourth)'
        )

    def test_remove_completed_by_group_and_block(self):
        for i in range(10):
            self.question_store.completed_blocks.append(
                Location('group1', i, 'block1'))

        self.question_store.completed_blocks.append(
            Location('group2', 0, 'block2'))

        self.question_store.remove_completed_blocks(group_id='group1',
                                                    block_id='block1')

        self.assertEqual(len(self.question_store.completed_blocks), 1)
        self.assertEqual(self.question_store.completed_blocks[0],
                         Location('group2', 0, 'block2'))

    def test_remove_completed_by_group_and_block_does_not_error_if_no_matching_blocks(
            self):
        for i in range(10):
            self.question_store.completed_blocks.append(
                Location('group1', i, 'block1'))

        self.question_store.completed_blocks.append(
            Location('group2', 0, 'block2'))

        self.question_store.remove_completed_blocks(group_id='group1',
                                                    block_id='block2')
        self.question_store.remove_completed_blocks(group_id='group2',
                                                    block_id='block1')