Пример #1
0
def _assemble_mock_expectations(mock, parse_results, file_name, line_number):
    mock_path = getattr(parse_results, 'mock_path', None) or None
    expectations = mock['expectations'].setdefault(mock_path, {'not_called': False, 'calls': []})

    if getattr(parse_results, 'not', None):
        if expectations['calls']:
            raise FixtureSyntaxError(
                'Cannot combine not-called expectations with other expectations for path "{}"'.format(mock_path),
                file_name,
                line_number,
            )
        expectations['not_called'] = True
    else:
        if expectations['not_called']:
            raise FixtureSyntaxError(
                'Cannot combine not-called expectations with other expectations for path "{}"'.format(mock_path),
                file_name,
                line_number,
            )
        value = _get_python_value_from_json(parse_results.json, file_name, line_number)
        try:
            if len(value) != 2 or not isinstance(value[0], list) or not isinstance(value[1], dict):
                raise Exception
        except Exception:
            raise FixtureSyntaxError(
                'Expected call JSON syntax must be in the form: [[arg1, ...], {"kwarg1": val1, ...}]',
                file_name,
                line_number,
            )
        expectations['calls'].append(value)
Пример #2
0
def _ingest_expect_called(test_target, parse_results, file_name, line_number):
    key = (parse_results.stub_service, parse_results.stub_action)
    stub_config = test_target.setdefault('stubbed_actions',
                                         {}).setdefault(key, {})

    if getattr(parse_results, 'not', False):
        if 'expect_request' in stub_config:
            raise FixtureSyntaxError(
                'Cannot combine "expect called" and "expect not called" on the same stub action for {}.{}'
                .format(*key),
                file_name,
                line_number,
            )
        stub_config['expect_not_called'] = True
    else:
        if 'expect_not_called' in stub_config:
            raise FixtureSyntaxError(
                'Cannot combine "expect called" and "expect not called" on the same stub action for {}.{}'
                .format(*key),
                file_name,
                line_number,
            )
        if getattr(parse_results, 'variable_name', None):
            path_put(
                stub_config.setdefault('expect_request', {}),
                parse_results.variable_name,
                get_parsed_data_type_value(parse_results, parse_results.value),
            )
        else:
            stub_config.setdefault('expect_request', {})
Пример #3
0
def _ingest_error_body(test_target, parse_results, file_name, line_number):
    key = (parse_results.stub_service, parse_results.stub_action)
    stub_config = test_target.setdefault('stubbed_actions',
                                         {}).setdefault(key, {})

    if 'body' in stub_config:
        raise FixtureSyntaxError(
            'Cannot combine stub action body and errors (must choose one) for {}.{}'
            .format(*key),
            file_name,
            line_number,
        )

    field = parse_results.field_name
    if not field or not field.strip() or field.strip().lower() == 'none':
        field = None

    message = parse_results.error_message
    if not message or not message.strip() or message.strip().lower() == 'none':
        message = None

    stub_config.setdefault('errors', []).append({
        'code': parse_results.error_code,
        'message': message,
        'field': field,
    })
Пример #4
0
    def ingest_from_parsed_test_fixture(self, action_case, test_case, parse_results, file_name, line_number):
        if 'description' in test_case:
            raise FixtureSyntaxError('Duplicate test description directive for test case', file_name, line_number)

        path_put(
            test_case,
            'description',
            '{}\n{}'.format(parse_results.description.strip(' \t\n'), file_name),
        )
Пример #5
0
    def parse_and_store_freeze_to(target, value, file_name, line_number):
        if not freeze_time:
            raise FixtureSyntaxError(
                'Could not import freezegun to support freeze time syntax. Perhaps you need to install it?',
                file_name,
                line_number,
            )

        if value == 'now':
            freeze_to = None
        else:
            try:
                freeze_to = datetime.datetime.strptime(value,
                                                       '%Y-%m-%dT%H:%M:%SZ')
            except ValueError:
                raise FixtureSyntaxError(
                    'Could not parse datetime value for time freeze',
                    file_name, line_number)

        target['_freezegun_freeze_time'] = freeze_to
Пример #6
0
    def _ingest_directives(self):
        # type: () -> None
        try:
            assert self._grammar is not None
            with codecs.open(self._fixture_file_name,
                             mode='rb',
                             encoding='utf-8') as file_input:
                self._grammar.parseFile(file_input)

            # explicit finalize on EOF to catch case of no blank line at end of file
            self._finalize_test_case('', 0, None)
        except ParseException as e:
            line_text = get_parse_line(e.loc, e.pstr)
            line_number = get_parse_line_number(e.loc, e.pstr)
            offset = get_parse_column(e.loc, e.pstr)
            raise FixtureSyntaxError(
                'Failed to parse line: {line}\nin file: {file}:{line_number}\n{message}'
                .format(
                    line=line_text,
                    file=self._fixture_file_name,
                    line_number=line_number,
                    message=e.msg,
                ),
                file_name=self._fixture_file_name,
                line_number=line_number,
                offset=offset,
                line_text=line_text,
            )
        except DataTypeConversionError as e:
            raise FixtureSyntaxError(
                'Data type conversion error\nin file: {file}:{line_number}\n{message}'
                .format(
                    file=self._fixture_file_name,
                    line_number=self._line_number,
                    message=e.args[0],
                ),
                file_name=self._fixture_file_name,
                line_number=self._line_number,
            )
        except IOError as e:
            raise FixtureLoadError(str(e))
Пример #7
0
def _assemble_mock_path_result(mock, parse_results, file_name, line_number):
    is_exception = is_delete = None
    if getattr(parse_results, 'instruction', None):
        is_exception = parse_results.instruction == 'exception'
        is_delete = parse_results.instruction == 'delete'

    mock_path = parse_results.mock_path

    if is_delete:
        if mock_path.endswith('return_value') or mock_path.endswith('side_effect'):
            raise FixtureSyntaxError(
                'Cannot delete paths ending in special Mock attributes `return_value` or `side_effect`',
                file_name,
                line_number,
            )
        mock['configure'][mock_path] = _DELETE_ATTRIBUTE
    else:
        value = parse_results.value
        if is_exception:
            try:
                if ':' not in value:
                    value = '__builtin__:{}'.format(value) if six.PY2 else 'builtins:{}'.format(value)
                value = fields.PythonPath.resolve_python_path(value)
            except (ValueError, ImportError, AttributeError) as e:
                raise FixtureSyntaxError(
                    'Could not resolve python path for value "{}" due to error: {!r}'.format(value, six.text_type(e)),
                    file_name,
                    line_number,
                )
        else:
            value = _get_python_value_from_json(value, file_name, line_number)

        if mock_path.endswith('side_effect'):
            mock['configure'].setdefault(mock_path, []).append(value)
        else:
            mock['configure'][mock_path] = value
Пример #8
0
def _ingest_action_body(test_target, parse_results, file_name, line_number):
    key = (parse_results.stub_service, parse_results.stub_action)
    stub_config = test_target.setdefault('stubbed_actions', {}).setdefault(key, {})

    if 'errors' in stub_config:
        raise FixtureSyntaxError(
            'Cannot combine stub action body and errors (must choose one) for {}.{}'.format(*key),
            file_name,
            line_number,
        )

    path_put(
        stub_config.setdefault('body', {}),
        parse_results.variable_name,
        get_parsed_data_type_value(parse_results, parse_results.value),
    )
Пример #9
0
    def ingest_from_parsed_test_fixture(self, action_case, test_case, parse_results, file_name, line_number):
        if 'name' in test_case:
            raise FixtureSyntaxError('Duplicate test name directive for test case', file_name, line_number)

        path_put(test_case, 'name', parse_results.name)
Пример #10
0
    def _finalize_test_case(self, active_string, location, _):
        # type: (six.text_type, int, Optional[ParseResults]) -> None
        """
        Called by PyParsing at the end of each test case.

        :param active_string: The contents of the fixture file
        :param location: The file location of the current parsing activity
        """
        self._fixture_source.append('')

        if self._working_action_case:
            # We're done parsing the test case and still need to wrap up the last action in the test case
            for dc in get_all_directives():
                dc().post_parse_test_case_action(
                    self._working_action_case,
                    self._working_test_case or self._global_directives,
                )
            self._working_action_case = {}

        if not self._working_test_case:
            # just a blank line before any test cases, probably after globals or an extra blank line between tests
            return

        self._working_test_case['line_number'] = self._working_test_case_line_number
        self._working_test_case_line_number = 0

        self._working_test_case['fixture_name'] = self._fixture_name
        self._working_test_case['fixture_file_name'] = self._fixture_file_name
        self._working_test_case['source'] = self._working_test_case_source

        line_number = get_parse_line_number(location, active_string)
        if not self._working_test_case.get('name'):

            raise FixtureSyntaxError(
                '{}:{}: Test case without name'.format(self._fixture_file_name, line_number),
                file_name=self._fixture_file_name,
                line_number=line_number - 1,
            )

        if not self._working_test_case.get('description'):
            raise FixtureSyntaxError(
                '{}:{}: Test case without description'.format(self._fixture_file_name, line_number),
                file_name=self._fixture_file_name,
                line_number=line_number - 1,
            )

        if not self._working_test_case.get('actions') and not self._global_directives:
            raise FixtureSyntaxError(
                '{}:{}: Empty test case'.format(self._fixture_file_name, line_number),
                file_name=self._fixture_file_name,
                line_number=line_number - 1,
            )

        if self._global_directives:
            # merge, but make sure current overlays global where there is conflict
            test_case = {}  # type: TestCase

            for path in get_all_paths(self._global_directives, allow_blank=True):
                try:
                    value = path_get(self._global_directives, path)
                    path_put(test_case, path, copy.copy(value))
                except (KeyError, IndexError):
                    raise FixtureSyntaxError(
                        'Invalid path: `{}`'.format(path),
                        file_name=self._fixture_file_name,
                        line_number=line_number,
                    )
            for path in get_all_paths(self._working_test_case, allow_blank=True):
                try:
                    path_put(test_case, path, path_get(self._working_test_case, path))
                except (KeyError, IndexError):
                    raise FixtureSyntaxError(
                        'Invalid path: `{}`'.format(path),
                        file_name=self._fixture_file_name,
                        line_number=line_number,
                    )

            for directive_class in get_all_directives():
                directive_class().post_parse_test_case(test_case)
        else:
            for directive_class in get_all_directives():
                directive_class().post_parse_test_case(self._working_test_case)

            test_case = copy.deepcopy(self._working_test_case)

        test_case['fixture_source'] = self._fixture_source
        self.test_cases.append(test_case)

        self._working_test_case.clear()
        self._working_test_case_source = []
Пример #11
0
def _get_python_value_from_json(json_value, file_name, line_number):
    try:
        return json.loads('{{"value": {}}}'.format(json_value), object_hook=_mock_any_decoder)['value']
    except Exception as e:
        raise FixtureSyntaxError(e.args[0], file_name, line_number)