示例#1
0
    def test_git_exclude(self):
        self.diff = GitDiffReporter(git_diff=self._git_diff,
                                    exclude=["file1.py"])

        # Configure the git diff output
        self._set_git_diff_output(
            git_diff_output({
                "subdir1/file1.py":
                line_numbers(3, 10) + line_numbers(34, 47)
            }),
            git_diff_output({
                "subdir2/file2.py": line_numbers(3, 10),
                "file3.py": [0]
            }),
            git_diff_output(dict(), deleted_files=["README.md"]),
        )

        # Get the source paths in the diff
        source_paths = self.diff.src_paths_changed()

        # Validate the source paths
        # They should be in alphabetical order
        self.assertEqual(len(source_paths), 3)
        self.assertEqual("file3.py", source_paths[0])
        self.assertEqual("README.md", source_paths[1])
        self.assertEqual("subdir2/file2.py", source_paths[2])
示例#2
0
    def setUp(self):

        # Create a mock git diff wrapper
        self._git_diff = mock.MagicMock(GitDiffTool)

        # Create the diff reporter
        self.diff = GitDiffReporter(git_diff=self._git_diff)
示例#3
0
def test_ignore_unstaged_inclusion(git_diff):
    reporter = GitDiffReporter(git_diff=git_diff, ignore_unstaged=True)

    unstaged_input = git_diff_output(
        {"subdir/file1.py": line_numbers(3, 10) + line_numbers(34, 47)})
    _set_git_diff_output(reporter, git_diff, "", "", unstaged_input)

    assert reporter._get_included_diff_results() == ["", ""]
示例#4
0
    def test_ignore_unstaged_inclusion(self):
        self.diff = GitDiffReporter(git_diff=self._git_diff, ignore_unstaged=True)

        unstaged_input = git_diff_output({'subdir/file1.py': line_numbers(3, 10) + line_numbers(34, 47)})
        self._set_git_diff_output('', '', unstaged_input)

        self.assertEqual(2, len(self.diff._get_included_diff_results()))
        self.assertEqual(['', ''], self.diff._get_included_diff_results())
    def test_ignore_staged_inclusion(self):
        self.diff = GitDiffReporter(git_diff=self._git_diff,
                                    ignore_staged=True)

        staged_input = git_diff_output(
            {"subdir/file1.py": line_numbers(3, 10) + line_numbers(34, 47)})
        self._set_git_diff_output("", staged_input, "")

        self.assertEqual(2, len(self.diff._get_included_diff_results()))
        self.assertEqual(["", ""], self.diff._get_included_diff_results())
示例#6
0
def test_git_path_selection(mocker, diff, git_diff, include, exclude,
                            expected):
    old_cwd = os.getcwd()
    with tempfile.TemporaryDirectory() as tmp_dir:
        # change the working directory into the temp directory so that globs are working
        os.chdir(tmp_dir)

        diff = GitDiffReporter(git_diff=git_diff,
                               exclude=exclude,
                               include=include)

        main_dir = Path(tmp_dir)
        (main_dir / "file3.py").touch()

        subdir1 = main_dir / "subdir1"
        subdir1.mkdir()
        (subdir1 / "file1.py").touch()

        subdir2 = main_dir / "subdir2"
        subdir2.mkdir()
        (subdir2 / "file2.py").touch()

        # Configure the git diff output
        _set_git_diff_output(
            diff,
            git_diff,
            git_diff_output({
                "subdir1/file1.py":
                line_numbers(3, 10) + line_numbers(34, 47)
            }),
            git_diff_output({
                "subdir2/file2.py": line_numbers(3, 10),
                "file3.py": [0]
            }),
            git_diff_output(dict(), deleted_files=["README.md"]),
        )

        # Get the source paths in the diff
        mocker.patch.object(os.path, "abspath",
                            lambda path: f"{tmp_dir}/{path}")
        source_paths = diff.src_paths_changed()

        # Validate the source paths
        # They should be in alphabetical order
        assert source_paths == expected

    # change back to the previous working directory
    os.chdir(old_cwd)
 def test_name_compare_branch(self):
     # Override the default branch
     self.assertEqual(
         GitDiffReporter(git_diff=self._git_diff,
                         compare_branch="release").name(),
         "release...HEAD, staged and unstaged changes",
     )
示例#8
0
def generate_coverage_report(coverage_xml, compare_branch,
                             html_report=None, css_file=None,
                             ignore_staged=False, ignore_unstaged=False,
                             exclude=None, src_roots=None):
    """
    Generate the diff coverage report, using kwargs from `parse_args()`.
    """
    diff = GitDiffReporter(
        compare_branch, git_diff=GitDiffTool(), ignore_staged=ignore_staged,
        ignore_unstaged=ignore_unstaged, exclude=exclude)

    xml_roots = [cElementTree.parse(xml_root) for xml_root in coverage_xml]
    coverage = XmlCoverageReporter(xml_roots, src_roots)

    # Build a report generator
    if html_report is not None:
        css_url = css_file
        if css_url is not None:
            css_url = os.path.relpath(css_file, os.path.dirname(html_report))
        reporter = HtmlReportGenerator(coverage, diff, css_url=css_url)
        with open(html_report, "wb") as output_file:
            reporter.generate_report(output_file)
        if css_file is not None:
            with open(css_file, "wb") as output_file:
                reporter.generate_css(output_file)

    reporter = StringReportGenerator(coverage, diff)
    output_file = sys.stdout if six.PY2 else sys.stdout.buffer

    # Generate the report
    reporter.generate_report(output_file)
    return reporter.total_percent_covered()
示例#9
0
def generate_quality_report(tool,
                            compare_branch,
                            html_report=None,
                            css_file=None,
                            ignore_unstaged=False):
    """
    Generate the quality report, using kwargs from `parse_args()`.
    """
    diff = GitDiffReporter(compare_branch,
                           git_diff=GitDiffTool(),
                           ignore_unstaged=ignore_unstaged)

    if html_report is not None:
        css_url = css_file
        if css_url is not None:
            css_url = os.path.relpath(css_file, os.path.dirname(html_report))
        reporter = HtmlQualityReportGenerator(tool, diff, css_url=css_url)
        with open(html_report, "wb") as output_file:
            reporter.generate_report(output_file)
        if css_file is not None:
            with open(css_file, "wb") as output_file:
                reporter.generate_css(output_file)

    # Generate the report for stdout
    reporter = StringQualityReportGenerator(tool, diff)
    output_file = sys.stdout if six.PY2 else sys.stdout.buffer

    reporter.generate_report(output_file)
    return reporter.total_percent_covered()
示例#10
0
def generate_quality_report(tool, compare_branch,
                            html_report=None, css_file=None,
                            ignore_staged=False, ignore_unstaged=False,
                            exclude=None, diff_range_notation=None):
    """
    Generate the quality report, using kwargs from `parse_args()`.
    """
    supported_extensions = getattr(tool, 'supported_extensions', None) \
        or tool.driver.supported_extensions
    diff = GitDiffReporter(
        compare_branch, git_diff=GitDiffTool(diff_range_notation),
        ignore_staged=ignore_staged, ignore_unstaged=ignore_unstaged,
        supported_extensions=supported_extensions,
        exclude=exclude)

    if html_report is not None:
        css_url = css_file
        if css_url is not None:
            css_url = os.path.relpath(css_file, os.path.dirname(html_report))
        reporter = HtmlQualityReportGenerator(tool, diff, css_url=css_url)
        with open(html_report, "wb") as output_file:
            reporter.generate_report(output_file)
        if css_file is not None:
            with open(css_file, "wb") as output_file:
                reporter.generate_css(output_file)

    # Generate the report for stdout
    reporter = StringQualityReportGenerator(tool, diff)
    output_file = sys.stdout if six.PY2 else sys.stdout.buffer

    reporter.generate_report(output_file)
    return reporter.total_percent_covered()
示例#11
0
def test_include_untracked(mocker, git_diff):
    reporter = GitDiffReporter(git_diff=git_diff, include_untracked=True)
    diff_output = git_diff_output(
        {"subdir/file1.py": line_numbers(3, 10) + line_numbers(34, 47)})
    _set_git_diff_output(reporter,
                         git_diff,
                         staged_diff=diff_output,
                         untracked=["u1.py", " u2.py"])

    open_mock = mocker.mock_open(read_data="1\n2\n3\n")
    mocker.patch("diff_cover.diff_reporter.open", open_mock)
    changed = reporter.src_paths_changed()

    assert sorted(changed) == [" u2.py", "subdir/file1.py", "u1.py"]
    assert reporter.lines_changed("u1.py") == [1, 2, 3]
    assert reporter.lines_changed(" u2.py") == [1, 2, 3]
示例#12
0
 def test_name_ignore_staged_and_unstaged(self):
     # Override the default branch
     self.assertEqual(
         GitDiffReporter(git_diff=self._git_diff,
                         ignore_staged=True,
                         ignore_unstaged=True).name(),
         'origin/master...HEAD')
    def setUp(self):

        # Create a mock git diff wrapper
        self._git_diff = mock.MagicMock(GitDiffTool)

        # Create the diff reporter
        self.diff = GitDiffReporter(git_diff=self._git_diff)
示例#14
0
def generate_coverage_report(coverage_xml,
                             compare_branch,
                             html_report=None,
                             ignore_unstaged=False):
    """
    Generate the diff coverage report, using kwargs from `parse_args()`.
    """
    diff = GitDiffReporter(compare_branch,
                           git_diff=GitDiffTool(),
                           ignore_unstaged=ignore_unstaged)

    xml_roots = [cElementTree.parse(xml_root) for xml_root in coverage_xml]
    coverage = XmlCoverageReporter(xml_roots)

    # Build a report generator
    if html_report is not None:
        reporter = HtmlReportGenerator(coverage, diff)
        with open(html_report, "wb") as output_file:
            reporter.generate_report(output_file)

    reporter = StringReportGenerator(coverage, diff)
    output_file = sys.stdout if six.PY2 else sys.stdout.buffer

    # Generate the report
    reporter.generate_report(output_file)
    return reporter.total_percent_covered()
示例#15
0
def generate_quality_report(
    tool,
    compare_branch,
    html_report=None,
    json_report=None,
    markdown_report=None,
    css_file=None,
    ignore_staged=False,
    ignore_unstaged=False,
    include_untracked=False,
    exclude=None,
    include=None,
    diff_range_notation=None,
    ignore_whitespace=False,
    quiet=False,
):
    """
    Generate the quality report, using kwargs from `parse_args()`.
    """
    supported_extensions = (getattr(tool, "supported_extensions", None)
                            or tool.driver.supported_extensions)
    diff = GitDiffReporter(
        compare_branch,
        git_diff=GitDiffTool(diff_range_notation, ignore_whitespace),
        ignore_staged=ignore_staged,
        ignore_unstaged=ignore_unstaged,
        include_untracked=include_untracked,
        supported_extensions=supported_extensions,
        exclude=exclude,
        include=include,
    )

    if html_report is not None:
        css_url = css_file
        if css_url is not None:
            css_url = os.path.relpath(css_file, os.path.dirname(html_report))
        reporter = HtmlQualityReportGenerator(tool, diff, css_url=css_url)
        with open(html_report, "wb") as output_file:
            reporter.generate_report(output_file)
        if css_file is not None:
            with open(css_file, "wb") as output_file:
                reporter.generate_css(output_file)

    if json_report is not None:
        reporter = JsonReportGenerator(tool, diff)
        with open(json_report, "wb") as output_file:
            reporter.generate_report(output_file)

    if markdown_report is not None:
        reporter = MarkdownQualityReportGenerator(tool, diff)
        with open(markdown_report, "wb") as output_file:
            reporter.generate_report(output_file)

    # Generate the report for stdout
    reporter = StringQualityReportGenerator(tool, diff)
    output_file = io.BytesIO() if quiet else sys.stdout.buffer
    reporter.generate_report(output_file)

    return reporter.total_percent_covered()
示例#16
0
def generate_coverage_report(
    coverage_xml,
    compare_branch,
    html_report=None,
    css_file=None,
    json_report=None,
    markdown_report=None,
    ignore_staged=False,
    ignore_unstaged=False,
    exclude=None,
    src_roots=None,
    diff_range_notation=None,
    ignore_whitespace=False,
    quiet=False,
    show_uncovered=False,
):
    """
    Generate the diff coverage report, using kwargs from `parse_args()`.
    """
    diff = GitDiffReporter(
        compare_branch,
        git_diff=GitDiffTool(diff_range_notation, ignore_whitespace),
        ignore_staged=ignore_staged,
        ignore_unstaged=ignore_unstaged,
        exclude=exclude,
    )

    xml_roots = [etree.parse(xml_root) for xml_root in coverage_xml]
    coverage = XmlCoverageReporter(xml_roots, src_roots)

    # Build a report generator
    if html_report is not None:
        css_url = css_file
        if css_url is not None:
            css_url = os.path.relpath(css_file, os.path.dirname(html_report))
        reporter = HtmlReportGenerator(coverage, diff, css_url=css_url)
        with open(html_report, "wb") as output_file:
            reporter.generate_report(output_file)
        if css_file is not None:
            with open(css_file, "wb") as output_file:
                reporter.generate_css(output_file)

    elif json_report is not None:
        reporter = JsonReportGenerator(coverage, diff)
        with open(json_report, "wb") as output_file:
            reporter.generate_report(output_file)

    elif markdown_report is not None:
        reporter = MarkdownReportGenerator(coverage, diff)
        with open(markdown_report, "wb") as output_file:
            reporter.generate_report(output_file)

    # Generate the report for stdout
    reporter = StringReportGenerator(coverage, diff, show_uncovered)
    output_file = io.BytesIO() if quiet else sys.stdout.buffer

    # Generate the report
    reporter.generate_report(output_file)
    return reporter.total_percent_covered()
示例#17
0
    def test_ignore_unstaged_inclusion(self):
        self.diff = GitDiffReporter(git_diff=self._git_diff, ignore_unstaged=True)

        unstaged_input = git_diff_output({'subdir/file1.py': line_numbers(3, 10) + line_numbers(34, 47)})
        self._set_git_diff_output('', '', unstaged_input)

        self.assertEqual(2, len(self.diff._get_included_diff_results()))
        self.assertEqual(['', ''], self.diff._get_included_diff_results())
示例#18
0
def generate_quality_report(tool, compare_branch, html_report=None):
    """
    Generate the quality report, using kwargs from `parse_args()`.
    """
    diff = GitDiffReporter(compare_branch, git_diff=GitDiffTool())

    if html_report is not None:
        reporter = HtmlQualityReportGenerator(tool, diff)
        output_file = open(html_report, "w")
    else:
        reporter = StringQualityReportGenerator(tool, diff)
        output_file = sys.stdout

    reporter.generate_report(output_file)
示例#19
0
def generate_coverage_report(coverage_xml,
                             compare_branch,
                             html_report=None,
                             css_file=None,
                             ignore_staged=False,
                             ignore_unstaged=False,
                             exclude=None):
    """
    Generate the diff coverage report, using kwargs from `parse_args()`.
    """
    diff = GitDiffReporter(compare_branch,
                           git_diff=GitDiffTool(),
                           ignore_staged=ignore_staged,
                           ignore_unstaged=ignore_unstaged,
                           exclude=exclude)

    xml_roots = [cElementTree.parse(xml_root) for xml_root in coverage_xml]
    clover_xml_roots = [
        clover_xml for clover_xml in xml_roots
        if clover_xml.findall('.[@clover]')
    ]
    cobertura_xml_roots = [
        cobertura_xml for cobertura_xml in xml_roots
        if cobertura_xml.findall('.[@line-rate]')
    ]
    if clover_xml_roots and cobertura_xml_roots:
        raise TypeError("Can't handle mixed coverage reports")
    elif clover_xml_roots:
        coverage = CloverXmlCoverageReporter(clover_xml_roots)
    elif cobertura_xml_roots:
        coverage = XmlCoverageReporter(cobertura_xml_roots)

    # Build a report generator
    if html_report is not None:
        css_url = css_file
        if css_url is not None:
            css_url = os.path.relpath(css_file, os.path.dirname(html_report))
        reporter = HtmlReportGenerator(coverage, diff, css_url=css_url)
        with open(html_report, "wb") as output_file:
            reporter.generate_report(output_file)
        if css_file is not None:
            with open(css_file, "wb") as output_file:
                reporter.generate_css(output_file)

    reporter = StringReportGenerator(coverage, diff)
    output_file = sys.stdout if six.PY2 else sys.stdout.buffer

    # Generate the report
    reporter.generate_report(output_file)
    return reporter.total_percent_covered()
示例#20
0
def generate_quality_report(tool, compare_branch, html_report=None):
    """
    Generate the quality report, using kwargs from `parse_args()`.
    """
    diff = GitDiffReporter(compare_branch, git_diff=GitDiffTool())

    if html_report is not None:
        reporter = HtmlQualityReportGenerator(tool, diff)
        output_file = open(html_report, "wb")
    else:
        reporter = StringQualityReportGenerator(tool, diff)
        output_file = sys.stdout if six.PY2 else sys.stdout.buffer

    reporter.generate_report(output_file)
    return reporter.total_percent_covered()
示例#21
0
文件: tool.py 项目: Julian/diff-cover
def generate_coverage_report(coverage_xml, html_report=None):
    """
    Generate the diff coverage report, using kwargs from `parse_args()`.
    """
    diff = GitDiffReporter(git_diff=GitDiffTool())

    xml_roots = [etree.parse(xml_root) for xml_root in coverage_xml]
    coverage = XmlCoverageReporter(xml_roots)

    # Build a report generator
    if html_report is not None:
        reporter = HtmlReportGenerator(coverage, diff)
        output_file = open(html_report, "w")
    else:
        reporter = StringReportGenerator(coverage, diff)
        output_file = sys.stdout

    # Generate the report
    reporter.generate_report(output_file)
示例#22
0
    def test_git_exclude(self):
        self.diff = GitDiffReporter(git_diff=self._git_diff, exclude=['file1.py'])

        # Configure the git diff output
        self._set_git_diff_output(
            git_diff_output({'subdir1/file1.py': line_numbers(3, 10) + line_numbers(34, 47)}),
            git_diff_output({'subdir2/file2.py': line_numbers(3, 10), 'file3.py': [0]}),
            git_diff_output(dict(), deleted_files=['README.md'])
        )

        # Get the source paths in the diff
        source_paths = self.diff.src_paths_changed()

        # Validate the source paths
        # They should be in alphabetical order
        self.assertEqual(len(source_paths), 3)
        self.assertEqual('file3.py', source_paths[0])
        self.assertEqual('README.md', source_paths[1])
        self.assertEqual('subdir2/file2.py', source_paths[2])
示例#23
0
文件: tool.py 项目: dashea/diff-cover
def generate_coverage_report(coverage_xml, compare_branch, html_report=None):
    """
    Generate the diff coverage report, using kwargs from `parse_args()`.
    """
    diff = GitDiffReporter(compare_branch, git_diff=GitDiffTool())

    xml_roots = [etree.parse(xml_root) for xml_root in coverage_xml]
    git_path = GitPathTool(os.getcwd())
    coverage = XmlCoverageReporter(xml_roots, git_path)

    # Build a report generator
    if html_report is not None:
        reporter = HtmlReportGenerator(coverage, diff)
        with open(html_report, "wb") as output_file:
            reporter.generate_report(output_file)

    reporter = StringReportGenerator(coverage, diff)
    output_file = sys.stdout

    # Generate the report
    reporter.generate_report(output_file)
示例#24
0
class GitDiffReporterTest(unittest.TestCase):

    def setUp(self):

        # Create a mock git diff wrapper
        self._git_diff = mock.MagicMock(GitDiffTool)

        # Create the diff reporter
        self.diff = GitDiffReporter(git_diff=self._git_diff)

    def test_name(self):

        # Expect that diff report is named after its compare branch
        self.assertEqual(
            self.diff.name(), 'origin/master...HEAD, staged and unstaged changes'
        )

    def test_name_compare_branch(self):
        # Override the default branch
        self.assertEqual(
            GitDiffReporter(git_diff=self._git_diff, compare_branch='release').name(),
            'release...HEAD, staged and unstaged changes'
        )

    def test_name_ignore_staged(self):
        # Override the default branch
        self.assertEqual(
            GitDiffReporter(git_diff=self._git_diff, ignore_staged=True).name(),
            'origin/master...HEAD and unstaged changes'
        )

    def test_name_ignore_unstaged(self):
        # Override the default branch
        self.assertEqual(
            GitDiffReporter(git_diff=self._git_diff, ignore_unstaged=True).name(),
            'origin/master...HEAD and staged changes'
        )

    def test_name_ignore_staged_and_unstaged(self):
        # Override the default branch
        self.assertEqual(
            GitDiffReporter(git_diff=self._git_diff, ignore_staged=True, ignore_unstaged=True).name(),
            'origin/master...HEAD'
        )

    def test_git_exclude(self):
        self.diff = GitDiffReporter(git_diff=self._git_diff, exclude=['file1.py'])

        # Configure the git diff output
        self._set_git_diff_output(
            git_diff_output({'subdir1/file1.py': line_numbers(3, 10) + line_numbers(34, 47)}),
            git_diff_output({'subdir2/file2.py': line_numbers(3, 10), 'file3.py': [0]}),
            git_diff_output(dict(), deleted_files=['README.md'])
        )

        # Get the source paths in the diff
        source_paths = self.diff.src_paths_changed()

        # Validate the source paths
        # They should be in alphabetical order
        self.assertEqual(len(source_paths), 3)
        self.assertEqual('file3.py', source_paths[0])
        self.assertEqual('README.md', source_paths[1])
        self.assertEqual('subdir2/file2.py', source_paths[2])

    def test_git_source_paths(self):

        # Configure the git diff output
        self._set_git_diff_output(
            git_diff_output({'subdir/file1.py': line_numbers(3, 10) + line_numbers(34, 47)}),
            git_diff_output({'subdir/file2.py': line_numbers(3, 10), 'file3.py': [0]}),
            git_diff_output(dict(), deleted_files=['README.md'])
        )

        # Get the source paths in the diff
        source_paths = self.diff.src_paths_changed()

        # Validate the source paths
        # They should be in alphabetical order
        self.assertEqual(len(source_paths), 4)
        self.assertEqual('file3.py', source_paths[0])
        self.assertEqual('README.md', source_paths[1])
        self.assertEqual('subdir/file1.py', source_paths[2])
        self.assertEqual('subdir/file2.py', source_paths[3])

    def test_duplicate_source_paths(self):

        # Duplicate the output for committed, staged, and unstaged changes
        diff = git_diff_output({'subdir/file1.py': line_numbers(3, 10) + line_numbers(34, 47)})
        self._set_git_diff_output(diff, diff, diff)

        # Get the source paths in the diff
        source_paths = self.diff.src_paths_changed()

        # Should see only one copy of source files
        self.assertEqual(len(source_paths), 1)
        self.assertEqual('subdir/file1.py', source_paths[0])

    def test_git_source_paths_with_supported_extensions(self):

        # Configure the git diff output
        self._set_git_diff_output(
            git_diff_output({'subdir/file1.py': line_numbers(3, 10) + line_numbers(34, 47)}),
            git_diff_output({'subdir/file2.py': line_numbers(3, 10), 'file3.py': [0]}),
            git_diff_output({'README.md': line_numbers(3, 10)})
        )

        # Set supported extensions
        self.diff._supported_extensions = ['py']

        # Get the source paths in the diff
        source_paths = self.diff.src_paths_changed()

        # Validate the source paths, README.md should be left out
        self.assertEqual(len(source_paths), 3)
        self.assertEqual('file3.py', source_paths[0])
        self.assertEqual('subdir/file1.py', source_paths[1])
        self.assertEqual('subdir/file2.py', source_paths[2])

    def test_git_lines_changed(self):

        # Configure the git diff output
        self._set_git_diff_output(
            git_diff_output({'subdir/file1.py': line_numbers(3, 10) + line_numbers(34, 47)}),
            git_diff_output({'subdir/file2.py': line_numbers(3, 10), 'file3.py': [0]}),
            git_diff_output(dict(), deleted_files=['README.md'])
        )

        # Get the lines changed in the diff
        lines_changed = self.diff.lines_changed('subdir/file1.py')

        # Validate the lines changed
        self.assertEqual(lines_changed, line_numbers(3, 10) + line_numbers(34, 47))

    def test_ignore_lines_outside_src(self):

        # Add some lines at the start of the diff, before any
        # source files are specified
        diff = git_diff_output({'subdir/file1.py': line_numbers(3, 10)})
        master_diff = "\n".join(['- deleted line', '+ added line', diff])

        # Configure the git diff output
        self._set_git_diff_output(master_diff, "", "")

        # Get the lines changed in the diff
        lines_changed = self.diff.lines_changed('subdir/file1.py')

        # Validate the lines changed
        self.assertEqual(lines_changed, line_numbers(3, 10))

    def test_one_line_file(self):

        # Files with only one line have a special format
        # in which the "length" part of the hunk is not specified
        diff_str = dedent("""
            diff --git a/diff_cover/one_line.txt b/diff_cover/one_line.txt
            index 0867e73..9daeafb 100644
            --- a/diff_cover/one_line.txt
            +++ b/diff_cover/one_line.txt
            @@ -1,3 +1 @@
            test
            -test
            -test
            """).strip()

        # Configure the git diff output
        self._set_git_diff_output(diff_str, "", "")

        # Get the lines changed in the diff
        lines_changed = self.diff.lines_changed('one_line.txt')

        # Expect that no lines are changed
        self.assertEqual(len(lines_changed), 0)

    def test_git_deleted_lines(self):

        # Configure the git diff output
        self._set_git_diff_output(
            git_diff_output({'subdir/file1.py': line_numbers(3, 10) + line_numbers(34, 47)}),
            git_diff_output({'subdir/file2.py': line_numbers(3, 10), 'file3.py': [0]}),
            git_diff_output(dict(), deleted_files=['README.md'])
        )

        # Get the lines changed in the diff
        lines_changed = self.diff.lines_changed('README.md')

        # Validate no lines changed
        self.assertEqual(len(lines_changed), 0)

    def test_git_unicode_filename(self):

        # Filenames with unicode characters have double quotes surrounding them
        # in the git diff output.
        diff_str = dedent("""
            diff --git "a/unic\303\270\342\210\202e\314\201.txt" "b/unic\303\270\342\210\202e\314\201.txt"
            new file mode 100644
            index 0000000..248ebea
            --- /dev/null
            +++ "b/unic\303\270\342\210\202e\314\201.txt"
            @@ -0,0 +1,13 @@
            +μῆνιν ἄειδε θεὰ Πηληϊάδεω Ἀχιλῆος
            +οὐλομένην, ἣ μυρί᾽ Ἀχαιοῖς ἄλγε᾽ ἔθηκε,
            +πολλὰς δ᾽ ἰφθίμους ψυχὰς Ἄϊδι προΐαψεν
            """).strip()

        self._set_git_diff_output(diff_str, "", "")
        # Get the lines changed in the diff
        lines_changed = self.diff.lines_changed('unic\303\270\342\210\202e\314\201.txt')

        # Expect that three lines changed
        self.assertEqual(len(lines_changed), 3)

    def test_git_repeat_lines(self):

        # Same committed, staged, and unstaged lines
        diff = git_diff_output({'subdir/file1.py': line_numbers(3, 10) + line_numbers(34, 47)})
        self._set_git_diff_output(diff, diff, diff)

        # Get the lines changed in the diff
        lines_changed = self.diff.lines_changed('subdir/file1.py')

        # Validate the lines changed
        self.assertEqual(lines_changed, line_numbers(3, 10) + line_numbers(34, 47))

    def test_git_overlapping_lines(self):

        master_diff = git_diff_output(
            {'subdir/file1.py': line_numbers(3, 10) + line_numbers(34, 47)}
        )

        # Overlap, extending the end of the hunk (lines 3 to 10)
        overlap_1 = git_diff_output({'subdir/file1.py': line_numbers(5, 14)})

        # Overlap, extending the beginning of the hunk (lines 34 to 47)
        overlap_2 = git_diff_output({'subdir/file1.py': line_numbers(32, 37)})

        # Lines in staged / unstaged overlap with lines in master
        self._set_git_diff_output(master_diff, overlap_1, overlap_2)

        # Get the lines changed in the diff
        lines_changed = self.diff.lines_changed('subdir/file1.py')

        # Validate the lines changed
        self.assertEqual(lines_changed, line_numbers(3, 14) + line_numbers(32, 47))

    def test_git_line_within_hunk(self):

        master_diff = git_diff_output({'subdir/file1.py': line_numbers(3, 10) + line_numbers(34, 47)})

        # Surround hunk in master (lines 3 to 10)
        surround = git_diff_output({'subdir/file1.py': line_numbers(2, 11)})

        # Within hunk in master (lines 34 to 47)
        within = git_diff_output({'subdir/file1.py': line_numbers(35, 46)})

        # Lines in staged / unstaged overlap with hunks in master
        self._set_git_diff_output(master_diff, surround, within)

        # Get the lines changed in the diff
        lines_changed = self.diff.lines_changed('subdir/file1.py')

        # Validate the lines changed
        self.assertEqual(lines_changed, line_numbers(2, 11) + line_numbers(34, 47))

    def test_inter_diff_conflict(self):

        # Commit changes to lines 3 through 10
        added_diff = git_diff_output({'file.py': line_numbers(3, 10)})

        # Delete the lines we modified
        deleted_lines = []
        for line in added_diff.split('\n'):

            # Any added line becomes a deleted line
            if line.startswith('+'):
                deleted_lines.append(line.replace('+', '-'))

            # No need to include lines we already deleted
            elif line.startswith('-'):
                pass

            # Keep any other line
            else:
                deleted_lines.append(line)

        deleted_diff = "\n".join(deleted_lines)

        # Try all combinations of diff conflicts
        combinations = [(added_diff, deleted_diff, ''),
                        (added_diff, '', deleted_diff),
                        ('', added_diff, deleted_diff),
                        (added_diff, deleted_diff, deleted_diff)]

        for (master_diff, staged_diff, unstaged_diff) in combinations:

            # Set up so we add lines, then delete them
            self._set_git_diff_output(master_diff, staged_diff, unstaged_diff)

            # Should have no lines changed, since
            # we deleted all the lines we modified
            fail_msg = dedent("""
            master_diff = {0}
            staged_diff = {1}
            unstaged_diff = {2}
            """).format(master_diff, staged_diff, unstaged_diff)

            self.assertEqual(self.diff.lines_changed('file.py'), [],
                             msg=fail_msg)

    def test_git_no_such_file(self):

        diff = git_diff_output({
            'subdir/file1.py': [1],
            'subdir/file2.py': [2],
            'file3.py': [3]
        })

        # Configure the git diff output
        self._set_git_diff_output(diff, "", "")

        lines_changed = self.diff.lines_changed('no_such_file.txt')
        self.assertEqual(len(lines_changed), 0)

    def test_no_diff(self):

        # Configure the git diff output
        self._set_git_diff_output('', '', '')

        # Expect no files changed
        source_paths = self.diff.src_paths_changed()
        self.assertEqual(source_paths, [])

    def test_git_diff_error(self):

        invalid_hunk_str = dedent("""
           diff --git a/subdir/file1.py b/subdir/file1.py
           @@ invalid @@ Text
        """).strip()

        no_src_line_str = "@@ -33,10 +34,13 @@ Text"

        non_numeric_lines = dedent("""
            diff --git a/subdir/file1.py b/subdir/file1.py
            @@ -1,2 +a,b @@
        """).strip()

        missing_line_num = dedent("""
            diff --git a/subdir/file1.py b/subdir/file1.py
            @@ -1,2 +  @@
        """).strip()

        missing_src_str = "diff --git "

        # List of (stdout, stderr) git diff pairs that should cause
        # a GitDiffError to be raised.
        err_outputs = [
            invalid_hunk_str, no_src_line_str,
            non_numeric_lines, missing_line_num,
            missing_src_str
        ]

        for diff_str in err_outputs:

            # Configure the git diff output
            self._set_git_diff_output(diff_str, '', '')

            # Expect that both methods that access git diff raise an error
            with self.assertRaises(GitDiffError):
                print("src_paths_changed() "
                      "should fail for {}".format(diff_str))
                self.diff.src_paths_changed()

            with self.assertRaises(GitDiffError):
                print("lines_changed() should fail for {}".format(diff_str))
                self.diff.lines_changed('subdir/file1.py')

    def test_plus_sign_in_hunk_bug(self):

        # This was a bug that caused a parse error
        diff_str = dedent("""
            diff --git a/file.py b/file.py
            @@ -16,16 +16,7 @@ 1 + 2
            + test
            + test
            + test
            + test
            """)

        self._set_git_diff_output(diff_str, '', '')

        lines_changed = self.diff.lines_changed('file.py')
        self.assertEqual(lines_changed, [16, 17, 18, 19])

    def test_terminating_chars_in_hunk(self):

        # Check what happens when there's an @@ symbol after the
        # first terminating @@ symbol
        diff_str = dedent("""
            diff --git a/file.py b/file.py
            @@ -16,16 +16,7 @@ and another +23,2 @@ symbol
            + test
            + test
            + test
            + test
            """)

        self._set_git_diff_output(diff_str, '', '')

        lines_changed = self.diff.lines_changed('file.py')
        self.assertEqual(lines_changed, [16, 17, 18, 19])

    def test_merge_conflict_diff(self):

        # Handle different git diff format when in the middle
        # of a merge conflict
        diff_str = dedent("""
            diff --cc subdir/src.py
            index d2034c0,e594d54..0000000
            diff --cc subdir/src.py
            index d2034c0,e594d54..0000000
            --- a/subdir/src.py
            +++ b/subdir/src.py
            @@@ -16,88 -16,222 +16,7 @@@ text
            + test
            ++<<<<<< HEAD
            + test
            ++=======
        """)

        self._set_git_diff_output(diff_str, '', '')

        lines_changed = self.diff.lines_changed('subdir/src.py')
        self.assertEqual(lines_changed, [16, 17, 18, 19])

    def test_inclusion_list(self):
        unstaged_input = git_diff_output({'subdir/file1.py': line_numbers(3, 10) + line_numbers(34, 47)})
        self._set_git_diff_output('', '', unstaged_input)

        self.assertEqual(3, len(self.diff._get_included_diff_results()))
        self.assertEqual(['', '', unstaged_input], self.diff._get_included_diff_results())

    def test_ignore_staged_inclusion(self):
        self.diff = GitDiffReporter(git_diff=self._git_diff, ignore_staged=True)

        staged_input = git_diff_output({'subdir/file1.py': line_numbers(3, 10) + line_numbers(34, 47)})
        self._set_git_diff_output('', staged_input, '')

        self.assertEqual(2, len(self.diff._get_included_diff_results()))
        self.assertEqual(['', ''], self.diff._get_included_diff_results())

    def test_ignore_unstaged_inclusion(self):
        self.diff = GitDiffReporter(git_diff=self._git_diff, ignore_unstaged=True)

        unstaged_input = git_diff_output({'subdir/file1.py': line_numbers(3, 10) + line_numbers(34, 47)})
        self._set_git_diff_output('', '', unstaged_input)

        self.assertEqual(2, len(self.diff._get_included_diff_results()))
        self.assertEqual(['', ''], self.diff._get_included_diff_results())

    def test_ignore_staged_and_unstaged_inclusion(self):
        self.diff = GitDiffReporter(git_diff=self._git_diff, ignore_staged=True, ignore_unstaged=True)

        staged_input = git_diff_output({'subdir/file1.py': line_numbers(3, 10) + line_numbers(34, 47)})
        unstaged_input = git_diff_output({'subdir/file2.py': line_numbers(3, 10) + line_numbers(34, 47)})
        self._set_git_diff_output('', staged_input, unstaged_input)

        self.assertEqual(1, len(self.diff._get_included_diff_results()))
        self.assertEqual([''], self.diff._get_included_diff_results())

    def test_fnmatch(self):
        """Verify that our fnmatch wrapper works as expected."""
        self.assertTrue(self.diff._fnmatch('foo.py', []))
        self.assertFalse(self.diff._fnmatch('foo.py', ['*.pyc']))
        self.assertTrue(self.diff._fnmatch('foo.pyc', ['*.pyc']))
        self.assertEqual(
            self.diff._fnmatch('foo.pyc', ['*.swp', '*.pyc', '*.py']), True)

    def test_fnmatch_returns_the_default_with_empty_default(self):
        """The default parameter should be returned when no patterns are given.
        """
        sentinel = object()
        self.assertTrue(
            self.diff._fnmatch('file.py', [], default=sentinel) is sentinel)

    def _set_git_diff_output(self, committed_diff,
                             staged_diff, unstaged_diff):
        """
        Configure the git diff tool to return `committed_diff`,
        `staged_diff`, and `unstaged_diff` as outputs from
        `git diff`
        """
        self.diff.clear_cache()
        self._git_diff.diff_committed.return_value = committed_diff
        self._git_diff.diff_staged.return_value = staged_diff
        self._git_diff.diff_unstaged.return_value = unstaged_diff
示例#25
0
def diff(git_diff):
    return GitDiffReporter(git_diff=git_diff)
class GitDiffReporterTest(unittest.TestCase):

    def setUp(self):

        # Create a mock git diff wrapper
        self._git_diff = mock.MagicMock(GitDiffTool)

        # Create the diff reporter
        self.diff = GitDiffReporter(git_diff=self._git_diff)

    def test_name(self):

        # Expect that diff report is named after its compare branch
        self.assertEqual(
            self.diff.name(), 'origin/master...HEAD, staged, and unstaged changes'
        )

    def test_name_compare_branch(self):
        # Override the default branch
        self.assertEqual(
            GitDiffReporter(git_diff=self._git_diff, compare_branch='release').name(),
            'release...HEAD, staged, and unstaged changes'
        )

    def test_git_source_paths(self):

        # Configure the git diff output
        self._set_git_diff_output(
            git_diff_output({'subdir/file1.py': line_numbers(3, 10) + line_numbers(34, 47)}),
            git_diff_output({'subdir/file2.py': line_numbers(3, 10), 'file3.py': [0]}),
            git_diff_output(dict(), deleted_files=['README.md'])
        )

        # Get the source paths in the diff
        source_paths = self.diff.src_paths_changed()

        # Validate the source paths
        # They should be in alphabetical order
        self.assertEqual(len(source_paths), 4)
        self.assertEqual('file3.py', source_paths[0])
        self.assertEqual('README.md', source_paths[1])
        self.assertEqual('subdir/file1.py', source_paths[2])
        self.assertEqual('subdir/file2.py', source_paths[3])

    def test_duplicate_source_paths(self):

        # Duplicate the output for committed, staged, and unstaged changes
        diff = git_diff_output({'subdir/file1.py': line_numbers(3, 10) + line_numbers(34, 47)})
        self._set_git_diff_output(diff, diff, diff)

        # Get the source paths in the diff
        source_paths = self.diff.src_paths_changed()

        # Should see only one copy of source files
        self.assertEqual(len(source_paths), 1)
        self.assertEqual('subdir/file1.py', source_paths[0])

    def test_git_lines_changed(self):

        # Configure the git diff output
        self._set_git_diff_output(
            git_diff_output({'subdir/file1.py': line_numbers(3, 10) + line_numbers(34, 47)}),
            git_diff_output({'subdir/file2.py': line_numbers(3, 10), 'file3.py': [0]}),
            git_diff_output(dict(), deleted_files=['README.md'])
        )

        # Get the lines changed in the diff
        lines_changed = self.diff.lines_changed('subdir/file1.py')

        # Validate the lines changed
        self.assertEqual(lines_changed, line_numbers(3, 10) + line_numbers(34, 47))

    def test_ignore_lines_outside_src(self):

        # Add some lines at the start of the diff, before any
        # source files are specified
        diff = git_diff_output({'subdir/file1.py': line_numbers(3, 10)})
        master_diff = "\n".join(['- deleted line', '+ added line', diff])

        # Configure the git diff output
        self._set_git_diff_output(master_diff, "", "")

        # Get the lines changed in the diff
        lines_changed = self.diff.lines_changed('subdir/file1.py')

        # Validate the lines changed
        self.assertEqual(lines_changed, line_numbers(3, 10))

    def test_one_line_file(self):

        # Files with only one line have a special format
        # in which the "length" part of the hunk is not specified
        diff_str = dedent("""
            diff --git a/diff_cover/one_line.txt b/diff_cover/one_line.txt
            index 0867e73..9daeafb 100644
            --- a/diff_cover/one_line.txt
            +++ b/diff_cover/one_line.txt
            @@ -1,3 +1 @@
            test
            -test
            -test
            """).strip()

        # Configure the git diff output
        self._set_git_diff_output(diff_str, "", "")

        # Get the lines changed in the diff
        lines_changed = self.diff.lines_changed('one_line.txt')

        # Expect that no lines are changed
        self.assertEqual(len(lines_changed), 0)

    def test_git_deleted_lines(self):

        # Configure the git diff output
        self._set_git_diff_output(
            git_diff_output({'subdir/file1.py': line_numbers(3, 10) + line_numbers(34, 47)}),
            git_diff_output({'subdir/file2.py': line_numbers(3, 10), 'file3.py': [0]}),
            git_diff_output(dict(), deleted_files=['README.md'])
        )

        # Get the lines changed in the diff
        lines_changed = self.diff.lines_changed('README.md')

        # Validate no lines changed
        self.assertEqual(len(lines_changed), 0)

    def test_git_unicode_filename(self):

        # Filenames with unicode characters have double quotes surrounding them
        # in the git diff output.
        diff_str = dedent("""
            diff --git "a/unic\303\270\342\210\202e\314\201.txt" "b/unic\303\270\342\210\202e\314\201.txt"
            new file mode 100644
            index 0000000..248ebea
            --- /dev/null
            +++ "b/unic\303\270\342\210\202e\314\201.txt"
            @@ -0,0 +1,13 @@
            +μῆνιν ἄειδε θεὰ Πηληϊάδεω Ἀχιλῆος
            +οὐλομένην, ἣ μυρί᾽ Ἀχαιοῖς ἄλγε᾽ ἔθηκε,
            +πολλὰς δ᾽ ἰφθίμους ψυχὰς Ἄϊδι προΐαψεν
            """).strip()

        self._set_git_diff_output(diff_str, "", "")
        # Get the lines changed in the diff
        lines_changed = self.diff.lines_changed('unic\303\270\342\210\202e\314\201.txt')

        # Expect that three lines changed
        self.assertEqual(len(lines_changed), 3)

    def test_git_repeat_lines(self):

        # Same committed, staged, and unstaged lines
        diff = git_diff_output({'subdir/file1.py': line_numbers(3, 10) + line_numbers(34, 47)})
        self._set_git_diff_output(diff, diff, diff)

        # Get the lines changed in the diff
        lines_changed = self.diff.lines_changed('subdir/file1.py')

        # Validate the lines changed
        self.assertEqual(lines_changed, line_numbers(3, 10) + line_numbers(34, 47))

    def test_git_overlapping_lines(self):

        master_diff = git_diff_output(
            {'subdir/file1.py': line_numbers(3, 10) + line_numbers(34, 47)}
        )

        # Overlap, extending the end of the hunk (lines 3 to 10)
        overlap_1 = git_diff_output({'subdir/file1.py': line_numbers(5, 14)})

        # Overlap, extending the beginning of the hunk (lines 34 to 47)
        overlap_2 = git_diff_output({'subdir/file1.py': line_numbers(32, 37)})

        # Lines in staged / unstaged overlap with lines in master
        self._set_git_diff_output(master_diff, overlap_1, overlap_2)

        # Get the lines changed in the diff
        lines_changed = self.diff.lines_changed('subdir/file1.py')

        # Validate the lines changed
        self.assertEqual(lines_changed, line_numbers(3, 14) + line_numbers(32, 47))

    def test_git_line_within_hunk(self):

        master_diff = git_diff_output({'subdir/file1.py': line_numbers(3, 10) + line_numbers(34, 47)})

        # Surround hunk in master (lines 3 to 10)
        surround = git_diff_output({'subdir/file1.py': line_numbers(2, 11)})

        # Within hunk in master (lines 34 to 47)
        within = git_diff_output({'subdir/file1.py': line_numbers(35, 46)})

        # Lines in staged / unstaged overlap with hunks in master
        self._set_git_diff_output(master_diff, surround, within)

        # Get the lines changed in the diff
        lines_changed = self.diff.lines_changed('subdir/file1.py')

        # Validate the lines changed
        self.assertEqual(lines_changed, line_numbers(2, 11) + line_numbers(34, 47))

    def test_inter_diff_conflict(self):

        # Commit changes to lines 3 through 10
        added_diff = git_diff_output({'file.py': line_numbers(3, 10)})

        # Delete the lines we modified
        deleted_lines = []
        for line in added_diff.split('\n'):

            # Any added line becomes a deleted line
            if line.startswith('+'):
                deleted_lines.append(line.replace('+', '-'))

            # No need to include lines we already deleted
            elif line.startswith('-'):
                pass

            # Keep any other line
            else:
                deleted_lines.append(line)

        deleted_diff = "\n".join(deleted_lines)

        # Try all combinations of diff conflicts
        combinations = [(added_diff, deleted_diff, ''),
                        (added_diff, '', deleted_diff),
                        ('', added_diff, deleted_diff),
                        (added_diff, deleted_diff, deleted_diff)]

        for (master_diff, staged_diff, unstaged_diff) in combinations:

            # Set up so we add lines, then delete them
            self._set_git_diff_output(master_diff, staged_diff, unstaged_diff)

            # Should have no lines changed, since
            # we deleted all the lines we modified
            fail_msg = dedent("""
            master_diff = {0}
            staged_diff = {1}
            unstaged_diff = {2}
            """).format(master_diff, staged_diff, unstaged_diff)

            self.assertEqual(self.diff.lines_changed('file.py'), [],
                             msg=fail_msg)

    def test_git_no_such_file(self):

        diff = git_diff_output({
            'subdir/file1.py': [1],
            'subdir/file2.py': [2],
            'file3.py': [3]
        })

        # Configure the git diff output
        self._set_git_diff_output(diff, "", "")

        lines_changed = self.diff.lines_changed('no_such_file.txt')
        self.assertEqual(len(lines_changed), 0)

    def test_no_diff(self):

        # Configure the git diff output
        self._set_git_diff_output('', '', '')

        # Expect no files changed
        source_paths = self.diff.src_paths_changed()
        self.assertEqual(source_paths, [])

    def test_git_diff_error(self):

        invalid_hunk_str = dedent("""
           diff --git a/subdir/file1.py b/subdir/file1.py
           @@ invalid @@ Text
        """).strip()

        no_src_line_str = "@@ -33,10 +34,13 @@ Text"

        non_numeric_lines = dedent("""
            diff --git a/subdir/file1.py b/subdir/file1.py
            @@ -1,2 +a,b @@
        """).strip()

        missing_line_num = dedent("""
            diff --git a/subdir/file1.py b/subdir/file1.py
            @@ -1,2 +  @@
        """).strip()

        missing_src_str = "diff --git "

        # List of (stdout, stderr) git diff pairs that should cause
        # a GitDiffError to be raised.
        err_outputs = [
            invalid_hunk_str, no_src_line_str,
            non_numeric_lines, missing_line_num,
            missing_src_str
        ]

        for diff_str in err_outputs:

            # Configure the git diff output
            self._set_git_diff_output(diff_str, '', '')

            # Expect that both methods that access git diff raise an error
            with self.assertRaises(GitDiffError):
                print "src_paths_changed() should fail for {0}".format(diff_str)
                self.diff.src_paths_changed()

            with self.assertRaises(GitDiffError):
                print "lines_changed() should fail for {0}".format(diff_str)
                self.diff.lines_changed('subdir/file1.py')

    def test_plus_sign_in_hunk_bug(self):

        # This was a bug that caused a parse error
        diff_str = dedent("""
            diff --git a/file.py b/file.py
            @@ -16,16 +16,7 @@ 1 + 2
            + test
            + test
            + test
            + test
            """)

        self._set_git_diff_output(diff_str, '', '')

        lines_changed = self.diff.lines_changed('file.py')
        self.assertEqual(lines_changed, [16, 17, 18, 19])

    def test_terminating_chars_in_hunk(self):

        # Check what happens when there's an @@ symbol after the
        # first terminating @@ symbol
        diff_str = dedent("""
            diff --git a/file.py b/file.py
            @@ -16,16 +16,7 @@ and another +23,2 @@ symbol
            + test
            + test
            + test
            + test
            """)

        self._set_git_diff_output(diff_str, '', '')

        lines_changed = self.diff.lines_changed('file.py')
        self.assertEqual(lines_changed, [16, 17, 18, 19])

    def test_merge_conflict_diff(self):

        # Handle different git diff format when in the middle
        # of a merge conflict
        diff_str = dedent("""
            diff --cc subdir/src.py
            index d2034c0,e594d54..0000000
            diff --cc subdir/src.py
            index d2034c0,e594d54..0000000
            --- a/subdir/src.py
            +++ b/subdir/src.py
            @@@ -16,88 -16,222 +16,7 @@@ text
            + test
            ++<<<<<< HEAD
            + test
            ++=======
        """)

        self._set_git_diff_output(diff_str, '', '')

        lines_changed = self.diff.lines_changed('subdir/src.py')
        self.assertEqual(lines_changed, [16, 17, 18, 19])

    def _set_git_diff_output(self, committed_diff,
                             staged_diff, unstaged_diff):
        """
        Configure the git diff tool to return `committed_diff`,
        `staged_diff`, and `unstaged_diff` as outputs from
        `git diff`
        """
        self.diff.clear_cache()
        self._git_diff.diff_committed.return_value = committed_diff
        self._git_diff.diff_staged.return_value = staged_diff
        self._git_diff.diff_unstaged.return_value = unstaged_diff
示例#27
0
def test_name_compare_branch(git_diff):
    # Override the default branch
    assert (GitDiffReporter(git_diff=git_diff,
                            compare_branch="release").name() ==
            "release...HEAD, staged and unstaged changes")
示例#28
0
def test_name_ignore_staged_and_unstaged(git_diff):
    # Override the default branch
    assert (GitDiffReporter(
        git_diff=git_diff, ignore_staged=True,
        ignore_unstaged=True).name() == "origin/main...HEAD")
示例#29
0
def generate_coverage_report(coverage_xml, compare_branch,
                             html_report=None, css_file=None,
                             json_report=None,
                             ignore_staged=False, ignore_unstaged=False,
                             exclude=None, src_roots=None, diff_range_notation=None,
                             target_dir=None, diff_json=None):
    """
    Generate the diff coverage report, using kwargs from `parse_args()`.
    """
    if target_dir:
        class FileDiffReporter(GitDiffReporter):
            def __init__(self, *args, **kwargs):
                self.target_dir = kwargs.pop("td")
                super(FileDiffReporter, self).__init__(*args, **kwargs)

            def _git_diff(self):
                def compare(left, right):
                    d = difile.Difile()
                    result = d.compare_dir(left, right)
                    diff_result = dict()

                    for each_file in result:
                        if not each_file:
                            continue
                        key = each_file[0].file_path.as_posix()
                        if key.startswith(str(self.target_dir)):
                            key = key.replace(str(self.target_dir) + "/", "")
                        if key not in diff_result:
                            diff_result[key] = []
                        for each_line in each_file:
                            diff_result[key].append(each_line.line_no)
                    return diff_result
                return compare(src_roots[0], self.target_dir)

        diff = FileDiffReporter(
            compare_branch, git_diff=GitDiffTool(diff_range_notation),
            ignore_staged=ignore_staged, ignore_unstaged=ignore_unstaged,
            exclude=exclude, td=target_dir)
    else:
        diff = GitDiffReporter(
            compare_branch, git_diff=GitDiffTool(diff_range_notation),
            ignore_staged=ignore_staged, ignore_unstaged=ignore_unstaged,
            exclude=exclude)

    xml_roots = [etree.parse(xml_root) for xml_root in coverage_xml]
    coverage = XmlCoverageReporter(xml_roots, src_roots)

    if diff_json:
        diff_dict = diff._git_diff()
        with open(diff_json, "w") as f:
            json.dump(diff_dict, f)

    # Build a report generator
    if html_report is not None:
        css_url = css_file
        if css_url is not None:
            css_url = os.path.relpath(css_file, os.path.dirname(html_report))
        reporter = HtmlReportGenerator(coverage, diff, css_url=css_url)
        with open(html_report, "wb") as output_file:
            reporter.generate_report(output_file)
        if css_file is not None:
            with open(css_file, "wb") as output_file:
                reporter.generate_css(output_file)

    elif json_report is not None:
        reporter = JsonReportGenerator(coverage, diff)
        with open(json_report, "wb") as output_file:
            reporter.generate_report(output_file)

    reporter = StringReportGenerator(coverage, diff)
    output_file = sys.stdout if six.PY2 else sys.stdout.buffer

    # Generate the report
    reporter.generate_report(output_file)
    return reporter.total_percent_covered()
示例#30
0
def test_name_include_untracked(git_diff):
    # Override the default branch
    assert (GitDiffReporter(git_diff=git_diff, include_untracked=True).name()
            == "origin/main...HEAD, staged, unstaged and untracked changes")