Beispiel #1
0
 def __str__(self):
     arg0 = _text(self.args[0])
     if self.filename:
         filename = _text(self.filename)
         return u'Failed to parse "%s": %s' % (filename, arg0)
     else:
         return u'Failed to parse <string>: %s' % arg0
Beispiel #2
0
 def __str__(self):
     arg0 = _text(self.args[0])
     if self.filename:
         filename = _text(self.filename, sys.getfilesystemencoding())
         return u'Failed to parse "%s": %s' % (filename, arg0)
     else:
         return u"Failed to parse <string>: %s" % arg0
Beispiel #3
0
    def captured(self):
        """Provides access of the captured output data.

        :return: Object that stores the captured output parts (as Captured).
        """
        stdout = None
        stderr = None
        log_out = None
        if self.config.stdout_capture and self.stdout_capture:
            stdout = _text(self.stdout_capture.getvalue())
        if self.config.stderr_capture and self.stderr_capture:
            stderr = _text(self.stderr_capture.getvalue())
        if self.config.log_capture and self.log_capture:
            log_out = _text(self.log_capture.getvalue())
        return Captured(stdout, stderr, log_out)
Beispiel #4
0
    def make_report(self):
        """Makes a detailled report of the captured output data.

        :returns: Report as string.
        """
        report_parts = []
        if self.stdout:
            parts = ["Captured stdout:", _text(self.stdout).rstrip(), ""]
            report_parts.extend(parts)
        if self.stderr:
            parts = ["Captured stderr:", _text(self.stderr).rstrip(), ""]
            report_parts.extend(parts)
        if self.log_output:
            parts = ["Captured logging:", _text(self.log_output)]
            report_parts.extend(parts)
        return self.linesep.join(report_parts).strip()
Beispiel #5
0
 def __str__(self):
     filename = self.filename
     if isinstance(filename, six.binary_type):
         filename = _text(filename, "utf-8")
     if self.line is None:
         return filename
     return u"%s:%d" % (filename, self.line)
Beispiel #6
0
 def doc_string(self, doc_string):
     #self.stream.write('      """' + doc_string.content_type + '\n')
     doc_string = _text(doc_string)
     prefix = u'      '
     self.stream.write(u'%s"""\n' % prefix)
     doc_string = escape_triple_quotes(indent(doc_string, prefix))
     self.stream.write(doc_string)
     self.stream.write(u'\n%s"""\n' % prefix)
     self.stream.flush()
Beispiel #7
0
def test_issue(exception_class, message):
    with pytest.raises(exception_class) as e:
        # runner.run()
        raise_exception(exception_class, message)

    # -- SHOULD NOT RAISE EXCEPTION HERE:
    text = _text(e)
    # -- DIAGNOSTICS:
    print(u"text"+ text)
    print(u"exception: %s" % e)
Beispiel #8
0
 def make_feature_filename(self, feature):
     filename = None
     for path in self.config.paths:
         if feature.filename.startswith(path):
             filename = feature.filename[len(path) + 1:]
             break
     if not filename:
         # -- NOTE: Directory path (subdirs) are taken into account.
         filename = feature.location.relpath(self.config.base_dir)
     filename = filename.rsplit('.', 1)[0]
     filename = filename.replace('\\', '/').replace('/', '.')
     return _text(filename)
Beispiel #9
0
    def feature(self, feature):
        if feature.status == "skipped" and not self.show_skipped:
            # -- SKIP-OUTPUT: If skipped features should not be shown.
            return

        feature_filename = self.make_feature_filename(feature)
        classname = feature_filename
        report = FeatureReportData(feature, feature_filename)

        suite = ElementTree.Element(u'testsuite')
        feature_name = feature.name or feature_filename
        suite.set(u'name', u'%s.%s' % (classname, feature_name))

        # -- BUILD-TESTCASES: From scenarios
        for scenario in feature:
            if isinstance(scenario, ScenarioOutline):
                scenario_outline = scenario
                self._process_scenario_outline(scenario_outline, report)
            else:
                self._process_scenario(scenario, report)

        # -- ADD TESTCASES to testsuite:
        for testcase in report.testcases:
            suite.append(testcase)

        suite.set(u'tests', _text(report.counts_tests))
        suite.set(u'errors', _text(report.counts_errors))
        suite.set(u'failures', _text(report.counts_failed))
        suite.set(u'skipped', _text(report.counts_skipped))  # WAS: skips
        suite.set(u'time', _text(round(feature.duration, 6)))

        if not os.path.exists(self.config.junit_directory):
            # -- ENSURE: Create multiple directory levels at once.
            os.makedirs(self.config.junit_directory)

        tree = ElementTreeWithCDATA(suite)
        report_dirname = self.config.junit_directory
        report_basename = u'TESTS-%s.xml' % feature_filename
        report_filename = os.path.join(report_dirname, report_basename)
        tree.write(codecs.open(report_filename, "wb"), "UTF-8")
Beispiel #10
0
    def report_used_step_definitions(self):
        # -- STEP: Used step definitions.
        # ORDERING: Sort step definitions by file location.
        get_location = lambda x: x[0].location
        step_definition_items = self.step_usage_database.items()
        step_definition_items = sorted(step_definition_items, key=get_location)

        for step_definition, steps in step_definition_items:
            stepdef_text = self.describe_step_definition(step_definition)
            steps_text = [u"  %s %s" % (step.keyword, step.name)
                          for step in steps]
            steps_text.append(stepdef_text)
            max_size = compute_words_maxsize(steps_text)
            if max_size < self.min_location_column:
                max_size = self.min_location_column

            schema = u"%-" + _text(max_size) + "s  # %s\n"
            self.stream.write(schema % (stepdef_text, step_definition.location))
            schema = u"%-" + _text(max_size) + "s  # %s\n"
            for step, step_text in zip(steps, steps_text):
                self.stream.write(schema % (step_text, step.location))
            self.stream.write("\n")
Beispiel #11
0
 def describe_step(self, step):
     status_text = _text(step.status.name)
     if self.show_timings:
         status_text += u" in %0.3fs" % step.duration
     text = u'%s %s ... ' % (step.keyword, step.name)
     text += u'%s\n' % status_text
     if self.show_multiline:
         prefix = make_indentation(2)
         if step.text:
             text += ModelDescriptor.describe_docstring(step.text, prefix)
         elif step.table:
             text += ModelDescriptor.describe_table(step.table, prefix)
     return text
Beispiel #12
0
    def report_steps_by_type(self):
        """Show an overview of the existing step implementations per step type.
        """
        # pylint: disable=too-many-branches
        assert set(self.step_types) == set(self.step_registry.steps.keys())
        language = self.config.lang or "en"
        language_keywords = i18n.languages[language]

        for step_type in self.step_types:
            steps = list(self.step_registry.steps[step_type])
            if step_type != "step":
                steps.extend(self.step_registry.steps["step"])
            if not steps:
                continue

            # -- PREPARE REPORT: For a step-type.
            step_type_name = step_type.upper()
            if step_type == "step":
                step_keyword = "* "
                step_type_name = "GENERIC"
            else:
                # step_keyword = step_type.capitalize()
                keywords = language_keywords[step_type]
                if keywords[0] == u"* " or keywords[0] == u"*":
                    # -- CASE: Skip over generic-step keyword and
                    #    use next keyword (as default) for this step_type.
                    assert len(keywords) > 1
                    step_keyword = keywords[1]
                else:
                    step_keyword = keywords[0]

            steps_text = [u"%s%s" % (step_keyword, step.pattern)
                          for step in steps]
            if self.shows_location:
                max_size = compute_words_maxsize(steps_text)
                if max_size < self.min_location_column:
                    max_size = self.min_location_column
                schema = u"  %-" + _text(max_size) + "s  # %s\n"
            else:
                schema = u"  %s\n"

            # -- REPORT:
            message = "%s STEP DEFINITIONS[%s]:\n"
            self.stream.write(message % (step_type_name, len(steps)))
            for step, step_text in zip(steps, steps_text):
                if self.shows_location:
                    self.stream.write(schema % (step_text, step.location))
                else:
                    self.stream.write(schema % step_text)
            self.stream.write("\n")
Beispiel #13
0
    def report_tag_counts(self):
        # -- PREPARE REPORT:
        ordered_tags = sorted(list(self.tag_counts.keys()))
        tag_maxsize = compute_words_maxsize(ordered_tags)
        schema = "  @%-" + _text(tag_maxsize) + "s %4d    (used for %s)\n"

        # -- EMIT REPORT:
        self.stream.write("TAG COUNTS (alphabetically sorted):\n")
        for tag in ordered_tags:
            tag_data = self.tag_counts[tag]
            counts = len(tag_data)
            details = self.get_tag_count_details(tag_data)
            self.stream.write(schema % (tag, counts, details))
        self.stream.write("\n")
Beispiel #14
0
    def feature(self, feature):
        feature_filename = self.make_feature_filename(feature)
        classname = feature_filename
        report = FeatureReportData(feature, feature_filename)

        suite = ElementTree.Element(u"testsuite")
        feature_name = feature.name or feature_filename
        suite.set(u"name", u"%s.%s" % (classname, feature_name))

        # -- BUILD-TESTCASES: From scenarios
        for scenario in feature:
            if isinstance(scenario, ScenarioOutline):
                scenario_outline = scenario
                self._process_scenario_outline(scenario_outline, report)
            else:
                self._process_scenario(scenario, report)

        # -- ADD TESTCASES to testsuite:
        for testcase in report.testcases:
            suite.append(testcase)

        suite.set(u"tests", _text(report.counts_tests))
        suite.set(u"errors", _text(report.counts_errors))
        suite.set(u"failures", _text(report.counts_failed))
        suite.set(u"skipped", _text(report.counts_skipped))  # WAS: skips
        suite.set(u"time", _text(round(feature.duration, 6)))

        if not os.path.exists(self.config.junit_directory):
            # -- ENSURE: Create multiple directory levels at once.
            os.makedirs(self.config.junit_directory)

        tree = ElementTreeWithCDATA(suite)
        report_dirname = self.config.junit_directory
        report_basename = u"TESTS-%s.xml" % feature_filename
        report_filename = os.path.join(report_dirname, report_basename)
        tree.write(codecs.open(report_filename, "wb"), "UTF-8")
Beispiel #15
0
    def report_tag_counts_by_usage(self):
        # -- PREPARE REPORT:
        compare_tag_counts_size = lambda x: len(self.tag_counts[x])
        ordered_tags = sorted(list(self.tag_counts.keys()),
                              key=compare_tag_counts_size)
        tag_maxsize = compute_words_maxsize(ordered_tags)
        schema = "  @%-" + _text(tag_maxsize) + "s %4d    (used for %s)\n"

        # -- EMIT REPORT:
        self.stream.write("TAG COUNTS (most often used first):\n")
        for tag in ordered_tags:
            tag_data = self.tag_counts[tag]
            counts = len(tag_data)
            details = self.get_tag_count_details(tag_data)
            self.stream.write(schema % (tag, counts, details))
        self.stream.write("\n")
Beispiel #16
0
    def report_tags_by_locations(self):
        # -- PREPARE REPORT:
        locations = set()
        for tag_elements in self.tag_counts.values():
            locations.update([six.text_type(x.location) for x in tag_elements])
        location_column_size = compute_words_maxsize(locations)
        schema = u"    %-" + _text(location_column_size) + "s   %s\n"

        # -- EMIT REPORT:
        self.stream.write("TAG LOCATIONS (alphabetically ordered):\n")
        for tag in sorted(self.tag_counts):
            self.stream.write("  @%s:\n" % tag)
            for element in self.tag_counts[tag]:
                info = u"%s: %s" % (element.keyword, element.name)
                self.stream.write(schema % (element.location, info))
            self.stream.write("\n")
        self.stream.write("\n")
Beispiel #17
0
 def add_step_definition(self, keyword, step_text, func):
     step_location = Match.make_location(func)
     step_type = keyword.lower()
     step_text = _text(step_text)
     step_definitions = self.steps[step_type]
     for existing in step_definitions:
         if self.same_step_definition(existing, step_text, step_location):
             # -- EXACT-STEP: Same step function is already registered.
             # This may occur when a step module imports another one.
             return
         elif existing.match(step_text):
             message = u"%s has already been defined in\n  existing step %s"
             new_step = u"@%s('%s')" % (step_type, step_text)
             existing.step_type = step_type
             existing_step = existing.describe()
             existing_step += u" at %s" % existing.location
             raise AmbiguousStep(message % (new_step, existing_step))
     step_definitions.append(get_matcher(func, step_text))
Beispiel #18
0
    def report_undefined_steps(self):
        if not self.undefined_steps:
            return

        # -- STEP: Undefined steps.
        undefined_steps = sorted(self.undefined_steps,
                                 key=attrgetter("location"))

        steps_text = [u"  %s %s" % (step.keyword, step.name)
                      for step in undefined_steps]
        max_size = compute_words_maxsize(steps_text)
        if max_size < self.min_location_column:
            max_size = self.min_location_column

        self.stream.write("\nUNDEFINED STEPS[%d]:\n" % len(steps_text))
        schema = u"%-" + _text(max_size) + "s  # %s\n"
        for step, step_text in zip(undefined_steps, steps_text):
            self.stream.write(schema % (step_text, step.location))
Beispiel #19
0
    def write_table(self, table):
        """
        Write a ReST simple table.

        EXAMPLE:
        ========================================= ===== ===== ===== =====
        Step Definition                           Given When  Then  Step
        ========================================= ===== ===== ===== =====
        Given a file named "{filename}" contains
        Then the file "{filename}" should ...
        ========================================= ===== ===== ===== =====

        :param table:   Table to render (as `behave.model.Table`)

        .. todo::
            Column alignments
        """
        assert self.stream

        # -- STEP: Determine table layout dimensions
        cols_size = []
        separator_parts = []
        row_schema_parts = []
        for col_index, heading in enumerate(table.headings):
            column = [six.text_type(row[col_index]) for row in table.rows]
            column.append(heading)
            column_size = compute_words_maxsize(column)
            cols_size.append(column_size)
            separator_parts.append("=" * column_size)
            row_schema_parts.append("%-" + _text(column_size) + "s")

        separator = " ".join(separator_parts) + "\n"
        row_schema = " ".join(row_schema_parts) + "\n"
        self.stream.write("\n")     # -- ENSURE: Empty line before table start.
        self.stream.write(separator)
        self.stream.write(row_schema % tuple(table.headings))
        self.stream.write(separator)
        for row in table.rows:
            self.stream.write(row_schema % tuple(row))
        self.stream.write(separator)
        self.stream.write("\n")     # -- ENSURE: Empty line after table end.
Beispiel #20
0
def print_formatters(title=None, stream=None):
    """Prints the list of available formatters and their description.

    :param title:   Optional title (as string).
    :param stream:  Optional, output stream to use (default: sys.stdout).
    """
    from behave.formatter._registry  import format_items
    from operator import itemgetter

    if stream is None:
        stream = sys.stdout
    if title:
        stream.write(u"%s\n" % title)

    format_items = sorted(format_items(resolved=True), key=itemgetter(0))
    format_names = [item[0]  for item in format_items]
    column_size = compute_words_maxsize(format_names)
    schema = u"  %-"+ _text(column_size) +"s  %s\n"
    for name, formatter_class in format_items:
        formatter_description = getattr(formatter_class, "description", "")
        stream.write(schema % (name, formatter_description))
Beispiel #21
0
    def report_unused_step_definitions(self):
        unused_step_definitions = self.select_unused_step_definitions()
        if not unused_step_definitions:
            return

        # -- STEP: Prepare report for unused step definitions.
        # ORDERING: Sort step definitions by file location.
        get_location = lambda x: x.location
        step_definitions = sorted(unused_step_definitions, key=get_location)
        step_texts = [self.describe_step_definition(step_definition)
                      for step_definition in step_definitions]

        max_size = compute_words_maxsize(step_texts)
        if max_size < self.min_location_column-2:
            max_size = self.min_location_column-2

        # -- STEP: Write report.
        schema = u"  %-" + _text(max_size) + "s  # %s\n"
        self.stream.write("UNUSED STEP DEFINITIONS[%d]:\n" % len(step_texts))
        for step_definition, step_text in zip(step_definitions, step_texts):
            self.stream.write(schema % (step_text, step_definition.location))
Beispiel #22
0
    def report_failures(self):
        if self.failures:
            separator = "-" * 80
            self.stream.write(u"%s\n" % separator)
            unicode_errors = 0
            for step in self.failures:
                try:
                    self.stream.write(u"FAILURE in step '%s' (%s):\n" % \
                                      (step.name, step.location))
                    self.stream.write(u"%s\n" % step.error_message)
                    self.stream.write(u"%s\n" % separator)
                except UnicodeError as e:
                    self.stream.write(u"%s while reporting failure in %s\n" % \
                                      (e.__class__.__name__, step.location))
                    self.stream.write(u"ERROR: %s\n" % \
                                      _text(e, encoding=self.stream.encoding))
                    unicode_errors += 1

            if unicode_errors:
                msg = u"HINT: %d unicode errors occured during failure reporting.\n"
                self.stream.write(msg % unicode_errors)
            self.stream.flush()
Beispiel #23
0
def run_behave(config, runner_class=None):
    """Run behave with configuration (and optional runner class).

    :param config:          Configuration object for behave.
    :param runner_class:    Runner class to use or none (use Runner class).
    :return:    0, if successful. Non-zero on failure.

    .. note:: BEST EFFORT, not intended for multi-threaded usage.
    """
    # pylint: disable=too-many-branches, too-many-statements, too-many-return-statements
    if runner_class is None:
        runner_class = Runner

    if config.version:
        print("behave " + BEHAVE_VERSION)
        return 0

    if config.tags_help:
        print(TAG_HELP)
        return 0

    if config.lang_list:
        print_language_list()
        return 0

    if config.lang_help:
        print_language_help(config)
        return 0

    if not config.format:
        config.format = [config.default_format]
    elif config.format and "format" in config.defaults:
        # -- CASE: Formatter are specified in behave configuration file.
        #    Check if formatter are provided on command-line, too.
        if len(config.format) == len(config.defaults["format"]):
            # -- NO FORMATTER on command-line: Add default formatter.
            config.format.append(config.default_format)
    if "help" in config.format:
        print_formatters("Available formatters:")
        return 0

    if len(config.outputs) > len(config.format):
        print("CONFIG-ERROR: More outfiles (%d) than formatters (%d)." % \
              (len(config.outputs), len(config.format)))
        return 1

    # -- MAIN PART:
    failed = True
    try:
        reset_runtime()
        runner = runner_class(config)
        failed = runner.run()
    except ParserError as e:
        print(u"ParserError: %s" % e)
    except ConfigError as e:
        print(u"ConfigError: %s" % e)
    except FileNotFoundError as e:
        print(u"FileNotFoundError: %s" % e)
    except InvalidFileLocationError as e:
        print(u"InvalidFileLocationError: %s" % e)
    except InvalidFilenameError as e:
        print(u"InvalidFilenameError: %s" % e)
    except ConstraintError as e:
        print(u"ConstraintError: %s" % e)
    except Exception as e:
        # -- DIAGNOSTICS:
        text = _text(e)
        print(u"Exception %s: %s" % (e.__class__.__name__, text))
        raise

    if config.show_snippets and runner.undefined_steps:
        print_undefined_step_snippets(runner.undefined_steps,
                                      colored=config.color)

    return_code = 0
    if failed:
        return_code = 1
    return return_code
Beispiel #24
0
    def _process_scenario(self, scenario, report):
        """
        Process a scenario and append information to JUnit report object.
        This corresponds to a JUnit testcase:

          * testcase.@classname = f(filename) +'.'+ feature.name
          * testcase.@name   = scenario.name
          * testcase.@status = scenario.status
          * testcase.@time   = scenario.duration

        Distinguishes now between failures and errors.
        Failures are AssertationErrors: expectation is violated/not met.
        Errors are unexpected RuntimeErrors (all other exceptions).

        If a failure/error occurs, the step, that caused the failure,
        and its location are provided now.

        :param scenario:  Scenario to process.
        :param report:    Context object to store/add info to (outgoing param).
        """
        # pylint: disable=too-many-locals, too-many-branches, too-many-statements
        assert isinstance(scenario, Scenario)
        assert not isinstance(scenario, ScenarioOutline)
        if scenario.status != "skipped" or self.show_skipped:
            # -- NOTE: Count only if not-skipped or skipped should be shown.
            report.counts_tests += 1
        classname = report.classname
        feature = report.feature
        feature_name = feature.name
        if not feature_name:
            feature_name = self.make_feature_filename(feature)

        case = ElementTree.Element('testcase')
        case.set(u'classname', u'%s.%s' % (classname, feature_name))
        case.set(u'name', scenario.name or '')
        case.set(u'status', scenario.status)
        case.set(u'time', _text(round(scenario.duration, 6)))

        step = None
        if scenario.status == 'failed':
            for status in ('failed', 'undefined'):
                step = self.select_step_with_status(status, scenario)
                if step:
                    break
            assert step, "OOPS: No failed step found in scenario: %s" % scenario.name
            assert step.status in ('failed', 'undefined')
            element_name = 'failure'
            if isinstance(step.exception, (AssertionError, type(None))):
                # -- FAILURE: AssertionError
                report.counts_failed += 1
            else:
                # -- UNEXPECTED RUNTIME-ERROR:
                report.counts_errors += 1
                element_name = 'error'
            # -- COMMON-PART:
            failure = ElementTree.Element(element_name)
            step_text = self.describe_step(step).rstrip()
            text = u"\nFailing step: %s\nLocation: %s\n" % (step_text,
                                                            step.location)
            message = _text(step.exception)
            if len(message) > 80:
                message = message[:80] + "..."
            failure.set(u'type', step.exception.__class__.__name__)
            failure.set(u'message', message)
            text += _text(step.error_message)
            failure.append(CDATA(text))
            case.append(failure)
        elif scenario.status in ("skipped", "untested") and self.show_skipped:
            report.counts_skipped += 1
            step = self.select_step_with_status('undefined', scenario)
            if step:
                # -- UNDEFINED-STEP:
                report.counts_failed += 1
                failure = ElementTree.Element(u'failure')
                failure.set(u'type', u'undefined')
                failure.set(u'message', (u'Undefined Step: %s' % step.name))
                case.append(failure)
            else:
                skip = ElementTree.Element(u'skipped')
                case.append(skip)

        # Create stdout section for each test case
        stdout = ElementTree.Element(u'system-out')
        text = self.describe_scenario(scenario)

        # Append the captured standard output
        if scenario.stdout:
            output = _text(scenario.stdout)
            text += u'\nCaptured stdout:\n%s\n' % output
        stdout.append(CDATA(text))
        case.append(stdout)

        # Create stderr section for each test case
        if scenario.stderr:
            stderr = ElementTree.Element(u'system-err')
            output = _text(scenario.stderr)
            text = u'\nCaptured stderr:\n%s\n' % output
            stderr.append(CDATA(text))
            case.append(stderr)

        if scenario.status != "skipped" or self.show_skipped:
            report.testcases.append(case)
Beispiel #25
0
    def _process_scenario(self, scenario, report):
        """
        Process a scenario and append information to JUnit report object.
        This corresponds to a JUnit testcase:

          * testcase.@classname = f(filename) +'.'+ feature.name
          * testcase.@name   = scenario.name
          * testcase.@status = scenario.status
          * testcase.@time   = scenario.duration

        Distinguishes now between failures and errors.
        Failures are AssertationErrors: expectation is violated/not met.
        Errors are unexpected RuntimeErrors (all other exceptions).

        If a failure/error occurs, the step, that caused the failure,
        and its location are provided now.

        :param scenario:  Scenario to process.
        :param report:    Context object to store/add info to (outgoing param).
        """
        assert isinstance(scenario, Scenario)
        assert not isinstance(scenario, ScenarioOutline)
        report.counts_tests += 1
        classname = report.classname
        feature   = report.feature
        feature_name = feature.name
        if not feature_name:
            feature_name = self.make_feature_filename(feature)

        case = ElementTree.Element('testcase')
        case.set(u'classname', u'%s.%s' % (classname, feature_name))
        case.set(u'name', scenario.name or '')
        case.set(u'status', scenario.status)
        case.set(u'time', _text(round(scenario.duration, 6)))

        step = None
        if scenario.status == 'failed':
            for status in ('failed', 'undefined'):
                step = self.select_step_with_status(status, scenario)
                if step:
                    break
            assert step, "OOPS: No failed step found in scenario: %s" % scenario.name
            assert step.status in ('failed', 'undefined')
            element_name = 'failure'
            if isinstance(step.exception, (AssertionError, type(None))):
                # -- FAILURE: AssertionError
                report.counts_failed += 1
            else:
                # -- UNEXPECTED RUNTIME-ERROR:
                report.counts_errors += 1
                element_name = 'error'
            # -- COMMON-PART:
            failure = ElementTree.Element(element_name)
            step_text = self.describe_step(step).rstrip()
            text = u"\nFailing step: %s\nLocation: %s\n" % (step_text, step.location)
            message = _text(step.exception)
            if len(message) > 80:
                message = message[:80] + "..."
            failure.set(u'type', step.exception.__class__.__name__)
            failure.set(u'message', message)
            text += _text(step.error_message)
            failure.append(CDATA(text))
            case.append(failure)
        elif scenario.status in ('skipped', 'untested'):
            report.counts_skipped += 1
            step = self.select_step_with_status('undefined', scenario)
            if step:
                # -- UNDEFINED-STEP:
                report.counts_failed += 1
                failure = ElementTree.Element(u'failure')
                failure.set(u'type', u'undefined')
                failure.set(u'message', (u'Undefined Step: %s' % step.name))
                case.append(failure)
            else:
                skip = ElementTree.Element(u'skipped')
                case.append(skip)

        # Create stdout section for each test case
        stdout = ElementTree.Element(u'system-out')
        text = self.describe_scenario(scenario)

        # Append the captured standard output
        if scenario.stdout:
            output = _text(scenario.stdout)
            text += u'\nCaptured stdout:\n%s\n' % output
        stdout.append(CDATA(text))
        case.append(stdout)

        # Create stderr section for each test case
        if scenario.stderr:
            stderr = ElementTree.Element(u'system-err')
            output = _text(scenario.stderr)
            text = u'\nCaptured stderr:\n%s\n' % output
            stderr.append(CDATA(text))
            case.append(stderr)

        report.testcases.append(case)
Beispiel #26
0
    def _process_scenario(self, scenario, report):
        """Process a scenario and append information to JUnit report object.
        This corresponds to a JUnit testcase:

          * testcase.@classname = f(filename) +'.'+ feature.name
          * testcase.@name   = scenario.name
          * testcase.@status = scenario.status
          * testcase.@time   = scenario.duration

        Distinguishes now between failures and errors.
        Failures are AssertationErrors: expectation is violated/not met.
        Errors are unexpected RuntimeErrors (all other exceptions).

        If a failure/error occurs, the step, that caused the failure,
        and its location are provided now.

        :param scenario:  Scenario to process.
        :param report:    Context object to store/add info to (outgoing param).
        """
        # pylint: disable=too-many-locals, too-many-branches, too-many-statements
        assert isinstance(scenario, Scenario)
        assert not isinstance(scenario, ScenarioOutline)
        if scenario.status != Status.skipped or self.show_skipped:
            # -- NOTE: Count only if not-skipped or skipped should be shown.
            report.counts_tests += 1
        classname = report.classname
        feature = report.feature
        feature_name = feature.name
        if not feature_name:
            feature_name = self.make_feature_filename(feature)

        case = ElementTree.Element('testcase')
        case.set(u"classname", u"%s.%s" % (classname, feature_name))
        case.set(u"name", scenario.name or "")
        case.set(u"status", scenario.status.name)
        case.set(u"time", _text(round(scenario.duration, 6)))
        case.set(u"tags", _text(self.describe_tags(scenario.tags)))

        step = None
        failing_step = None
        if scenario.status == Status.failed:
            for status in (Status.failed, Status.undefined):
                step = self.select_step_with_status(status, scenario)
                if step:
                    break
            # -- NOTE: Scenario may fail now due to hook-errors.
            element_name = "failure"
            if step and isinstance(step.exception,
                                   (AssertionError, type(None))):
                # -- FAILURE: AssertionError
                assert step.status in (Status.failed, Status.undefined)
                report.counts_failed += 1
            else:
                # -- UNEXPECTED RUNTIME-ERROR:
                report.counts_errors += 1
                element_name = "error"
            # -- COMMON-PART:
            failure = ElementTree.Element(element_name)
            if step:
                step_text = self.describe_step(step).rstrip()
                text = u"\nFailing step: %s\nLocation: %s\n" % \
                       (step_text, step.location)
                message = _text(step.exception)
                failure.set(u'type', step.exception.__class__.__name__)
                failure.set(u'message', message)
                text += _text(step.error_message)
            else:
                # -- MAYBE: Hook failure before any step is executed.
                failure_type = "UnknownError"
                if scenario.exception:
                    failure_type = scenario.exception.__class__.__name__
                failure.set(u'type', failure_type)
                failure.set(u'message', scenario.error_message or "")
                traceback_lines = traceback.format_tb(scenario.exc_traceback)
                traceback_lines.insert(0, u"Traceback:\n")
                text = _text(u"".join(traceback_lines))
            failure.append(CDATA(text))
            case.append(failure)
        elif (scenario.status in (Status.skipped, Status.untested)
              and self.show_skipped):
            report.counts_skipped += 1
            step = self.select_step_with_status(Status.undefined, scenario)
            if step:
                # -- UNDEFINED-STEP:
                report.counts_failed += 1
                failure = ElementTree.Element(u"failure")
                failure.set(u"type", u"undefined")
                failure.set(u"message", (u"Undefined Step: %s" % step.name))
                case.append(failure)
            else:
                skip = ElementTree.Element(u'skipped')
                case.append(skip)

        if scenario.status_error == StatusError.none:
            case.set(u"status_error", "none")
Beispiel #27
0
 def add_step_definition(self, keyword, step_text, func, matcher=None):
     step_type = keyword.lower()
     step_text = _text(step_text)
     self.steps[step_type].append(self.get_matcher(func, step_text,
                                                   matcher))
Beispiel #28
0
        if scenario.status_error == StatusError.none:
            case.set(u"status_error", "none")
        elif scenario.status_error == StatusError.timeout:
            case.set(u"status_error", "timeout")
        elif scenario.status_error == StatusError.crash:
            case.set(u"status_error", "crash")

        # Create stdout section for each test case
        stdout = ElementTree.Element(u"system-out")
        text = u""
        if self.show_scenarios:
            text = self.describe_scenario(scenario)

        # Append the captured standard output
        if scenario.captured.stdout:
            output = _text(scenario.captured.stdout)
            text += u"\nCaptured stdout:\n%s\n" % output
        stdout.append(CDATA(text))
        case.append(stdout)

        # Create stderr section for each test case
        if scenario.captured.stderr:
            stderr = ElementTree.Element(u"system-err")
            output = _text(scenario.captured.stderr)
            text = u"\nCaptured stderr:\n%s\n" % output
            stderr.append(CDATA(text))
            case.append(stderr)

        if scenario.status != Status.skipped or self.show_skipped:
            report.testcases.append(case)
Beispiel #29
0
def main(args=None):
    config = Configuration(args)
    if config.version:
        print("behave " + __version__)
        return 0

    if config.tags_help:
        print(TAG_HELP)
        return 0

    if config.lang_list:
        from behave.i18n import languages
        iso_codes = languages.keys()
        iso_codes.sort()
        print("Languages available:")
        for iso_code in iso_codes:
            native = languages[iso_code]['native'][0]
            name = languages[iso_code]['name'][0]
            print(u'%s: %s / %s' % (iso_code, native, name))
        return 0

    if config.lang_help:
        from behave.i18n import languages
        if config.lang_help not in languages:
            print('%s is not a recognised language: try --lang-list' % \
                    config.lang_help)
            return 1
        trans = languages[config.lang_help]
        print(u"Translations for %s / %s" % (trans['name'][0],
                                             trans['native'][0]))
        for kw in trans:
            if kw in 'name native'.split():
                continue
            print(u'%16s: %s' % (kw.title().replace('_', ' '),
                  u', '.join(w for w in trans[kw] if w != '*')))
        return 0

    if not config.format:
        config.format = [ config.default_format ]
    elif config.format and "format" in config.defaults:
        # -- CASE: Formatter are specified in behave configuration file.
        #    Check if formatter are provided on command-line, too.
        if len(config.format) == len(config.defaults["format"]):
            # -- NO FORMATTER on command-line: Add default formatter.
            config.format.append(config.default_format)
    if 'help' in config.format:
        print_formatters("Available formatters:")
        return 0

    if len(config.outputs) > len(config.format):
        print('CONFIG-ERROR: More outfiles (%d) than formatters (%d).' % \
              (len(config.outputs), len(config.format)))
        return 1

    failed = True
    runner = Runner(config)
    try:
        failed = runner.run()
    except ParserError as e:
        print(u"ParseError: %s" % e)
    except ConfigError as e:
        print(u"ConfigError: %s" % e)
    except FileNotFoundError as e:
        print(u"FileNotFoundError: %s" % e)
    except InvalidFileLocationError as e:
        print(u"InvalidFileLocationError: %s" % e)
    except InvalidFilenameError as e:
        print(u"InvalidFilenameError: %s" % e)
    except Exception as e:
        # -- DIAGNOSTICS:
        text = _text(e)
        print(u"Exception %s: %s" % (e.__class__.__name__, text))
        raise

    if config.show_snippets and runner.undefined_steps:
        print_undefined_step_snippets(runner.undefined_steps,
                                      colored=config.color)

    return_code = 0
    if failed:
        return_code = 1
    return return_code
Beispiel #30
0
    def _process_scenario(self, scenario, report):
        """Process a scenario and append information to JUnit report object.
        This corresponds to a JUnit testcase:

          * testcase.@classname = f(filename) +'.'+ feature.name
          * testcase.@name   = scenario.name
          * testcase.@status = scenario.status
          * testcase.@time   = scenario.duration

        Distinguishes now between failures and errors.
        Failures are AssertationErrors: expectation is violated/not met.
        Errors are unexpected RuntimeErrors (all other exceptions).

        If a failure/error occurs, the step, that caused the failure,
        and its location are provided now.

        :param scenario:  Scenario to process.
        :param report:    Context object to store/add info to (outgoing param).
        """
        # pylint: disable=too-many-locals, too-many-branches, too-many-statements
        assert isinstance(scenario, Scenario)
        assert not isinstance(scenario, ScenarioOutline)
        if scenario.status != Status.skipped or self.show_skipped:
            # -- NOTE: Count only if not-skipped or skipped should be shown.
            report.counts_tests += 1
        classname = report.classname
        feature = report.feature
        feature_name = feature.name
        if not feature_name:
            feature_name = self.make_feature_filename(feature)

        case = ElementTree.Element('testcase')
        case.set(u"classname", u"%s.%s" % (classname, feature_name))
        case.set(u"name", scenario.name or "")
        case.set(u"status", scenario.status.name)
        case.set(u"time", _text(round(scenario.duration, 6)))

        step = None
        failing_step = None
        if scenario.status == Status.failed:
            for status in (Status.failed, Status.undefined):
                step = self.select_step_with_status(status, scenario)
                if step:
                    break
            # -- NOTE: Scenario may fail now due to hook-errors.
            element_name = "failure"
            if step and isinstance(step.exception, (AssertionError, type(None))):
                # -- FAILURE: AssertionError
                assert step.status in (Status.failed, Status.undefined)
                report.counts_failed += 1
            else:
                # -- UNEXPECTED RUNTIME-ERROR:
                report.counts_errors += 1
                element_name = "error"
            # -- COMMON-PART:
            failure = ElementTree.Element(element_name)
            if step:
                step_text = self.describe_step(step).rstrip()
                text = u"\nFailing step: %s\nLocation: %s\n" % \
                       (step_text, step.location)
                message = _text(step.exception)
                failure.set(u'type', step.exception.__class__.__name__)
                failure.set(u'message', message)
                text += _text(step.error_message)
            else:
                # -- MAYBE: Hook failure before any step is executed.
                failure_type = "UnknownError"
                if scenario.exception:
                    failure_type = scenario.exception.__class__.__name__
                failure.set(u'type', failure_type)
                failure.set(u'message', scenario.error_message or "")
                traceback_lines = traceback.format_tb(scenario.exc_traceback)
                traceback_lines.insert(0, u"Traceback:\n")
                text = _text(u"".join(traceback_lines))
            failure.append(CDATA(text))
            case.append(failure)
        elif (scenario.status in (Status.skipped, Status.untested)
              and self.show_skipped):
            report.counts_skipped += 1
            step = self.select_step_with_status(Status.undefined, scenario)
            if step:
                # -- UNDEFINED-STEP:
                report.counts_failed += 1
                failure = ElementTree.Element(u"failure")
                failure.set(u"type", u"undefined")
                failure.set(u"message", (u"Undefined Step: %s" % step.name))
                case.append(failure)
            else:
                skip = ElementTree.Element(u'skipped')
                case.append(skip)

        # Create stdout section for each test case
        stdout = ElementTree.Element(u"system-out")
        text = u""
        if self.show_scenarios:
            text = self.describe_scenario(scenario)

        # Append the captured standard output
        if scenario.captured.stdout:
            output = _text(scenario.captured.stdout)
            text += u"\nCaptured stdout:\n%s\n" % output
        stdout.append(CDATA(text))
        case.append(stdout)

        # Create stderr section for each test case
        if scenario.captured.stderr:
            stderr = ElementTree.Element(u"system-err")
            output = _text(scenario.captured.stderr)
            text = u"\nCaptured stderr:\n%s\n" % output
            stderr.append(CDATA(text))
            case.append(stderr)

        if scenario.status != Status.skipped or self.show_skipped:
            report.testcases.append(case)
Beispiel #31
0
    def run(cls, command, cwd=".", **kwargs):
        """
        Make a subprocess call, collect its output and returncode.
        Returns CommandResult instance as ValueObject.
        """
        assert isinstance(command, six.string_types)
        command_result = CommandResult()
        command_result.command = command
        use_shell = cls.USE_SHELL
        if "shell" in kwargs:
            use_shell = kwargs.pop("shell")

        # -- BUILD COMMAND ARGS:
        if six.PY2 and isinstance(command, six.text_type):
            # -- PREPARE-FOR: shlex.split()
            # In PY2, shlex.split() requires bytes string (non-unicode).
            # In PY3, shlex.split() accepts unicode string.
            command = codecs.encode(command, "utf-8")
        cmdargs = shlex.split(command)

        # -- TRANSFORM COMMAND (optional)
        command0 = cmdargs[0]
        real_command = cls.COMMAND_MAP.get(command0, None)
        if real_command:
            cmdargs0 = real_command.split()
            cmdargs = cmdargs0 + cmdargs[1:]
        preprocessors = cls.PREPROCESSOR_MAP.get(command0)
        if preprocessors:
            cmdargs = cls.preprocess_command(preprocessors, cmdargs, command, cwd)


        # -- RUN COMMAND:
        try:
            process = subprocess.Popen(cmdargs,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE,
                            universal_newlines=True,
                            shell=use_shell,
                            cwd=cwd, **kwargs)
            out, err = process.communicate()
            if six.PY2: # py3: we get unicode strings, py2 not
                # default_encoding = "UTF-8"
                out = _text(out, process.stdout.encoding)
                err = _text(err, process.stderr.encoding)
            process.poll()
            assert process.returncode is not None
            command_result.stdout = out
            command_result.stderr = err
            command_result.returncode = process.returncode
            if cls.DEBUG:
                print("shell.cwd={0}".format(kwargs.get("cwd", None)))
                print("shell.command: {0}".format(" ".join(cmdargs)))
                print("shell.command.output:\n{0};".format(command_result.output))
        except OSError as e:
            command_result.stderr = u"OSError: %s" % e
            command_result.returncode = e.errno
            assert e.errno != 0

        postprocessors = cls.POSTPROCESSOR_MAP.get(command0)
        if postprocessors:
            command_result = cls.postprocess_command(postprocessors, command_result)
        return command_result
Beispiel #32
0
def run_behave(config, runner_class=None):
    """Run behave with configuration (and optional runner class).

    :param config:          Configuration object for behave.
    :param runner_class:    Runner class to use or none (use Runner class).
    :return:    0, if successful. Non-zero on failure.

    .. note:: BEST EFFORT, not intended for multi-threaded usage.
    """
    # pylint: disable=too-many-branches, too-many-statements, too-many-return-statements
    if runner_class is None:
        runner_class = Runner

    if config.version:
        print("behave " + __version__)
        return 0

    if config.tags_help:
        print(TAG_HELP)
        return 0

    if config.lang_list:
        print_language_list()
        return 0

    if config.lang_help:
        print_language_help(config)
        return 0

    if not config.format:
        config.format = [config.default_format]
    elif config.format and "format" in config.defaults:
        # -- CASE: Formatter are specified in behave configuration file.
        #    Check if formatter are provided on command-line, too.
        if len(config.format) == len(config.defaults["format"]):
            # -- NO FORMATTER on command-line: Add default formatter.
            config.format.append(config.default_format)
    if "help" in config.format:
        print_formatters("Available formatters:")
        return 0

    if len(config.outputs) > len(config.format):
        print("CONFIG-ERROR: More outfiles (%d) than formatters (%d)." % \
              (len(config.outputs), len(config.format)))
        return 1

    # -- MAIN PART:
    failed = True
    try:
        reset_runtime()
        runner = runner_class(config)
        failed = runner.run()
    except ParserError as e:
        print(u"ParserError: %s" % e)
    except ConfigError as e:
        print(u"ConfigError: %s" % e)
    except FileNotFoundError as e:
        print(u"FileNotFoundError: %s" % e)
    except InvalidFileLocationError as e:
        print(u"InvalidFileLocationError: %s" % e)
    except InvalidFilenameError as e:
        print(u"InvalidFilenameError: %s" % e)
    except Exception as e:
        # -- DIAGNOSTICS:
        text = _text(e)
        print(u"Exception %s: %s" % (e.__class__.__name__, text))
        raise

    if config.show_snippets and runner.undefined_steps:
        print_undefined_step_snippets(runner.undefined_steps,
                                      colored=config.color)

    return_code = 0
    if failed:
        return_code = 1
    return return_code
Beispiel #33
0
def main(args=None):
    config = Configuration(args)
    if config.version:
        print("behave " + __version__)
        return 0

    if config.tags_help:
        print(TAG_HELP)
        return 0

    if config.lang_list:
        from behave.i18n import languages
        stdout = sys.stdout
        if six.PY2:
            # -- PYTHON2: Overcome implicit encode problems (encoding=ASCII).
            stdout = codecs.getwriter("UTF-8")(sys.stdout)
        iso_codes = languages.keys()
        print("Languages available:")
        for iso_code in sorted(iso_codes):
            native = languages[iso_code]["native"][0]
            name = languages[iso_code]["name"][0]
            print(u'%s: %s / %s' % (iso_code, native, name), file=stdout)
        return 0

    if config.lang_help:
        from behave.i18n import languages
        if config.lang_help not in languages:
            print('%s is not a recognised language: try --lang-list' % \
                    config.lang_help)
            return 1
        trans = languages[config.lang_help]
        print(u"Translations for %s / %s" %
              (trans['name'][0], trans['native'][0]))
        for kw in trans:
            if kw in 'name native'.split():
                continue
            print(u'%16s: %s' % (kw.title().replace('_', ' '), u', '.join(
                w for w in trans[kw] if w != '*')))
        return 0

    if not config.format:
        config.format = [config.default_format]
    elif config.format and "format" in config.defaults:
        # -- CASE: Formatter are specified in behave configuration file.
        #    Check if formatter are provided on command-line, too.
        if len(config.format) == len(config.defaults["format"]):
            # -- NO FORMATTER on command-line: Add default formatter.
            config.format.append(config.default_format)
    if 'help' in config.format:
        print_formatters("Available formatters:")
        return 0

    if len(config.outputs) > len(config.format):
        print('CONFIG-ERROR: More outfiles (%d) than formatters (%d).' % \
              (len(config.outputs), len(config.format)))
        return 1

    failed = True
    runner = Runner(config)
    try:
        failed = runner.run()
    except ParserError as e:
        print(u"ParseError: %s" % e)
    except ConfigError as e:
        print(u"ConfigError: %s" % e)
    except FileNotFoundError as e:
        print(u"FileNotFoundError: %s" % e)
    except InvalidFileLocationError as e:
        print(u"InvalidFileLocationError: %s" % e)
    except InvalidFilenameError as e:
        print(u"InvalidFilenameError: %s" % e)
    except Exception as e:
        # -- DIAGNOSTICS:
        text = _text(e)
        print(u"Exception %s: %s" % (e.__class__.__name__, text))
        raise

    if config.show_snippets and runner.undefined_steps:
        print_undefined_step_snippets(runner.undefined_steps,
                                      colored=config.color)

    return_code = 0
    if failed:
        return_code = 1
    return return_code
Beispiel #34
0
def run_behave(config, runner_class=None):
    """Run behave with configuration.

    :param config:          Configuration object for behave.
    :param runner_class:    Runner class to use or none (use Runner class).
    :return:    0, if successful. Non-zero on failure.

    .. note:: BEST EFFORT, not intended for multi-threaded usage.
    """
    # pylint: disable=too-many-branches, too-many-statements, too-many-return-statements
    if runner_class is None:
        runner_class = Runner

    if config.version:
        print("behave " + __version__)
        return 0

    if config.tags_help:
        print(TAG_HELP)
        return 0

    if config.lang_list:
        from behave.i18n import languages
        stdout = sys.stdout
        if six.PY2:
            # -- PYTHON2: Overcome implicit encode problems (encoding=ASCII).
            stdout = codecs.getwriter("UTF-8")(sys.stdout)
        iso_codes = list(languages.keys())
        print("Languages available:")
        for iso_code in sorted(iso_codes):
            native = languages[iso_code]["native"][0]
            name = languages[iso_code]["name"][0]
            print("%s: %s / %s" % (iso_code, native, name), file=stdout)
        return 0

    if config.lang_help:
        from behave.i18n import languages
        if config.lang_help not in languages:
            print("%s is not a recognised language: try --lang-list" % \
                    config.lang_help)
            return 1
        trans = languages[config.lang_help]
        print("Translations for %s / %s" %
              (trans["name"][0], trans["native"][0]))
        for kw in trans:
            if kw in "name native".split():
                continue
            print("%16s: %s" % (kw.title().replace("_", " "), ", ".join(
                w for w in trans[kw] if w != "*")))
        return 0

    if not config.format:
        config.format = [config.default_format]
    elif config.format and "format" in config.defaults:
        # -- CASE: Formatter are specified in behave configuration file.
        #    Check if formatter are provided on command-line, too.
        if len(config.format) == len(config.defaults["format"]):
            # -- NO FORMATTER on command-line: Add default formatter.
            config.format.append(config.default_format)
    if "help" in config.format:
        print_formatters("Available formatters:")
        return 0

    if len(config.outputs) > len(config.format):
        print("CONFIG-ERROR: More outfiles (%d) than formatters (%d)." % \
              (len(config.outputs), len(config.format)))
        return 1

    # -- MAIN PART:
    failed = True
    try:
        reset_runtime()
        runner = runner_class(config)
        failed = runner.run()
    except ParserError as e:
        print("ParserError: %s" % e)
    except ConfigError as e:
        print("ConfigError: %s" % e)
    except FileNotFoundError as e:
        print("FileNotFoundError: %s" % e)
    except InvalidFileLocationError as e:
        print("InvalidFileLocationError: %s" % e)
    except InvalidFilenameError as e:
        print("InvalidFilenameError: %s" % e)
    except Exception as e:
        # -- DIAGNOSTICS:
        text = _text(e)
        print("Exception %s: %s" % (e.__class__.__name__, text))
        raise

    if config.show_snippets and runner.undefined_steps:
        print_undefined_step_snippets(runner.undefined_steps,
                                      colored=config.color)

    return_code = 0
    if failed:
        return_code = 1
    return return_code
Beispiel #35
0
def run_behave(config, runner_class=None):
    """Run behave with configuration.

    :param config:          Configuration object for behave.
    :param runner_class:    Runner class to use or none (use Runner class).
    :return:    0, if successful. Non-zero on failure.

    .. note:: BEST EFFORT, not intended for multi-threaded usage.
    """
    # pylint: disable=too-many-branches, too-many-statements, too-many-return-statements
    if runner_class is None:
        runner_class = Runner

    if config.version:
        print("behave " + __version__)
        return 0

    if config.tags_help:
        print(TAG_HELP)
        return 0

    if config.lang_list:
        from behave.i18n import languages
        stdout = sys.stdout
        if six.PY2:
            # -- PYTHON2: Overcome implicit encode problems (encoding=ASCII).
            stdout = codecs.getwriter("UTF-8")(sys.stdout)
        iso_codes = languages.keys()
        print("Languages available:")
        for iso_code in sorted(iso_codes):
            native = languages[iso_code]["native"][0]
            name = languages[iso_code]["name"][0]
            print(u"%s: %s / %s" % (iso_code, native, name), file=stdout)
        return 0

    if config.lang_help:
        from behave.i18n import languages
        if config.lang_help not in languages:
            print("%s is not a recognised language: try --lang-list" % \
                    config.lang_help)
            return 1
        trans = languages[config.lang_help]
        print(u"Translations for %s / %s" % (trans["name"][0],
                                             trans["native"][0]))
        for kw in trans:
            if kw in "name native".split():
                continue
            print(u"%16s: %s" % (kw.title().replace("_", " "),
                                 u", ".join(w for w in trans[kw] if w != "*")))
        return 0

    if not config.format:
        config.format = [config.default_format]
    elif config.format and "format" in config.defaults:
        # -- CASE: Formatter are specified in behave configuration file.
        #    Check if formatter are provided on command-line, too.
        if len(config.format) == len(config.defaults["format"]):
            # -- NO FORMATTER on command-line: Add default formatter.
            config.format.append(config.default_format)
    if "help" in config.format:
        print_formatters("Available formatters:")
        return 0

    if len(config.outputs) > len(config.format):
        print("CONFIG-ERROR: More outfiles (%d) than formatters (%d)." % \
              (len(config.outputs), len(config.format)))
        return 1

    # -- MAIN PART:
    failed = True
    try:
        reset_runtime()
        runner = runner_class(config)
        failed = runner.run()
    except ParserError as e:
        print(u"ParserError: %s" % e)
    except ConfigError as e:
        print(u"ConfigError: %s" % e)
    except FileNotFoundError as e:
        print(u"FileNotFoundError: %s" % e)
    except InvalidFileLocationError as e:
        print(u"InvalidFileLocationError: %s" % e)
    except InvalidFilenameError as e:
        print(u"InvalidFilenameError: %s" % e)
    except Exception as e:
        # -- DIAGNOSTICS:
        text = _text(e)
        print(u"Exception %s: %s" % (e.__class__.__name__, text))
        raise

    if config.show_snippets and runner.undefined_steps:
        print_undefined_step_snippets(runner.undefined_steps,
                                      colored=config.color)

    return_code = 0
    if failed:
        return_code = 1
    return return_code
Beispiel #36
0
def main(args=None):
    config = Configuration(args)
    if config.version:
        print("behave " + __version__)
        return 0

    if config.tags_help:
        print(TAG_HELP)
        return 0

    if config.lang_list:
        from behave.i18n import languages

        stdout = sys.stdout
        if six.PY2:
            # -- PYTHON2: Overcome implicit encode problems (encoding=ASCII).
            stdout = codecs.getwriter("UTF-8")(sys.stdout)
        iso_codes = languages.keys()
        print("Languages available:")
        for iso_code in sorted(iso_codes):
            native = languages[iso_code]["native"][0]
            name = languages[iso_code]["name"][0]
            print(u"%s: %s / %s" % (iso_code, native, name), file=stdout)
        return 0

    if config.lang_help:
        from behave.i18n import languages

        if config.lang_help not in languages:
            print("%s is not a recognised language: try --lang-list" % config.lang_help)
            return 1
        trans = languages[config.lang_help]
        print(u"Translations for %s / %s" % (trans["name"][0], trans["native"][0]))
        for kw in trans:
            if kw in "name native".split():
                continue
            print(u"%16s: %s" % (kw.title().replace("_", " "), u", ".join(w for w in trans[kw] if w != "*")))
        return 0

    if not config.format:
        config.format = [config.default_format]
    elif config.format and "format" in config.defaults:
        # -- CASE: Formatter are specified in behave configuration file.
        #    Check if formatter are provided on command-line, too.
        if len(config.format) == len(config.defaults["format"]):
            # -- NO FORMATTER on command-line: Add default formatter.
            config.format.append(config.default_format)
    if "help" in config.format:
        print_formatters("Available formatters:")
        return 0

    if len(config.outputs) > len(config.format):
        print("CONFIG-ERROR: More outfiles (%d) than formatters (%d)." % (len(config.outputs), len(config.format)))
        return 1

    failed = True
    runner = Runner(config)
    try:
        failed = runner.run()
    except ParserError as e:
        print(u"ParseError: %s" % e)
    except ConfigError as e:
        print(u"ConfigError: %s" % e)
    except FileNotFoundError as e:
        print(u"FileNotFoundError: %s" % e)
    except InvalidFileLocationError as e:
        print(u"InvalidFileLocationError: %s" % e)
    except InvalidFilenameError as e:
        print(u"InvalidFilenameError: %s" % e)
    except Exception as e:
        # -- DIAGNOSTICS:
        text = _text(e)
        print(u"Exception %s: %s" % (e.__class__.__name__, text))
        raise

    if config.show_snippets and runner.undefined_steps:
        print_undefined_step_snippets(runner.undefined_steps, colored=config.color)

    return_code = 0
    if failed:
        return_code = 1
    return return_code