def collect_feature_locations(paths, strict=True):
    """
    Collect feature file names by processing list of paths (from command line).
    A path can be a:

      * filename (ending with ".feature")
      * location, ala "{filename}:{line_number}"
      * features configuration filename, ala "@features.txt"
      * directory, to discover and collect all "*.feature" files below.

    :param paths:  Paths to process.
    :return: Feature file locations to use (as list of FileLocations).
    """
    locations = []
    for path in paths:
        if os.path.isdir(path):
            for dirpath, dirnames, filenames in os.walk(path, followlinks=True):
                dirnames.sort()
                for filename in sorted(filenames):
                    if filename.endswith(".feature"):
                        location = FileLocation(os.path.join(dirpath, filename))
                        locations.append(location)
        elif path.startswith('@'):
            # -- USE: behave @list_of_features.txt
            locations.extend(FeatureListParser.parse_file(path[1:]))
        else:
            # -- OTHERWISE: Normal filename or location (schema: filename:line)
            location = FileLocationParser.parse(path)
            if not location.filename.endswith(".feature"):
                raise InvalidFilenameError(location.filename)
            elif location.exists():
                locations.append(location)
            elif strict:
                raise FileNotFoundError(path)
    return locations
Esempio n. 2
0
def collect_feature_locations(paths, strict=True):
    """
    Collect feature file names by processing list of paths (from command line).
    A path can be a:

      * filename (ending with ".feature")
      * location, ala "{filename}:{line_number}"
      * features configuration filename, ala "@features.txt"
      * directory, to discover and collect all "*.feature" files below.

    :param paths:  Paths to process.
    :return: Feature file locations to use (as list of FileLocations).
    """
    locations = []
    for path in paths:
        if os.path.isdir(path):
            for dirpath, dirnames, filenames in os.walk(path, followlinks=True):
                dirnames.sort()
                for filename in sorted(filenames):
                    if filename.endswith(".feature"):
                        location = FileLocation(os.path.join(dirpath, filename))
                        locations.append(location)
        elif path.startswith('@'):
            # -- USE: behave @list_of_features.txt
            locations.extend(FeatureListParser.parse_file(path[1:]))
        else:
            # -- OTHERWISE: Normal filename or location (schema: filename:line)
            location = FileLocationParser.parse(path)
            if not location.filename.endswith(".feature"):
                raise InvalidFilenameError(location.filename)
            elif location.exists():
                locations.append(location)
            elif strict:
                raise FileNotFoundError(path)
    return locations
 def parse(cls, text):
     match = cls.pattern.match(text)
     if match:
         filename = match.group("filename").strip()
         line = int(match.group("line"))
         return FileLocation(filename, line)
     # -- NORMAL PATH/FILENAME:
     filename = text.strip()
     return FileLocation(filename)
Esempio n. 4
0
    def make_location(step_function):
        """Extracts the location information from the step function and
        builds a FileLocation object with (filename, line_number) info.

        :param step_function: Function whose location should be determined.
        :return: FileLocation object for step function.
        """
        return FileLocation.for_function(step_function)
Esempio n. 5
0
    def make_location(step_function):
        """Extracts the location information from the step function and
        builds a FileLocation object with (filename, line_number) info.

        :param step_function: Function whose location should be determined.
        :return: FileLocation object for step function.
        """
        return FileLocation.for_function(step_function)
Esempio n. 6
0
    def make_location(step_function):
        '''
        Extracts the location information from the step function and builds
        the location string (schema: "{source_filename}:{line_number}").

        :param step_function: Function whose location should be determined.
        :return: Step function location as string.
        '''
        step_function_code = six.get_function_code(step_function)
        filename = os.path.relpath(step_function_code.co_filename, os.getcwd())
        line_number = step_function_code.co_firstlineno
        return FileLocation(filename, line_number)
Esempio n. 7
0
def parse_features(feature_files, language=None):
    """
    Parse feature files and return list of Feature model objects.
    Handles:

      * feature file names, ala "alice.feature"
      * feature file locations, ala: "alice.feature:10"

    :param feature_files: List of feature file names to parse.
    :param language:      Default language to use.
    :return: List of feature objects.
    """
    scenario_collector = FeatureScenarioLocationCollector()
    features = []
    for location in feature_files:
        if not isinstance(location, FileLocation):
            assert isinstance(location, string_types)
            location = FileLocation(os.path.normpath(location))

        if location.filename == scenario_collector.filename:
            scenario_collector.add_location(location)
            continue
        elif scenario_collector.feature:
            # -- ADD CURRENT FEATURE: As collection of scenarios.
            current_feature = scenario_collector.build_feature()
            features.append(current_feature)
            scenario_collector.clear()

        # -- NEW FEATURE:
        assert isinstance(location, FileLocation)
        filename = os.path.abspath(location.filename)
        feature = parser.parse_file(filename, language=language)
        if feature:
            # -- VALID FEATURE:
            # SKIP CORNER-CASE: Feature file without any feature(s).
            scenario_collector.feature = feature
            scenario_collector.add_location(location)
    # -- FINALLY:
    if scenario_collector.feature:
        current_feature = scenario_collector.build_feature()
        features.append(current_feature)
    return features
Esempio n. 8
0
class TestFileLocation(unittest.TestCase):
    # pylint: disable=invalid-name
    ordered_locations1 = [
        FileLocation("features/alice.feature", 1),
        FileLocation("features/alice.feature", 5),
        FileLocation("features/alice.feature", 10),
        FileLocation("features/alice.feature", 11),
        FileLocation("features/alice.feature", 100),
    ]
    ordered_locations2 = [
        FileLocation("features/alice.feature", 1),
        FileLocation("features/alice.feature", 10),
        FileLocation("features/bob.feature", 5),
        FileLocation("features/charly.feature", None),
        FileLocation("features/charly.feature", 0),
        FileLocation("features/charly.feature", 100),
    ]
    same_locations = [
        (
            FileLocation("alice.feature"),
            FileLocation("alice.feature", None),
        ),
        (
            FileLocation("alice.feature", 10),
            FileLocation("alice.feature", 10),
        ),
        (
            FileLocation("features/bob.feature", 11),
            FileLocation("features/bob.feature", 11),
        ),
    ]

    def test_compare_equal(self):
        for value1, value2 in self.same_locations:
            eq_(value1, value2)

    def test_compare_equal_with_string(self):
        for location in self.ordered_locations2:
            eq_(location, location.filename)
            eq_(location.filename, location)

    def test_compare_not_equal(self):
        for value1, value2 in self.same_locations:
            assert not (value1 != value2)  # pylint: disable=unneeded-not, superfluous-parens

        for locations in [self.ordered_locations1, self.ordered_locations2]:
            for value1, value2 in zip(locations, locations[1:]):
                assert value1 != value2

    def test_compare_less_than(self):
        for locations in [self.ordered_locations1, self.ordered_locations2]:
            for value1, value2 in zip(locations, locations[1:]):
                assert value1 < value2, "FAILED: %s < %s" % (_text(value1),
                                                             _text(value2))
                assert value1 != value2

    def test_compare_less_than_with_string(self):
        locations = self.ordered_locations2
        for value1, value2 in zip(locations, locations[1:]):
            if value1.filename == value2.filename:
                continue
            assert value1 < value2.filename, \
                   "FAILED: %s < %s" % (_text(value1), _text(value2.filename))
            assert value1.filename < value2, \
                   "FAILED: %s < %s" % (_text(value1.filename), _text(value2))

    def test_compare_greater_than(self):
        for locations in [self.ordered_locations1, self.ordered_locations2]:
            for value1, value2 in zip(locations, locations[1:]):
                assert value2 > value1, "FAILED: %s > %s" % (_text(value2),
                                                             _text(value1))
                assert value2 != value1

    def test_compare_less_or_equal(self):
        for value1, value2 in self.same_locations:
            assert value1 <= value2, "FAILED: %s <= %s" % (_text(value1),
                                                           _text(value2))
            assert value1 == value2

        for locations in [self.ordered_locations1, self.ordered_locations2]:
            for value1, value2 in zip(locations, locations[1:]):
                assert value1 <= value2, "FAILED: %s <= %s" % (_text(value1),
                                                               _text(value2))
                assert value1 != value2

    def test_compare_greater_or_equal(self):
        for value1, value2 in self.same_locations:
            assert value2 >= value1, "FAILED: %s >= %s" % (_text(value2),
                                                           _text(value1))
            assert value2 == value1

        for locations in [self.ordered_locations1, self.ordered_locations2]:
            for value1, value2 in zip(locations, locations[1:]):
                assert value2 >= value1, "FAILED: %s >= %s" % (_text(value2),
                                                               _text(value1))
                assert value2 != value1

    def test_filename_should_be_same_as_self(self):
        for location in self.ordered_locations2:
            assert location == location.filename
            assert location.filename == location

    def test_string_conversion(self):
        for location in self.ordered_locations2:
            expected = u"%s:%s" % (location.filename, location.line)
            if location.line is None:
                expected = location.filename
            assert six.text_type(location) == expected

    def test_repr_conversion(self):
        for location in self.ordered_locations2:
            expected = u'<FileLocation: filename="%s", line=%s>' % \
                       (location.filename, location.line)
            actual = repr(location)
            assert actual == expected, "FAILED: %s == %s" % (actual, expected)