Exemplo n.º 1
0
    def __init__(self, report, source=None, source_prefix=None):
        """
        Initialize a Cobertura report given a coverage report `report`. It can
        be either a file object or the path to an XML file that is in the
        Cobertura format.

        The optional argument `source` is the location of the source code
        provided as a directory path or a file object zip archive containing
        the source code.

        The optional argument `source_prefix` will be used to lookup source
        files if a zip archive is provided and will be prepended to filenames
        found in the coverage report.
        """
        self.xml = ET.parse(report).getroot()

        if source is None:
            if isinstance(report, basestring):
                # get the directory in which the coverage file lives
                source = os.path.dirname(report)
            self.filesystem = DirectoryFileSystem(
                source, source_prefix=source_prefix
            )
        elif zipfile.is_zipfile(source):
            self.filesystem = ZipFileSystem(
                source, source_prefix=source_prefix
            )
        else:
            self.filesystem = DirectoryFileSystem(
                source, source_prefix=source_prefix
            )
Exemplo n.º 2
0
    def __init__(self, report, source=None, source_prefix=None):
        """
        Initialize a Cobertura report given a coverage report `report`. It can
        be either a file object or the path to an XML file that is in the
        Cobertura format.

        The optional argument `source` is the location of the source code
        provided as a directory path or a file object zip archive containing
        the source code.

        The optional argument `source_prefix` will be used to lookup source
        files if a zip archive is provided and will be prepended to filenames
        found in the coverage report.
        """
        self.xml = ET.parse(report).getroot()

        if source is None:
            if isinstance(report, basestring):
                # get the directory in which the coverage file lives
                source = os.path.dirname(report)
            self.filesystem = DirectoryFileSystem(
                source, source_prefix=source_prefix
            )
        elif zipfile.is_zipfile(source):
            self.filesystem = ZipFileSystem(
                source, source_prefix=source_prefix
            )
        else:
            self.filesystem = DirectoryFileSystem(
                source, source_prefix=source_prefix
            )
Exemplo n.º 3
0
def test_filesystem_directory__returns_fileobject():
    from pycobertura.filesystem import DirectoryFileSystem

    fs = DirectoryFileSystem('tests/dummy')

    expected_filepaths = {
        'dummy/dummy.py': 'dummy/dummy/dummy.py',
    }

    for filename in expected_filepaths:
        with fs.open(filename) as f:
            assert hasattr(f, 'read')
Exemplo n.º 4
0
def test_filesystem_directory__returns_fileobject():
    from pycobertura.filesystem import DirectoryFileSystem

    fs = DirectoryFileSystem('tests/dummy')

    expected_filepaths = {
        'dummy/dummy.py': 'dummy/dummy/dummy.py',
    }

    for filename in expected_filepaths:
        with fs.open(filename) as f:
            assert hasattr(f, 'read')
Exemplo n.º 5
0
def test_filesystem_directory__with_source_prefix():
    from pycobertura.filesystem import DirectoryFileSystem

    fs = DirectoryFileSystem(
        'tests/',
        source_prefix='dummy'  # should resolve to tests/dummy/
    )

    expected_filepaths = {
        'dummy/dummy.py': 'dummy/dummy/dummy.py',
    }

    for filename in expected_filepaths:
        with fs.open(filename) as f:
            assert hasattr(f, 'read')
Exemplo n.º 6
0
def test_filesystem_directory__with_source_prefix():
    from pycobertura.filesystem import DirectoryFileSystem

    fs = DirectoryFileSystem(
        'tests/',
        source_prefix='dummy'  # should resolve to tests/dummy/
    )

    expected_filepaths = {
        'dummy/dummy.py': 'dummy/dummy/dummy.py',
    }

    for filename in expected_filepaths:
        with fs.open(filename) as f:
            assert hasattr(f, 'read')
Exemplo n.º 7
0
def test_filesystem_directory__file_not_found():
    from pycobertura.filesystem import DirectoryFileSystem

    fs = DirectoryFileSystem('foo/bar/baz')

    expected_filepaths = {
        'Main.java': 'foo/bar/baz/Main.java',
        'search/BinarySearch.java': 'foo/bar/baz/search/BinarySearch.java',
        'search/ISortedArraySearch.java': 'foo/bar/baz/search/ISortedArraySearch.java',
        'search/LinearSearch.java': 'foo/bar/baz/search/LinearSearch.java',
    }

    for filename in expected_filepaths:
        try:
            with fs.open(filename) as f:
                pass
        except DirectoryFileSystem.FileNotFound as fnf:
            assert fnf.path == expected_filepaths[filename]
Exemplo n.º 8
0
def test_filesystem_directory__file_not_found():
    from pycobertura.filesystem import DirectoryFileSystem

    fs = DirectoryFileSystem('foo/bar/baz')

    expected_filepaths = {
        'Main.java': 'foo/bar/baz/Main.java',
        'search/BinarySearch.java': 'foo/bar/baz/search/BinarySearch.java',
        'search/ISortedArraySearch.java': 'foo/bar/baz/search/ISortedArraySearch.java',
        'search/LinearSearch.java': 'foo/bar/baz/search/LinearSearch.java',
    }

    for filename in expected_filepaths:
        try:
            with fs.open(filename) as f:
                pass
        except DirectoryFileSystem.FileNotFound as fnf:
            assert fnf.path == expected_filepaths[filename]
Exemplo n.º 9
0
class Cobertura(object):
    """
    An XML Cobertura parser.
    """
    def __init__(self, report, source=None, source_prefix=None):
        """
        Initialize a Cobertura report given a coverage report `report`. It can
        be either a file object or the path to an XML file that is in the
        Cobertura format.

        The optional argument `source` is the location of the source code
        provided as a directory path or a file object zip archive containing
        the source code.

        The optional argument `source_prefix` will be used to lookup source
        files if a zip archive is provided and will be prepended to filenames
        found in the coverage report.
        """
        self.xml = ET.parse(report).getroot()

        if source is None:
            if isinstance(report, basestring):
                # get the directory in which the coverage file lives
                source = os.path.dirname(report)
            self.filesystem = DirectoryFileSystem(
                source, source_prefix=source_prefix
            )
        elif zipfile.is_zipfile(source):
            self.filesystem = ZipFileSystem(
                source, source_prefix=source_prefix
            )
        else:
            self.filesystem = DirectoryFileSystem(
                source, source_prefix=source_prefix
            )

    @memoize
    def _get_class_element_by_filename(self, filename):
        syntax = "./packages/package/classes/class[@filename='%s'][1]" % (
            filename
        )
        return self.xml.xpath(syntax)[0]

    @memoize
    def _get_lines_by_filename(self, filename):
        el = self._get_class_element_by_filename(filename)
        return el.xpath('./lines/line')

    @property
    def version(self):
        """Return the version number of the coverage report."""
        return self.xml.attrib['version']

    def line_rate(self, filename=None):
        """
        Return the global line rate of the coverage report. If the
        `filename` file is given, return the line rate of the file.
        """
        if filename is None:
            el = self.xml
        else:
            el = self._get_class_element_by_filename(filename)

        return float(el.attrib['line-rate'])

    def branch_rate(self, filename=None):
        """
        Return the global branch rate of the coverage report. If the
        `filename` file is given, return the branch rate of the file.
        """
        if filename is None:
            el = self.xml
        else:
            el = self._get_class_element_by_filename(filename)

        return float(el.attrib['branch-rate'])

    @memoize
    def missed_statements(self, filename):
        """
        Return a list of uncovered line numbers for each of the missed
        statements found for the file `filename`.
        """
        el = self._get_class_element_by_filename(filename)
        lines = el.xpath('./lines/line[@hits=0]')
        return [int(l.attrib['number']) for l in lines]

    @memoize
    def hit_statements(self, filename):
        """
        Return a list of covered line numbers for each of the hit statements
        found for the file `filename`.
        """
        el = self._get_class_element_by_filename(filename)
        lines = el.xpath('./lines/line[@hits>0]')
        return [int(l.attrib['number']) for l in lines]

    def line_statuses(self, filename):
        """
        Return a list of tuples `(lineno, status)` of all the lines found in
        the Cobertura report for the given file `filename` where `lineno` is
        the line number and `status` is coverage status of the line which can
        be either `True` (line hit) or `False` (line miss).
        """
        line_elements = self._get_lines_by_filename(filename)

        lines_w_status = []
        for line in line_elements:
            lineno = int(line.attrib['number'])
            status = line.attrib['hits'] != '0'
            lines_w_status.append((lineno, status))

        return lines_w_status

    def missed_lines(self, filename):
        """
        Return a list of extrapolated uncovered line numbers for the
        file `filename` according to `Cobertura.line_statuses`.
        """
        statuses = self.line_statuses(filename)
        statuses = extrapolate_coverage(statuses)
        return [lno for lno, status in statuses if status is False]

    @memoize
    def file_source(self, filename):
        """
        Return a list of namedtuple `Line` for each line of code found in the
        source file with the given `filename`.
        """
        lines = []
        try:
            with self.filesystem.open(filename) as f:
                line_statuses = dict(self.line_statuses(filename))
                for lineno, source in enumerate(f, start=1):
                    line_status = line_statuses.get(lineno)
                    line = Line(lineno, source, line_status, None)
                    lines.append(line)

        except self.filesystem.FileNotFound as file_not_found:
            lines.append(
                Line(0, '%s not found' % file_not_found.path, None, None)
            )

        return lines

    def total_misses(self, filename=None):
        """
        Return the total number of uncovered statements for the file
        `filename`. If `filename` is not given, return the total
        number of uncovered statements for all files.
        """
        if filename is not None:
            return len(self.missed_statements(filename))

        total = 0
        for filename in self.files():
            total += len(self.missed_statements(filename))

        return total

    def total_hits(self, filename=None):
        """
        Return the total number of covered statements for the file
        `filename`. If `filename` is not given, return the total
        number of covered statements for all files.
        """
        if filename is not None:
            return len(self.hit_statements(filename))

        total = 0
        for filename in self.files():
            total += len(self.hit_statements(filename))

        return total

    def total_statements(self, filename=None):
        """
        Return the total number of statements for the file
        `filename`. If `filename` is not given, return the total
        number of statements for all files.
        """
        if filename is not None:
            statements = self._get_lines_by_filename(filename)
            return len(statements)

        total = 0
        for filename in self.files():
            statements = self._get_lines_by_filename(filename)
            total += len(statements)

        return total

    @memoize
    def files(self):
        """
        Return the list of available files in the coverage report.
        """
        return [el.attrib['filename'] for el in self.xml.xpath("//class")]

    def has_file(self, filename):
        """
        Return `True` if the file `filename` is present in the report, return
        `False` otherwise.
        """
        # FIXME: this will lookup a list which is slow, make it O(1)
        return filename in self.files()

    @memoize
    def source_lines(self, filename):
        """
        Return a list for source lines of file `filename`.
        """
        with self.filesystem.open(filename) as f:
            return f.readlines()

    @memoize
    def packages(self):
        """
        Return the list of available packages in the coverage report.
        """
        return [el.attrib['name'] for el in self.xml.xpath("//package")]
Exemplo n.º 10
0
class Cobertura(object):
    """
    An XML Cobertura parser.
    """
    def __init__(self, report, source=None, source_prefix=None):
        """
        Initialize a Cobertura report given a coverage report `report`. It can
        be either a file object or the path to an XML file that is in the
        Cobertura format.

        The optional argument `source` is the location of the source code
        provided as a directory path or a file object zip archive containing
        the source code.

        The optional argument `source_prefix` will be used to lookup source
        files if a zip archive is provided and will be prepended to filenames
        found in the coverage report.
        """
        self.xml = ET.parse(report).getroot()

        if source is None:
            if isinstance(report, basestring):
                # get the directory in which the coverage file lives
                source = os.path.dirname(report)
            self.filesystem = DirectoryFileSystem(
                source, source_prefix=source_prefix
            )
        elif zipfile.is_zipfile(source):
            self.filesystem = ZipFileSystem(
                source, source_prefix=source_prefix
            )
        else:
            self.filesystem = DirectoryFileSystem(
                source, source_prefix=source_prefix
            )

    @memoize
    def _get_class_element_by_filename(self, filename):
        syntax = "./packages/package/classes/class[@filename='%s'][1]" % (
            filename
        )
        return self.xml.xpath(syntax)[0]

    @memoize
    def _get_lines_by_filename(self, filename):
        el = self._get_class_element_by_filename(filename)
        return el.xpath('./lines/line')

    @property
    def version(self):
        """Return the version number of the coverage report."""
        return self.xml.attrib['version']

    def line_rate(self, filename=None):
        """
        Return the global line rate of the coverage report. If the
        `filename` file is given, return the line rate of the file.
        """
        if filename is None:
            el = self.xml
        else:
            el = self._get_class_element_by_filename(filename)

        return float(el.attrib['line-rate'])

    def branch_rate(self, filename=None):
        """
        Return the global branch rate of the coverage report. If the
        `filename` file is given, return the branch rate of the file.
        """
        if filename is None:
            el = self.xml
        else:
            el = self._get_class_element_by_filename(filename)

        return float(el.attrib['branch-rate'])

    @memoize
    def missed_statements(self, filename):
        """
        Return a list of uncovered line numbers for each of the missed
        statements found for the file `filename`.
        """
        el = self._get_class_element_by_filename(filename)
        lines = el.xpath('./lines/line[@hits=0]')
        return [int(l.attrib['number']) for l in lines]

    @memoize
    def hit_statements(self, filename):
        """
        Return a list of covered line numbers for each of the hit statements
        found for the file `filename`.
        """
        el = self._get_class_element_by_filename(filename)
        lines = el.xpath('./lines/line[@hits>0]')
        return [int(l.attrib['number']) for l in lines]

    def line_statuses(self, filename):
        """
        Return a list of tuples `(lineno, status)` of all the lines found in
        the Cobertura report for the given file `filename` where `lineno` is
        the line number and `status` is coverage status of the line which can
        be either `True` (line hit) or `False` (line miss).
        """
        line_elements = self._get_lines_by_filename(filename)

        lines_w_status = []
        for line in line_elements:
            lineno = int(line.attrib['number'])
            status = line.attrib['hits'] != '0'
            lines_w_status.append((lineno, status))

        return lines_w_status

    def missed_lines(self, filename):
        """
        Return a list of extrapolated uncovered line numbers for the
        file `filename` according to `Cobertura.line_statuses`.
        """
        statuses = self.line_statuses(filename)
        statuses = extrapolate_coverage(statuses)
        return [lno for lno, status in statuses if status is False]

    @memoize
    def file_source(self, filename):
        """
        Return a list of namedtuple `Line` for each line of code found in the
        source file with the given `filename`.
        """
        lines = []
        try:
            with self.filesystem.open(filename) as f:
                line_statuses = dict(self.line_statuses(filename))
                for lineno, source in enumerate(f, start=1):
                    line_status = line_statuses.get(lineno)
                    line = Line(lineno, source, line_status, None)
                    lines.append(line)

        except self.filesystem.FileNotFound as file_not_found:
            lines.append(
                Line(0, '%s not found' % file_not_found.path, None, None)
            )

        return lines

    def total_misses(self, filename=None):
        """
        Return the total number of uncovered statements for the file
        `filename`. If `filename` is not given, return the total
        number of uncovered statements for all files.
        """
        if filename is not None:
            return len(self.missed_statements(filename))

        total = 0
        for filename in self.files():
            total += len(self.missed_statements(filename))

        return total

    def total_hits(self, filename=None):
        """
        Return the total number of covered statements for the file
        `filename`. If `filename` is not given, return the total
        number of covered statements for all files.
        """
        if filename is not None:
            return len(self.hit_statements(filename))

        total = 0
        for filename in self.files():
            total += len(self.hit_statements(filename))

        return total

    def total_statements(self, filename=None):
        """
        Return the total number of statements for the file
        `filename`. If `filename` is not given, return the total
        number of statements for all files.
        """
        if filename is not None:
            statements = self._get_lines_by_filename(filename)
            return len(statements)

        total = 0
        for filename in self.files():
            statements = self._get_lines_by_filename(filename)
            total += len(statements)

        return total

    @memoize
    def files(self):
        """
        Return the list of available files in the coverage report.
        """
        return [el.attrib['filename'] for el in self.xml.xpath("//class")]

    def has_file(self, filename):
        """
        Return `True` if the file `filename` is present in the report, return
        `False` otherwise.
        """
        # FIXME: this will lookup a list which is slow, make it O(1)
        return filename in self.files()

    @memoize
    def source_lines(self, filename):
        """
        Return a list for source lines of file `filename`.
        """
        with self.filesystem.open(filename) as f:
            return f.readlines()

    @memoize
    def packages(self):
        """
        Return the list of available packages in the coverage report.
        """
        return [el.attrib['name'] for el in self.xml.xpath("//package")]