blob: 1aa46c688f9015dc9f858654a03a98f9bdcad706 [file] [log] [blame]
Trent Apted72468352023-07-11 16:15:57 +10001# Copyright 2023 The ChromiumOS Authors
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Tests for the analyzers module."""
6
Trent Apted4d4f1bd2023-06-26 12:24:54 +10007from typing import List
Trent Apteded02b392023-06-26 12:47:11 +10008from unittest import mock
Trent Apted4d4f1bd2023-06-26 12:24:54 +10009
Trent Apted72468352023-07-11 16:15:57 +100010from chromite.cli import analyzers
Trent Apted4d4f1bd2023-06-26 12:24:54 +100011from chromite.lib import commandline
12
13
14def process_args(args: List[str]) -> commandline.ArgumentNamespace:
15 """Feeds an ArgumentParser with the provided `args` to AnalyzerCommand."""
16 parser = commandline.ArgumentParser()
17 analyzers.AnalyzerCommand.AddParser(parser)
18 parser_namespace = parser.parse_args(args)
19 analyzers.AnalyzerCommand.ProcessOptions(parser, parser_namespace)
20 return parser_namespace
Trent Apted72468352023-07-11 16:15:57 +100021
22
Trent Apteded02b392023-06-26 12:47:11 +100023# Patch can_modify_files to return True for additional coverage.
24@mock.patch(
25 "chromite.cli.analyzers.AnalyzerCommand.can_modify_files", return_value=True
26)
27def test_get_files_from_commit(_, run_mock) -> None:
Trent Apted4d4f1bd2023-06-26 12:24:54 +100028 """Test files from commit are correctly reconstructed as absolute paths."""
Trent Apted72468352023-07-11 16:15:57 +100029 run_mock.AddCmdResult(
30 ["git", "rev-parse", "--show-toplevel"], stdout="/path/to/root\n"
31 )
Trent Apted4d4f1bd2023-06-26 12:24:54 +100032 run_mock.AddCmdResult(
33 ["git", "diff-tree", "--no-commit-id", "--name-only", "-r", "ignored"],
34 stdout="file1\nsub/file2\n",
35 )
36 # There is a third, more verbose call to `git` to check for uncommitted
37 # changes. Use no output to indicate that there are none.
38 run_mock.SetDefaultCmdResult(stdout="")
39 parser_namespace = process_args(["--commit", "ignored"])
40 assert run_mock.call_count == 3
41 assert parser_namespace.files == [
Trent Apted72468352023-07-11 16:15:57 +100042 "/path/to/root/file1",
43 "/path/to/root/sub/file2",
44 ]
45
46
Trent Apted4d4f1bd2023-06-26 12:24:54 +100047def test_commit_is_pre_submit(run_mock) -> None:
48 """Test the special "pre-submit" commit id used by pre-upload.py."""
49 parser_namespace = process_args(["--commit", "pre-submit"])
50 assert not run_mock.called, "Should not call out to git."
51 assert not parser_namespace.files, "Files should remain empty."
52
53
Trent Apted488c8932023-07-27 13:44:16 +100054@mock.patch.multiple(
55 analyzers.AnalyzerCommand, can_modify_files=True, use_dryrun_options=True
56)
57def test_dry_run_never_inplace() -> None:
58 """Ensure --check ignores --inplace (sets it to False)."""
59 assert process_args(["--inplace"]).inplace
60 assert not process_args(["--check"]).inplace
61 assert not process_args(["--check", "--inplace"]).inplace
62
63
Trent Apted72468352023-07-11 16:15:57 +100064def test_has_uncommitted_changes(run_mock) -> None:
Trent Apted4d4f1bd2023-06-26 12:24:54 +100065 """Test handling of porcelain output for uncommitted change."""
Trent Apted72468352023-07-11 16:15:57 +100066 run_mock.SetDefaultCmdResult(stdout="M file\n")
67 assert analyzers.HasUncommittedChanges(["/path/to/file"]) is True
68
69
70def test_has_no_uncommitted_changes(run_mock) -> None:
Trent Apted4d4f1bd2023-06-26 12:24:54 +100071 """Test handling of porcelain output when no uncommitted changes."""
Trent Apted72468352023-07-11 16:15:57 +100072 run_mock.SetDefaultCmdResult(stdout="")
73 assert analyzers.HasUncommittedChanges(["/path/to/file"]) is False
Mike Frysinger8f9ed8d2023-08-31 10:26:38 -040074
75
76@mock.patch.multiple(
77 analyzers.AnalyzerCommand, can_modify_files=True, use_dryrun_options=True
78)
79def test_inplace_dryrun_default(caplog) -> None:
80 """Check default inplace behavior."""
81 result = process_args(["f.txt"])
82 assert result.inplace
83
84 result = process_args(["--inplace", "f.txt"])
85 assert result.inplace
86
87 result = process_args(["--check", "f.txt"])
88 assert not result.inplace
89
90 # The inplace & dry-run *defaults* should *not* warn on conflicts.
91 assert caplog.text == ""
92
93 result = process_args(["--inplace", "--check", "f.txt"])
94 assert not result.inplace
95
96 # inplace & dry-run options should warn on conflicts.
97 assert caplog.text != ""
98
99
100@mock.patch.multiple(
101 analyzers.AnalyzerCommand, can_modify_files=True, use_dryrun_options=False
102)
103def test_inplace_no_dryrun_default(caplog) -> None:
104 """Check default inplace behavior."""
105 result = process_args(["f.txt"])
106 assert result.inplace
107
108 result = process_args(["--stdout", "f.txt"])
109 assert not result.inplace
110
111 result = process_args(["--stdout", "--inplace", "f.txt"])
112 assert result.inplace
113
114 result = process_args(["--inplace", "--stdout", "f.txt"])
115 assert not result.inplace
116
117 assert caplog.text == ""
118
119
120@mock.patch.multiple(
121 analyzers.AnalyzerCommand, can_modify_files=False, use_dryrun_options=True
122)
123def test_no_inplace_dryrun_default(caplog) -> None:
124 """Make sure we don't crash when inplace isn't enabled."""
125 result = process_args(["f.txt"])
126 assert not hasattr(result, "inplace")
127
128 assert caplog.text == ""
129
130
131@mock.patch.multiple(
132 analyzers.AnalyzerCommand, can_modify_files=False, use_dryrun_options=False
133)
134def test_no_inplace_no_dryrun_default(caplog) -> None:
135 """Make sure we don't crash when these options aren't enabled."""
136 result = process_args(["f.txt"])
137 assert not hasattr(result, "inplace")
138
139 assert caplog.text == ""