• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# Copyright 2022 The Pigweed Authors
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may not
5# use this file except in compliance with the License. You may obtain a copy of
6# the License at
7#
8#     https://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations under
14# the License.
15"""Tests for todo_check."""
16
17from pathlib import Path
18import re
19import unittest
20from unittest.mock import MagicMock, mock_open, patch
21
22from pw_presubmit import todo_check
23
24# pylint: disable=attribute-defined-outside-init
25# todo-check: disable
26
27
28# pylint: disable-next=too-many-public-methods
29class TestTodoCheck(unittest.TestCase):
30    """Test TODO checker."""
31
32    def _run(self, regex: re.Pattern, contents: str) -> None:
33        self.ctx = MagicMock()
34        self.ctx.fail = MagicMock()
35        path = MagicMock(spec=Path('foo/bar'))
36
37        def mocked_open_read(*args, **kwargs):
38            return mock_open(read_data=contents)(*args, **kwargs)
39
40        with patch.object(path, 'open', mocked_open_read):
41            # pylint: disable=protected-access
42            todo_check._process_file(self.ctx, regex, path)
43
44            # pylint: enable=protected-access
45
46    def _run_bugs_users(self, contents: str) -> None:
47        self._run(todo_check.BUGS_OR_USERNAMES, contents)
48
49    def _run_bugs(self, contents: str) -> None:
50        self._run(todo_check.BUGS_ONLY, contents)
51
52    def test_one_bug_legacy(self) -> None:
53        contents = 'TODO(b/123): foo\n'
54        self._run_bugs_users(contents)
55        self.ctx.fail.assert_not_called()
56        self._run_bugs(contents)
57        self.ctx.fail.assert_not_called()
58
59    def test_one_bug_new(self) -> None:
60        contents = 'TODO: b/123 - foo\n'
61        self._run_bugs_users(contents)
62        self.ctx.fail.assert_not_called()
63        self._run_bugs(contents)
64        self.ctx.fail.assert_not_called()
65
66    def test_one_bug_short_url(self) -> None:
67        contents = 'TODO: https://pwbug.dev/123 - foo\n'
68        self._run_bugs_users(contents)
69        self.ctx.fail.assert_not_called()
70        self._run_bugs(contents)
71        self.ctx.fail.assert_not_called()
72
73    def test_one_bug_shorter_url(self) -> None:
74        contents = 'TODO: pwbug.dev/123 - foo\n'
75        self._run_bugs_users(contents)
76        self.ctx.fail.assert_not_called()
77        self._run_bugs(contents)
78
79    def test_one_bug_shorter_markdown_url(self) -> None:
80        contents = 'TODO: <pwbug.dev/123> - foo\n'
81        self._run_bugs_users(contents)
82        self.ctx.fail.assert_not_called()
83        self._run_bugs(contents)
84        self.ctx.fail.assert_not_called()
85
86    def test_one_bug_full_url(self) -> None:
87        contents = 'TODO: https://issues.pigweed.dev/issues/123 - foo\n'
88        self._run_bugs_users(contents)
89        self.ctx.fail.assert_not_called()
90        self._run_bugs(contents)
91        self.ctx.fail.assert_not_called()
92
93    def test_two_bugs_legacy(self) -> None:
94        contents = 'TODO(b/123, b/456): foo\n'
95        self._run_bugs_users(contents)
96        self.ctx.fail.assert_not_called()
97        self._run_bugs(contents)
98        self.ctx.fail.assert_not_called()
99
100    def test_two_bugs_new(self) -> None:
101        contents = 'TODO: b/123, b/456 - foo\n'
102        self._run_bugs_users(contents)
103        self.ctx.fail.assert_not_called()
104        self._run_bugs(contents)
105        self.ctx.fail.assert_not_called()
106
107    def test_three_bugs_legacy(self) -> None:
108        contents = 'TODO(b/123,b/456,b/789): foo\n'
109        self._run_bugs_users(contents)
110        self.ctx.fail.assert_not_called()
111        self._run_bugs(contents)
112        self.ctx.fail.assert_not_called()
113
114    def test_three_bugs_new(self) -> None:
115        contents = 'TODO: b/123,b/456,b/789 - foo\n'
116        self._run_bugs_users(contents)
117        self.ctx.fail.assert_not_called()
118        self._run_bugs(contents)
119        self.ctx.fail.assert_not_called()
120
121    def test_one_username_legacy(self) -> None:
122        self._run_bugs_users('TODO(usera): foo\n')
123        self.ctx.fail.assert_not_called()
124
125    def test_one_username_new(self) -> None:
126        self._run_bugs_users('TODO: usera@ - foo\n')
127        self.ctx.fail.assert_not_called()
128
129    def test_one_username_new_noat(self) -> None:
130        self._run_bugs_users('TODO: usera - foo\n')
131        self.ctx.fail.assert_called()
132
133    def test_one_username_new_short_domain(self) -> None:
134        self._run_bugs_users('TODO: usera@com - foo\n')
135        self.ctx.fail.assert_called()
136
137    def test_one_username_new_medium_domain(self) -> None:
138        self._run_bugs_users('TODO: usera@example.com - foo\n')
139        self.ctx.fail.assert_not_called()
140
141    def test_one_username_new_long_domain(self) -> None:
142        self._run_bugs_users('TODO: usera@a.b.c.d.example.com - foo\n')
143        self.ctx.fail.assert_not_called()
144
145    def test_two_usernames_legacy(self) -> None:
146        self._run_bugs_users('TODO(usera, userb): foo\n')
147        self.ctx.fail.assert_not_called()
148
149    def test_two_usernames_new(self) -> None:
150        self._run_bugs_users('TODO: usera@, userb@ - foo\n')
151        self.ctx.fail.assert_not_called()
152
153    def test_three_usernames_legacy(self) -> None:
154        self._run_bugs_users('TODO(usera,userb,userc): foo\n')
155        self.ctx.fail.assert_not_called()
156
157    def test_three_usernames_new(self) -> None:
158        self._run_bugs_users('TODO: usera@,userb@example.com,userc@ - foo\n')
159        self.ctx.fail.assert_not_called()
160
161    def test_username_not_allowed_legacy(self) -> None:
162        self._run_bugs('TODO(usera): foo\n')
163        self.ctx.fail.assert_called()
164
165    def test_username_not_allowed_new(self) -> None:
166        self._run_bugs('TODO: usera@ - foo\n')
167        self.ctx.fail.assert_called()
168
169    def test_space_after_todo_bugsonly_legacy(self) -> None:
170        self._run_bugs('TODO (b/123): foo\n')
171        self.ctx.fail.assert_called()
172
173    def test_space_after_todo_bugsonly_new(self) -> None:
174        self._run_bugs('TODO : b/123 - foo\n')
175        self.ctx.fail.assert_called()
176
177    def test_space_after_todo_bugsusers_legacy(self) -> None:
178        self._run_bugs_users('TODO (b/123): foo\n')
179        self.ctx.fail.assert_called()
180
181    def test_space_after_todo_bugsusers_new(self) -> None:
182        self._run_bugs_users('TODO : b/123 - foo\n')
183        self.ctx.fail.assert_called()
184
185    def test_space_before_bug_bugsonly_legacy(self) -> None:
186        self._run_bugs('TODO( b/123): foo\n')
187        self.ctx.fail.assert_called()
188
189    def test_no_space_before_bug_bugsonly_new(self) -> None:
190        self._run_bugs('TODO:b/123 - foo\n')
191        self.ctx.fail.assert_called()
192
193    def test_space_before_bug_bugsusers_legacy(self) -> None:
194        self._run_bugs_users('TODO( b/123): foo\n')
195        self.ctx.fail.assert_called()
196
197    def test_no_space_before_bug_bugsusers_new(self) -> None:
198        self._run_bugs_users('TODO:b/123 - foo\n')
199        self.ctx.fail.assert_called()
200
201    def test_space_after_bug_bugsonly_legacy(self) -> None:
202        self._run_bugs('TODO(b/123 ): foo\n')
203        self.ctx.fail.assert_called()
204
205    def test_no_space_after_bug_bugsonly_new(self) -> None:
206        self._run_bugs('TODO: b/123- foo\n')
207        self.ctx.fail.assert_called()
208
209    def test_no_space_before_explanation_bugsonly_new(self) -> None:
210        self._run_bugs('TODO: b/123 -foo\n')
211        self.ctx.fail.assert_called()
212
213    def test_space_after_bug_bugsusers_legacy(self) -> None:
214        self._run_bugs_users('TODO(b/123 ): foo\n')
215        self.ctx.fail.assert_called()
216
217    def test_no_space_before_explanation_bugsusers_new(self) -> None:
218        self._run_bugs_users('TODO: b/123 -foo\n')
219        self.ctx.fail.assert_called()
220
221    def test_missing_explanation_bugsonly_legacy(self) -> None:
222        self._run_bugs('TODO: b/123 -\n')
223        self.ctx.fail.assert_called()
224
225    def test_missing_explanation_bugsonly_new(self) -> None:
226        self._run_bugs('TODO: b/123\n')
227        self.ctx.fail.assert_called()
228
229    def test_missing_explanation_bugsusers_legacy(self) -> None:
230        self._run_bugs_users('TODO: b/123 -\n')
231        self.ctx.fail.assert_called()
232
233    def test_missing_explanation_bugsusers_new(self) -> None:
234        self._run_bugs_users('TODO: b/123\n')
235        self.ctx.fail.assert_called()
236
237    def test_not_a_bug_bugsonly_legacy(self) -> None:
238        self._run_bugs('TODO(cl/123): foo\n')
239        self.ctx.fail.assert_called()
240
241    def test_not_a_bug_bugsonly_new(self) -> None:
242        self._run_bugs('TODO: cl/123 - foo\n')
243        self.ctx.fail.assert_called()
244
245    def test_not_a_bug_bugsusers_legacy(self) -> None:
246        self._run_bugs_users('TODO(cl/123): foo\n')
247        self.ctx.fail.assert_called()
248
249    def test_not_a_bug_bugsusers_new(self) -> None:
250        self._run_bugs_users('TODO: cl/123 - foo\n')
251        self.ctx.fail.assert_called()
252
253    def test_but_not_bug_bugsonly_legacy(self) -> None:
254        self._run_bugs('TODO(b/123, cl/123): foo\n')
255        self.ctx.fail.assert_called()
256
257    def test_but_not_bug_bugsonly_new(self) -> None:
258        self._run_bugs('TODO: b/123, cl/123 - foo\n')
259        self.ctx.fail.assert_called()
260
261    def test_bug_not_bug_bugsusers_legacy(self) -> None:
262        self._run_bugs_users('TODO(b/123, cl/123): foo\n')
263        self.ctx.fail.assert_called()
264
265    def test_bug_not_bug_bugsusers_new(self) -> None:
266        self._run_bugs_users('TODO: b/123, cl/123 - foo\n')
267        self.ctx.fail.assert_called()
268
269    def test_empty_bugsonly_legacy(self) -> None:
270        self._run_bugs('TODO(): foo\n')
271        self.ctx.fail.assert_called()
272
273    def test_empty_bugsonly_new(self) -> None:
274        self._run_bugs('TODO: - foo\n')
275        self.ctx.fail.assert_called()
276
277    def test_empty_bugsusers_legacy(self) -> None:
278        self._run_bugs_users('TODO(): foo\n')
279        self.ctx.fail.assert_called()
280
281    def test_empty_bugsusers_new(self) -> None:
282        self._run_bugs_users('TODO: - foo\n')
283        self.ctx.fail.assert_called()
284
285    def test_bare_bugsonly_legacy(self) -> None:
286        self._run_bugs('TODO: foo\n')
287        self.ctx.fail.assert_called()
288
289    def test_bare_bugsonly_new(self) -> None:
290        self._run_bugs('TODO: foo\n')
291        self.ctx.fail.assert_called()
292
293    def test_bare_bugsusers_legacy(self) -> None:
294        self._run_bugs_users('TODO: foo\n')
295        self.ctx.fail.assert_called()
296
297    def test_bare_bugsusers_new(self) -> None:
298        self._run_bugs_users('TODO: foo\n')
299        self.ctx.fail.assert_called()
300
301    def test_fuchsia(self) -> None:
302        self._run_bugs_users('TODO(fxbug.dev/123): foo\n')
303        self.ctx.fail.assert_not_called()
304
305    def test_fuchsia_two_bugs(self) -> None:
306        self._run_bugs_users('TODO(fxbug.dev/123,fxbug.dev/321): bar\n')
307        self.ctx.fail.assert_not_called()
308
309    def test_bazel_gh_issue(self) -> None:
310        contents = (
311            'TODO: https://github.com/bazelbuild/bazel/issues/12345 - '
312            'Bazel sometimes works\n'
313        )
314        self._run_bugs_users(contents)
315        self.ctx.fail.assert_not_called()
316        self._run_bugs(contents)
317        self.ctx.fail.assert_not_called()
318
319    def test_bazel_gh_issue_underscore(self) -> None:
320        contents = (
321            'TODO: https://github.com/bazelbuild/rules_cc/issues/678910 - '
322            'Sometimes it does not work\n'
323        )
324        self._run_bugs_users(contents)
325        self.ctx.fail.assert_not_called()
326        self._run_bugs(contents)
327        self.ctx.fail.assert_not_called()
328
329
330if __name__ == '__main__':
331    unittest.main()
332
333# todo-check: enable
334