Beispiel #1
0
    def test_parse_feature_with_ignored_tag(self):
        """
            Test parsing a feature which is not part of the feature tag expression
        """
        feature = """
@some_feature
Feature: some feature
    Scenario: foo
        When I have a normal scenario
        Then I expect nothing special
    """

        with NamedTemporaryFile("w+") as featurefile:
            featurefile.write(feature)
            featurefile.flush()

            core = Mock()
            parser = FeatureParser(
                core,
                featurefile.name,
                1,
                feature_tag_expr=tagexpressions.parse('not some_feature'))
            feature = parser.parse()

            feature.should.be.none
Beispiel #2
0
            def _decorator(self, *args, **kwargs):
                """
                    Actual hook decorator
                """
                if len(args) == 1 and len(kwargs) == 0 and callable(args[0]):
                    func = args[0]
                    # hook was called without argument -> legacy!
                    HookRegistry().register(
                        self._when, what, func
                    )  # pylint: disable=protected-access
                else:
                    # hook was called with argument
                    on_tags = kwargs.get("on_tags")
                    order = kwargs.get("order")

                    if on_tags:
                        expr = tagexpressions.parse(on_tags)
                        on_tags = lambda tags: expr.evaluate(tags)

                    def func(f):
                        HookRegistry().register(
                            self._when, what, f, order, on_tags)
                        return f

                return func
Beispiel #3
0
    def call(self, what, when, only_formatters, tagged_model, *args, **kwargs):
        """Calls a registered Hook"""
        hooks = self._hooks[when][what]
        for hook_impl in hooks:
            if not hook_impl.always:
                if only_formatters and not hook_impl.is_formatter:
                    continue

            #: holds a flag whether or not the Hook actually has to be called
            #  which is depenend on the `on_tags` setting of the HookImpl.
            call_hook = True

            if hook_impl.on_tags:
                tag_expression = tagexpressions.parse(" or ".join(
                    hook_impl.on_tags))
                # get the Tags for models which actually have Tags
                tags = (tagged_model.get_all_tags() if hasattr(
                    tagged_model, "get_all_tags") else [])
                call_hook = tag_expression.evaluate([t.name for t in tags])

            if not call_hook:
                continue

            try:
                hook_impl(tagged_model, *args, **kwargs)
            except Exception as exc:
                raise HookExecError(hook_impl, exc) from exc
Beispiel #4
0
    def __init__(self, command_line_config):
        for opt_key, opt_value in command_line_config.items():
            setattr(self, opt_key, opt_value)

        # make some configuration options easily accessible
        if hasattr(self, "tags") and self.tags:
            try:
                self.tag_expression = parse(self.tags)
            except Exception as exc:
                raise RadishError(
                    "The given Tag Expression '{}' has Syntax Errors. "
                    "Please consult https://github.com/timofurrer/tag-expressions "
                    "for detailed information about the Tag Expression Syntax".
                    format(self.tags)) from exc
        else:
            self.tag_expression = None
Beispiel #5
0
    def test_parse_feature_with_ignored_scenario(self):
        """
            Test parsing a feature which has an ignored scenario by a given tag expression
        """
        feature = """
Feature: some feature
    @good_case
    Scenario: foo
        When I have a normal scenario
        Then I expect nothing special

    @bad_case
    Scenario: bad case
        Given I have the number 1
        When I add 3 to my number
        Then I expect my number not to be 4

    @good_case
    Scenario: foo second it
        When I have a normal scenario
        Then I expect nothing special

    """

        with NamedTemporaryFile("w+") as featurefile:
            featurefile.write(feature)
            featurefile.flush()

            core = Mock()
            parser = FeatureParser(
                core,
                featurefile.name,
                1,
                scenario_tag_expr=tagexpressions.parse('not bad_case'))
            feature = parser.parse()

            feature.scenarios.should.have.length_of(2)
Beispiel #6
0
    Test parsing Feature and Scenario Tags
    """
    # when
    feature = parser.parse()

    # then
    assert feature.tags == expected_feature_tags
    assert len(feature.scenarios) == len(expected_scenarios_tags)
    for scenario, expected_scenario_tags in zip(feature.scenarios,
                                                expected_scenarios_tags):
        assert scenario.tags == expected_scenario_tags


@pytest.mark.parametrize('parser',
                         [('tags-ignored-feature', [], {
                             'tag_expr': tagexpressions.parse('not foo')
                         })],
                         indirect=['parser'])
def test_parse_ignored_feature_via_tag(parser):
    """
    Test parsing a Feature which is ignored because of a Tag
    """
    # when
    feature = parser.parse()

    # then
    assert feature is None


@pytest.mark.parametrize('parser',
                         [('tags-ignored-scenario', [], {
        ],
        2,
    )

    # then
    assert len(scenario.examples[0].steps) == 2
    assert len(scenario.examples[1].steps) == 2
    assert scenario.steps is not scenario.examples[0].steps
    assert scenario.steps is not scenario.examples[1].steps


@pytest.mark.parametrize(
    "tagexpression, scenario_ids, expected_has_to_run",
    [
        (None, [], True),
        (parse("tag-a"), [], True),
        (parse("tag-c"), [], True),
        (parse("tag-X"), [], False),
        (None, [1], True),
        (None, [3], True),
        (None, [-1], False),
        (parse("tag-a"), [-1], False),
        (parse("tag-X"), [1], False),
        (parse("tag-X"), [3], False),
        (parse("tag-a"), [3], True),
    ],
    ids=[
        "no tagexpression, no scenario_ids => RUN",
        "tagexpression match in Scenario Tags, no scenario_ids => RUN",
        "tagexpression match in Feature Tags, no scenario_ids => RUN",
        "tagexpression no match, no scenario_ids => NO RUN",
Beispiel #8
0
def main():
    """
    Entrypont to radish.
    Setup up configuration, loads extensions, reads feature files and runs
    radish
    """

    # note: using doc string for usage, messes up Sphinx documantation
    usage = """
Usage:
    radish show <features>
           [--expand]
           [--no-ansi]
    radish <features>...
           [-b=<basedir> | --basedir=<basedir>]
           [-e | --early-exit]
           [--debug-steps]
           [-t | --with-traceback]
           [-m=<marker> | --marker=<marker>]
           [-p=<profile> | --profile=<profile>]
           [-d | --dry-run]
           [-s=<scenarios> | --scenarios=<scenarios>]
           [--shuffle]
           [--feature-tags=<feature_tags>]
           [--scenario-tags=<scenario_tags>]
           {0}
    radish (-h | --help)
    radish (-v | --version)

Arguments:
    features                                    feature files to run

Options:
    -h --help                                   show this screen
    -v --version                                show version
    -e --early-exit                             stop the run after the first failed step
    --debug-steps                               debugs each step
    -t --with-traceback                         show the Exception traceback when a step fails
    -m=<marker> --marker=<marker>               specify the marker for this run [default: time.time()]
    -p=<profile> --profile=<profile>            specify the profile which can be used in the step/hook implementation
    -b=<basedir> --basedir=<basedir>            set base dir from where the step.py and terrain.py will be loaded [default: $PWD/radish]
    -d --dry-run                                make dry run for the given feature files
    -s=<scenarios> --scenarios=<scenarios>      only run the specified scenarios (comma separated list)
    --shuffle                                   shuttle run order of features and scenarios
    --feature-tags=<feature_tags>               only run features with the given tags
    --scenario-tags=<scenario_tags>             only run scenarios with the given tags
    --expand                                    expand the feature file (all preconditions)
    {1}

(C) Copyright by Timo Furrer <*****@*****.**>
    """

    # load extensions
    load_modules(os.path.join(os.path.dirname(__file__), "extensions"))

    extensions = ExtensionRegistry()
    # add arguments from extensions to the usage
    usage = usage.format(extensions.get_options(), extensions.get_option_description())

    sys.excepthook = catch_unhandled_exception

    # add version to the usage
    arguments = docopt("radish {0}\n{1}".format(__VERSION__, usage), version=__VERSION__)

    # store all arguments to configuration dict in terrain.world
    setup_config(arguments)

    # load needed extensions
    extensions.load(world.config)

    core = Core()

    feature_files = []
    for given_feature in world.config.features:
        if not os.path.exists(given_feature):
            raise FeatureFileNotFoundError(given_feature)

        if os.path.isdir(given_feature):
            feature_files.extend(utils.recursive_glob(given_feature, "*.feature"))
            continue

        feature_files.append(given_feature)

    # parse feature and scenario tag expressions
    feature_tag_expression = None
    if world.config.feature_tags:
        feature_tag_expression = tagexpressions.parse(world.config.feature_tags)

    scenario_tag_expression = None
    if world.config.scenario_tags:
        scenario_tag_expression = tagexpressions.parse(world.config.scenario_tags)
    core.parse_features(feature_files, feature_tag_expression, scenario_tag_expression)

    if not core.features or sum(len(f.scenarios) for f in core.features) == 0:
        print(colorful.bold_red('Error: ') + colorful.red('please specify at least one feature to run'))
        if feature_tag_expression or scenario_tag_expression:
            print(colorful.red('You have specified a feature or scenario expression. Make sure those are valid and actually yield some features to run.'))
        return 1

    argument_dispatcher = [
        ((lambda: world.config.show), show_features),
        ((lambda: True), run_features)
    ]

    # radish command dispatching
    for to_run, method in argument_dispatcher:
        if to_run():
            return method(core)
def test_complex_evaluation(infix, values, expected):
    """Test complex tag expression evaluation"""
    assert parse(infix).evaluate(values) == expected
def test_basic_evaluation(infix, values, expected):
    """Test basic tag expression evaluation"""
    assert parse(infix).evaluate(values) == expected
def test_parser(infix, expected):
    """Test the tag expression parser"""
    assert str(parse(infix)) == expected
Beispiel #12
0
def main(args=None):
    """
    Entrypont to radish.
    Setup up configuration, loads extensions, reads feature files and runs
    radish
    """

    if args is None:
        args = sys.argv[1:]

    # note: using doc string for usage, messes up Sphinx documantation
    usage = """
Usage:
    radish show <features>
           [--expand]
           [--no-ansi]
    radish <features>...
           [-b=<basedir> | --basedir=<basedir>...]
           [-e | --early-exit]
           [--debug-steps]
           [-t | --with-traceback]
           [-m=<marker> | --marker=<marker>]
           [-p=<profile> | --profile=<profile>]
           [-d | --dry-run]
           [-s=<scenarios> | --scenarios=<scenarios>]
           [--shuffle]
           [--tags=<tags>]
           [--wip]
           [-f=<formatter> | --formatter=<formatter>]
           {0}
    radish (-h | --help)
    radish (-v | --version)

Arguments:
    features                                    feature files to run

Options:
    -h --help                                   show this screen
    -v --version                                show version
    -e --early-exit                             stop the run after the first failed step
    --debug-steps                               debugs each step
    -t --with-traceback                         show the Exception traceback when a step fails
    -m=<marker> --marker=<marker>               specify the marker for this run [default: time.time()]
    -p=<profile> --profile=<profile>            specify the profile which can be used in the step/hook implementation
    -b=<basedir> --basedir=<basedir>...         set base dir from where the step.py and terrain.py will be loaded. [default: $PWD/radish]
                                                You can specify -b|--basedir multiple times or split multiple paths with a colon (:) similar to $PATH. All files will be imported.
    -d --dry-run                                make dry run for the given feature files
    -s=<scenarios> --scenarios=<scenarios>      only run the specified scenarios (comma separated list)
    --shuffle                                   shuttle run order of features and scenarios
    --tags=<feature_tags>                       only run Scenarios with the given tags
    --wip                                       expects all tests to fail instead of succeeding
    -f=<formatter> --formatter=<formatter>      the output formatter which should be used. [default: gherkin]
    --expand                                    expand the feature file (all preconditions)
    {1}

(C) Copyright by Timo Furrer <*****@*****.**>
    """

    warnings.simplefilter("always", DeprecationWarning)

    # load extensions
    load_modules(os.path.join(os.path.dirname(__file__), "extensions"))

    extensions = ExtensionRegistry()
    # add arguments from extensions to the usage
    usage = usage.format(extensions.get_options(),
                         extensions.get_option_description())

    sys.excepthook = catch_unhandled_exception

    # add version to the usage
    arguments = docopt("radish {0}\n{1}".format(__VERSION__, usage),
                       argv=args,
                       version=__VERSION__)

    # store all arguments to configuration dict in terrain.world
    setup_config(arguments)

    # disable colors if necessary
    if world.config.no_ansi:
        colorful.disable()
    else:
        colorful.use_8_ansi_colors()

    # load needed extensions
    extensions.load(world.config)

    core = Core()

    if world.config.profile:
        msg = (
            "Command line argument -p/--profile will be removed in a future version.  Please "
            "use -u/--user-data instead.")
        warnings.warn(msg, DeprecationWarning, stacklevel=1)

    feature_files = []
    for given_feature in world.config.features:
        if not os.path.exists(given_feature):
            raise FeatureFileNotFoundError(given_feature)

        if os.path.isdir(given_feature):
            feature_files.extend(
                utils.recursive_glob(given_feature, "*.feature"))
            continue

        feature_files.append(given_feature)

    # parse tag expressions
    tag_expression = None
    if world.config.tags:
        tag_expression = tagexpressions.parse(world.config.tags)

    core.parse_features(feature_files, tag_expression)

    if not core.features or sum(len(f.scenarios) for f in core.features) == 0:
        print(
            colorful.bold_red("Error: ") +
            colorful.red("please specify at least one feature to run"))
        if tag_expression:
            print(
                colorful.red(
                    "You have specified a tag expression. Make sure those are valid and actually yield some Scenarios to run."
                ))
        return 1

    argument_dispatcher = [
        ((lambda: world.config.show), show_features),
        ((lambda: True), run_features),
    ]

    # radish command dispatching
    for to_run, method in argument_dispatcher:
        if to_run():
            return method(core)
Beispiel #13
0
def main(args=None):
    """
    Entrypont to radish.
    Setup up configuration, loads extensions, reads feature files and runs
    radish
    """

    if args is None:
        args = sys.argv[1:]

    # note: using doc string for usage, messes up Sphinx documantation
    usage = """
Usage:
    radish show <features>
           [--expand]
           [--no-ansi]
    radish <features>...
           [-b=<basedir> | --basedir=<basedir>...]
           [-e | --early-exit]
           [--debug-steps]
           [-t | --with-traceback]
           [-m=<marker> | --marker=<marker>]
           [-p=<profile> | --profile=<profile>]
           [-d | --dry-run]
           [-s=<scenarios> | --scenarios=<scenarios>]
           [--shuffle]
           [--tags=<tags>]
           [--wip]
           [-f=<formatter> | --formatter=<formatter>]
           {0}
    radish (-h | --help)
    radish (-v | --version)

Arguments:
    features                                    feature files to run

Options:
    -h --help                                   show this screen
    -v --version                                show version
    -e --early-exit                             stop the run after the first failed step
    --debug-steps                               debugs each step
    -t --with-traceback                         show the Exception traceback when a step fails
    -m=<marker> --marker=<marker>               specify the marker for this run [default: time.time()]
    -p=<profile> --profile=<profile>            specify the profile which can be used in the step/hook implementation
    -b=<basedir> --basedir=<basedir>...         set base dir from where the step.py and terrain.py will be loaded. [default: $PWD/radish]
                                                You can specify -b|--basedir multiple times or split multiple paths with a colon (:) similar to $PATH. All files will be imported.
    -d --dry-run                                make dry run for the given feature files
    -s=<scenarios> --scenarios=<scenarios>      only run the specified scenarios (comma separated list)
    --shuffle                                   shuttle run order of features and scenarios
    --tags=<feature_tags>                       only run Scenarios with the given tags
    --wip                                       expects all tests to fail instead of succeeding
    -f=<formatter> --formatter=<formatter>      the output formatter which should be used. [default: gherkin]
    --expand                                    expand the feature file (all preconditions)
    {1}

(C) Copyright by Timo Furrer <*****@*****.**>
    """

    warnings.simplefilter("always", DeprecationWarning)

    # load extensions
    load_modules(os.path.join(os.path.dirname(__file__), "extensions"))

    extensions = ExtensionRegistry()
    # add arguments from extensions to the usage
    usage = usage.format(extensions.get_options(), extensions.get_option_description())

    sys.excepthook = catch_unhandled_exception

    # add version to the usage
    arguments = docopt(
        "radish {0}\n{1}".format(__VERSION__, usage), argv=args, version=__VERSION__
    )

    # store all arguments to configuration dict in terrain.world
    setup_config(arguments)

    # disable colors if necessary
    if world.config.no_ansi:
        colorful.disable()
    else:
        colorful.use_8_ansi_colors()

    # load needed extensions
    extensions.load(world.config)

    core = Core()

    if world.config.profile:
        msg = (
            "Command line argument -p/--profile will be removed in a future version.  Please "
            "use -u/--user-data instead."
        )
        warnings.warn(msg, DeprecationWarning, stacklevel=1)

    feature_files = []
    for given_feature in world.config.features:
        if not os.path.exists(given_feature):
            raise FeatureFileNotFoundError(given_feature)

        if os.path.isdir(given_feature):
            feature_files.extend(utils.recursive_glob(given_feature, "*.feature"))
            continue

        feature_files.append(given_feature)

    # parse tag expressions
    tag_expression = None
    if world.config.tags:
        tag_expression = tagexpressions.parse(world.config.tags)

    core.parse_features(feature_files, tag_expression)

    if not core.features or sum(len(f.scenarios) for f in core.features) == 0:
        utils.console_write(colorful.bold_red("Error: ")
            + colorful.red("No feature or no scenario specified in at least one of the given feature files")
        )
        if tag_expression:
            utils.console_write(colorful.red(
                    "You have specified a tag expression. Make sure those are valid and actually yield some Scenarios to run."
                )
            )
        return 1

    argument_dispatcher = [
        ((lambda: world.config.show), show_features),
        ((lambda: True), run_features),
    ]

    # radish command dispatching
    for to_run, method in argument_dispatcher:
        if to_run():
            return method(core)
Beispiel #14
0
    """
    # when
    feature = parser.parse()

    # then
    assert feature.tags == expected_feature_tags
    assert len(feature.scenarios) == len(expected_scenarios_tags)
    for scenario, expected_scenario_tags in zip(
        feature.scenarios, expected_scenarios_tags
    ):
        assert scenario.tags == expected_scenario_tags


@pytest.mark.parametrize(
    "parser",
    [("tags-ignored-feature", [], {"tag_expr": tagexpressions.parse("not foo")})],
    indirect=["parser"],
)
def test_parse_ignored_feature_via_tag(parser):
    """
    Test parsing a Feature which is ignored because of a Tag
    """
    # when
    feature = parser.parse()

    # then
    assert feature is None


@pytest.mark.parametrize(
    "parser",
Beispiel #15
0
    """
    # when
    feature = parser.parse()

    # then
    assert feature.tags == expected_feature_tags
    assert len(feature.scenarios) == len(expected_scenarios_tags)
    for scenario, expected_scenario_tags in zip(
        feature.scenarios, expected_scenarios_tags
    ):
        assert scenario.tags == expected_scenario_tags


@pytest.mark.parametrize(
    "parser",
    [("tags-ignored-feature", [], {"tag_expr": tagexpressions.parse("not foo")})],
    indirect=["parser"],
)
def test_parse_ignored_feature_via_tag(parser):
    """
    Test parsing a Feature which is ignored because of a Tag
    """
    # when
    feature = parser.parse()

    # then
    assert feature is None


@pytest.mark.parametrize(
    "parser",