Example #1
0
    def test_should_go_to_next_question_when_condition_is_meta_and_answer_type(
            self):
        # Given
        goto_rule = {
            'id':
            'next-question',
            'when': [{
                'id': 'my_answer',
                'condition': 'equals',
                'value': 'Yes'
            }, {
                'condition': 'equals',
                'meta': 'sexual_identity',
                'value': True
            }]
        }
        answer_store = AnswerStore()
        answer_store.add(Answer(answer_id='my_answer', value='Yes'))
        metadata = {'sexual_identity': True}

        # When
        goto = evaluate_goto(goto_rule, metadata, answer_store, 0)

        # Then
        self.assertTrue(goto)
Example #2
0
    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 _evaluate_routing_rules(
        self, this_location, blocks, routing_rules, block_index, routing_path_block_ids
    ):
        for rule in filter(is_goto_rule, routing_rules):
            should_goto = evaluate_goto(
                rule["goto"],
                self.schema,
                self.metadata,
                self.answer_store,
                self.list_store,
                current_location=this_location,
                routing_path_block_ids=routing_path_block_ids,
            )

            if should_goto:
                next_block_id = self._get_next_block_id(rule)
                next_block_index = PathFinder._block_index_for_block_id(
                    blocks, next_block_id
                )
                next_precedes_current = (
                    next_block_index is not None and next_block_index < block_index
                )

                if next_precedes_current:
                    self._remove_rule_answers(rule["goto"], this_location)
                    routing_path_block_ids.append(next_block_id)
                    return None

                return next_block_index
Example #4
0
    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_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(Answer(answer_id='my_answer', value='Yes'))
        metadata = {'sexual_identity': True}

        # When
        goto = evaluate_goto(goto_rule, get_schema_mock(), metadata, answer_store, 0)

        # Then
        self.assertFalse(goto)
Example #6
0
    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,
            ))
Example #7
0
    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,
            ))
Example #8
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,
            ))
Example #9
0
    def can_reach_summary(self, routing_path):
        """
        Determines whether the end of a given routing path can be reached given
        a set of answers
        :param routing_path:
        :return:
        """
        blocks = self.get_blocks()
        last_routing_block_id = routing_path[-1].block_id
        last_block_id = blocks[-1]['block']['id']

        if last_block_id == last_routing_block_id:
            return True

        routing_block_id_index = next(
            index for (index, b) in enumerate(blocks)
            if b['block']["id"] == last_routing_block_id)

        last_routing_block = blocks[routing_block_id_index]['block']

        if 'routing_rules' in last_routing_block:
            for rule in last_routing_block['routing_rules']:
                goto_rule = rule['goto']
                if 'id' in goto_rule.keys() and goto_rule['id'] == 'summary':
                    return evaluate_goto(goto_rule, self.metadata,
                                         self.answer_store, 0)
        return False
Example #10
0
    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,
            ))
Example #11
0
    def _evaluate_routing_rules(self, this_location, blocks, block,
                                block_index, path):
        for rule in filter(is_goto_rule, block['routing_rules']):
            should_goto = evaluate_goto(rule['goto'], self.schema,
                                        self.metadata, self.answer_store,
                                        this_location.group_instance)

            if should_goto:
                return self._follow_routing_rule(this_location, rule, blocks,
                                                 block_index, path)
Example #12
0
    def test_do_not_go_to_next_question_for_answer(self):
        # Given
        goto_rule = {
            'id': 'next-question',
            'when': [{
                'id': 'my_answer',
                'condition': 'equals',
                'value': 'Yes'
            }]
        }
        answer_store = AnswerStore()
        answer_store.add(Answer(answer_id='my_answer', value='No'))

        self.assertFalse(evaluate_goto(goto_rule, {}, answer_store, 0))
    def test_evaluate_goto_returns_true_when_value_not_contained_in_list(self):

        goto = {
            'id': 'next-question',
            'when': [
                {
                    'id': 'my_answers',
                    'condition': 'not contains',
                    'value': 'answer1'
                }
            ]
        }
        answer_store = AnswerStore({})
        answer_store.add(Answer(answer_id='my_answers', value=['answer2', 'answer3']))

        self.assertTrue(evaluate_goto(goto, get_schema_mock(), {}, answer_store, 0))
Example #14
0
    def test_go_to_next_question_for_answer(self):
        # Given
        goto = {
            'id': 'next-question',
            'when': [{
                'id': 'my_answer',
                'condition': 'equals',
                'value': 'Yes'
            }]
        }
        answer_store = AnswerStore({})

        answer_store.add_or_update(Answer(answer_id='my_answer', value='Yes'))

        self.assertTrue(
            evaluate_goto(goto, get_schema_mock(), {}, answer_store, 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(Answer(answer_id='date_answer', value='2018-02-01'))

        self.assertFalse(evaluate_goto(goto_rule, get_schema_mock(), {}, answer_store, 0))
Example #16
0
    def test_go_to_next_question_for_multiple_answers(self):
        # Given
        goto = {
            '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(Answer(answer_id='my_answer', value='Yes'))
        answer_store.add(Answer(answer_id='my_other_answer', value='2'))

        self.assertTrue(evaluate_goto(goto, {}, answer_store, 0))
Example #17
0
    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'))

        self.assertFalse(
            evaluate_goto(goto_rule, get_schema_mock(), {}, answer_store, 0))
    def test_meta_comparison_missing(self):
        # Given
        goto_rule = {
            'id': 'next-question',
            'when': [
                {
                    'condition': 'equals',
                    'meta': 'varient_flags.does_not_exist.does_not_exist',
                    'value': True
                }
            ]
        }
        answer_store = AnswerStore({})
        answer_store.add(Answer(answer_id='my_answer', value='Yes'))
        metadata = {'varient_flags': {'sexual_identity': True}}

        # When
        goto = evaluate_goto(goto_rule, get_schema_mock(), metadata, answer_store, 0)

        # Then
        self.assertFalse(goto)
Example #19
0
    def build_path(self, blocks, this_location):
        """
        Visits all the blocks from a location forwards and returns path
        taken given a list of answers.

        :param blocks: A list containing all block content in the survey
        :param this_location: The location to visit, represented as a dict
        :return: A list of locations followed through the survey
        """
        path = []
        block_index = 0
        blocks_len = len(blocks)

        # Keep going unless we've hit the last block
        while block_index < blocks_len:
            block_index = PathFinder._block_index_for_location(
                blocks, this_location)
            if block_index is None:
                logger.error('block index is none (invalid location)',
                             **this_location.__dict__)
                return path

            path.append(this_location)
            block = blocks[block_index]["block"]

            # If routing rules exist then a rule must match (i.e. default goto)
            if 'routing_rules' in block and len(block['routing_rules']) > 0:
                original_this_location = copy.copy(this_location)
                for rule in filter(is_goto_rule, block['routing_rules']):
                    should_goto = evaluate_goto(rule['goto'], self.metadata,
                                                self.answer_store,
                                                this_location.group_instance)

                    if should_goto:
                        next_location = copy.copy(this_location)
                        next_location.block_id = rule['goto']['id']

                        next_block_index = PathFinder._block_index_for_location(
                            blocks, next_location)
                        next_precedes_current = next_block_index is not None and next_block_index < block_index

                        if next_precedes_current:
                            self._remove_rule_answers(rule['goto'],
                                                      this_location)

                        this_location = next_location
                        break

                # If we haven't changed location based on routing rules then we can't progress any further
                if this_location == original_this_location:
                    break

            # No routing rules, so if this isn't the last block, step forward a block
            elif block_index < len(blocks) - 1:
                this_location = Location(
                    blocks[block_index + 1]['group_id'],
                    blocks[block_index + 1]['group_instance'],
                    blocks[block_index + 1]['block']['id'])

            # If we've reached last block stop evaluating the path
            else:
                break

        return path