]> git.ipfire.org Git - thirdparty/gcc.git/blob - contrib/gcc-changelog/test_email.py
a185b85e8380c3b6dc6869c89e344a8bb2e60491
[thirdparty/gcc.git] / contrib / gcc-changelog / test_email.py
1 #!/usr/bin/env python3
2 #
3 # This file is part of GCC.
4 #
5 # GCC is free software; you can redistribute it and/or modify it under
6 # the terms of the GNU General Public License as published by the Free
7 # Software Foundation; either version 3, or (at your option) any later
8 # version.
9 #
10 # GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 # WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 # for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with GCC; see the file COPYING3. If not see
17 # <http://www.gnu.org/licenses/>. */
18
19 import os
20 import tempfile
21 import unittest
22
23 from git_commit import GitCommit
24
25 from git_email import GitEmail
26
27 import unidiff
28
29 script_path = os.path.dirname(os.path.realpath(__file__))
30
31 unidiff_supports_renaming = hasattr(unidiff.PatchedFile(), 'is_rename')
32
33
34 NAME_STATUS1 = """
35 M gcc/ada/impunit.adb'
36 R097 gcc/ada/libgnat/s-atopar.adb gcc/ada/libgnat/s-aoinar.adb
37 """
38
39
40 class TestGccChangelog(unittest.TestCase):
41 def setUp(self):
42 self.patches = {}
43 self.temps = []
44
45 filename = None
46 patch_lines = []
47 with open(os.path.join(script_path, 'test_patches.txt')) as f:
48 lines = f.read()
49 for line in lines.split('\n'):
50 if line.startswith('==='):
51 if patch_lines:
52 self.patches[filename] = patch_lines
53 filename = line.split(' ')[1]
54 patch_lines = []
55 else:
56 patch_lines.append(line)
57 if patch_lines:
58 self.patches[filename] = patch_lines
59
60 def tearDown(self):
61 for t in self.temps:
62 assert t.endswith('.patch')
63 os.remove(t)
64
65 def get_git_email(self, filename, strict=False):
66 with tempfile.NamedTemporaryFile(mode='w+', suffix='.patch',
67 delete=False) as f:
68 f.write('\n'.join(self.patches[filename]))
69 self.temps.append(f.name)
70 return GitEmail(f.name, strict)
71
72 def from_patch_glob(self, name, strict=False):
73 files = [f for f in self.patches.keys() if f.startswith(name)]
74 assert len(files) == 1
75 return self.get_git_email(files[0], strict)
76
77 def test_simple_patch_format(self):
78 email = self.get_git_email('0577-aarch64-Add-an-and.patch')
79 assert not email.errors
80 assert len(email.changelog_entries) == 2
81 entry = email.changelog_entries[0]
82 assert (entry.author_lines ==
83 [('Richard Sandiford <richard.sandiford@arm.com>',
84 '2020-02-06')])
85 assert len(entry.authors) == 1
86 assert (entry.authors[0]
87 == 'Richard Sandiford <richard.sandiford@arm.com>')
88 assert entry.folder == 'gcc'
89 assert entry.prs == ['PR target/87763']
90 assert len(entry.files) == 3
91 assert entry.files[0] == 'config/aarch64/aarch64-protos.h'
92
93 def test_daily_bump(self):
94 email = self.get_git_email('0085-Daily-bump.patch')
95 assert not email.errors
96 assert not email.changelog_entries
97
98 def test_deduce_changelog_entries(self):
99 email = self.from_patch_glob('0040')
100 assert len(email.changelog_entries) == 2
101 assert email.changelog_entries[0].folder == 'gcc/cp'
102 assert email.changelog_entries[0].prs == ['PR c++/90916']
103 assert email.changelog_entries[0].files == ['pt.c']
104 # this one is added automatically
105 assert email.changelog_entries[1].folder == 'gcc/testsuite'
106
107 def test_only_changelog_updated(self):
108 email = self.from_patch_glob('0129')
109 assert not email.errors
110 assert not email.changelog_entries
111
112 def test_wrong_mentioned_filename(self):
113 email = self.from_patch_glob('0096')
114 assert email.errors
115 err = email.errors[0]
116 assert err.message == 'unchanged file mentioned in a ChangeLog'
117 assert err.line == 'gcc/testsuite/gcc.target/aarch64/' \
118 'advsimd-intrinsics/vdot-compile-3-1.c'
119
120 def test_missing_tab(self):
121 email = self.from_patch_glob('0031')
122 assert len(email.errors) == 2
123 err = email.errors[0]
124 assert err.message == 'line should start with a tab'
125 assert err.line == ' * cfgloopanal.c (average_num_loop_insns): ' \
126 'Free bbs when early'
127
128 def test_leading_changelog_format(self):
129 email = self.from_patch_glob('0184')
130 assert len(email.errors) == 4
131 assert email.errors[0].line == 'gcc/c-family/c-cppbuiltins.c'
132 assert email.errors[2].line == 'gcc/c-family/c-cppbuiltin.c'
133
134 def test_cannot_deduce_no_blank_line(self):
135 email = self.from_patch_glob('0334')
136 assert len(email.errors) == 1
137 assert len(email.changelog_entries) == 1
138 assert email.changelog_entries[0].folder is None
139
140 def test_author_lines(self):
141 email = self.from_patch_glob('0814')
142 assert not email.errors
143 assert (email.changelog_entries[0].author_lines ==
144 [('Martin Jambor <mjambor@suse.cz>', '2020-02-19')])
145
146 def test_multiple_authors_and_prs(self):
147 email = self.from_patch_glob('0735')
148 assert len(email.changelog_entries) == 1
149 entry = email.changelog_entries[0]
150 assert len(entry.author_lines) == 2
151 assert len(entry.authors) == 2
152 assert (entry.author_lines[1] ==
153 ('Bernd Edlinger <bernd.edlinger@hotmail.de>', None))
154
155 def test_multiple_prs(self):
156 email = self.from_patch_glob('1699')
157 assert len(email.changelog_entries) == 2
158 assert len(email.changelog_entries[0].prs) == 2
159
160 def test_missing_PR_component(self):
161 email = self.from_patch_glob('0735')
162 assert len(email.errors) == 1
163 assert email.errors[0].message == 'missing PR component'
164
165 def test_invalid_PR_component(self):
166 email = self.from_patch_glob('0198')
167 assert len(email.errors) == 1
168 assert email.errors[0].message == 'invalid PR component'
169
170 def test_additional_author_list(self):
171 email = self.from_patch_glob('0342')
172 msg = 'additional author must be indented ' \
173 'with one tab and four spaces'
174 assert email.errors[1].message == msg
175
176 def test_trailing_whitespaces(self):
177 email = self.get_git_email('trailing-whitespaces.patch')
178 assert len(email.errors) == 3
179
180 def test_space_after_asterisk(self):
181 email = self.from_patch_glob('1999')
182 assert len(email.errors) == 1
183 assert email.errors[0].message == 'one space should follow asterisk'
184
185 def test_long_lines(self):
186 email = self.get_git_email('long-lines.patch')
187 assert len(email.errors) == 1
188 assert email.errors[0].message == 'line exceeds 100 character limit'
189
190 def test_new_files(self):
191 email = self.from_patch_glob('0030')
192 assert not email.errors
193
194 def test_wrong_changelog_location(self):
195 email = self.from_patch_glob('0043')
196 assert len(email.errors) == 2
197 assert (email.errors[0].message ==
198 'wrong ChangeLog location "gcc", should be "gcc/testsuite"')
199
200 def test_single_author_name(self):
201 email = self.from_patch_glob('1975')
202 assert len(email.changelog_entries) == 2
203 assert len(email.changelog_entries[0].author_lines) == 1
204 assert len(email.changelog_entries[1].author_lines) == 1
205
206 def test_bad_first_line(self):
207 email = self.from_patch_glob('0413')
208 assert len(email.errors) == 1
209
210 def test_co_authored_by(self):
211 email = self.from_patch_glob('1850')
212 assert email.co_authors == ['Jakub Jelinek <jakub@redhat.com>']
213 output_entries = list(email.to_changelog_entries())
214 assert len(output_entries) == 2
215 ent0 = output_entries[0]
216 assert ent0[1].startswith('2020-04-16 Martin Liska '
217 '<mliska@suse.cz>\n\t'
218 ' Jakub Jelinek <jakub@redhat.com>')
219
220 def test_multiple_co_author_formats(self):
221 email = self.get_git_email('co-authored-by.patch')
222 assert len(email.co_authors) == 3
223 assert email.co_authors[0] == 'Jakub Jelinek <jakub@redhat.com>'
224 assert email.co_authors[1] == 'John Miller <jm@example.com>'
225 assert email.co_authors[2] == 'John Miller2 <jm2@example.com>'
226
227 def test_new_file_added_entry(self):
228 email = self.from_patch_glob('1957')
229 output_entries = list(email.to_changelog_entries())
230 assert len(output_entries) == 2
231 needle = ('\t* g++.dg/cpp2a/lambda-generic-variadic20.C'
232 ': New file.')
233 assert output_entries[1][1].endswith(needle)
234 assert email.changelog_entries[1].prs == ['PR c++/94546']
235
236 def test_global_pr_entry(self):
237 email = self.from_patch_glob('2004')
238 assert not email.errors
239 assert email.changelog_entries[0].prs == ['PR other/94629']
240
241 def test_unique_prs(self):
242 email = self.get_git_email('pr-check1.patch')
243 assert not email.errors
244 assert email.changelog_entries[0].prs == ['PR ipa/12345']
245 assert email.changelog_entries[1].prs == []
246
247 def test_multiple_prs_not_added(self):
248 email = self.from_patch_glob('0001-Add-patch_are')
249 assert not email.errors
250 assert email.changelog_entries[0].prs == ['PR target/93492']
251 assert email.changelog_entries[1].prs == ['PR target/12345']
252 assert email.changelog_entries[2].prs == []
253 assert email.changelog_entries[2].folder == 'gcc/testsuite'
254
255 def test_strict_mode(self):
256 email = self.from_patch_glob('0001-Add-patch_are',
257 True)
258 msg = 'ChangeLog, DATESTAMP, BASE-VER and DEV-PHASE updates should ' \
259 'be done separately from normal commits'
260 assert email.errors[0].message == msg
261
262 def test_strict_mode_normal_patch(self):
263 email = self.get_git_email('0001-Just-test-it.patch', True)
264 assert not email.errors
265
266 def test_strict_mode_datestamp_only(self):
267 email = self.get_git_email('0002-Bump-date.patch', True)
268 assert not email.errors
269
270 def test_wrong_changelog_entry(self):
271 email = self.from_patch_glob('0020-IPA-Avoid')
272 msg = 'first line should start with a tab, an asterisk and a space'
273 assert (email.errors[0].message == msg)
274
275 def test_cherry_pick_format(self):
276 email = self.from_patch_glob('0001-c-Alias.patch')
277 assert not email.errors
278
279 def test_signatures(self):
280 email = self.from_patch_glob('0001-RISC-V-Make-unique.patch')
281 assert not email.errors
282 assert len(email.changelog_entries) == 1
283
284 def test_duplicate_top_level_author(self):
285 email = self.from_patch_glob('0001-Fortran-ProcPtr-function.patch')
286 assert not email.errors
287 assert len(email.changelog_entries[0].author_lines) == 1
288
289 def test_dr_entry(self):
290 email = self.from_patch_glob('0001-c-C-20-DR-2237.patch')
291 assert email.changelog_entries[0].prs == ['DR 2237']
292
293 def test_changes_only_in_ignored_location(self):
294 email = self.from_patch_glob('0001-go-in-ignored-location.patch')
295 assert not email.errors
296
297 def test_changelog_for_ignored_location(self):
298 email = self.from_patch_glob('0001-Update-merge.sh-to-reflect.patch')
299 assert (email.changelog_entries[0].lines[0]
300 == '\t* LOCAL_PATCHES: Use git hash instead of SVN id.')
301
302 def test_multiline_file_list(self):
303 email = self.from_patch_glob(
304 '0001-Ada-Reuse-Is_Package_Or_Generic_Package-where-possib.patch')
305 assert (email.changelog_entries[0].files
306 == ['contracts.adb', 'einfo.adb', 'exp_ch9.adb',
307 'sem_ch12.adb', 'sem_ch4.adb', 'sem_ch7.adb',
308 'sem_ch8.adb', 'sem_elab.adb', 'sem_type.adb',
309 'sem_util.adb'])
310
311 @unittest.skipIf(not unidiff_supports_renaming,
312 'Newer version of unidiff is needed (0.6.0+)')
313 def test_renamed_file(self):
314 email = self.from_patch_glob(
315 '0001-Ada-Add-support-for-XDR-streaming-in-the-default-run.patch')
316 assert not email.errors
317
318 def test_duplicite_author_lines(self):
319 email = self.from_patch_glob('0001-Fortran-type-is-real-kind-1.patch')
320 assert (email.changelog_entries[0].author_lines[0][0]
321 == 'Steven G. Kargl <kargl@gcc.gnu.org>')
322 assert (email.changelog_entries[0].author_lines[1][0]
323 == 'Mark Eggleston <markeggleston@gcc.gnu.org>')
324
325 def test_missing_change_description(self):
326 email = self.from_patch_glob('0001-Missing-change-description.patch')
327 assert len(email.errors) == 2
328 assert email.errors[0].message == 'missing description of a change'
329 assert email.errors[1].message == 'missing description of a change'
330
331 def test_libstdcxx_html_regenerated(self):
332 email = self.from_patch_glob('0001-Fix-text-of-hyperlink')
333 assert not email.errors
334 email = self.from_patch_glob('0002-libstdc-Fake-test-change-1.patch')
335 assert len(email.errors) == 1
336 msg = 'pattern doesn''t match any changed files'
337 assert email.errors[0].message == msg
338 assert email.errors[0].line == 'libstdc++-v3/doc/html/'
339 email = self.from_patch_glob('0003-libstdc-Fake-test-change-2.patch')
340 assert len(email.errors) == 1
341 msg = 'changed file not mentioned in a ChangeLog'
342 assert email.errors[0].message == msg
343
344 def test_not_deduce(self):
345 email = self.from_patch_glob('0001-configure.patch')
346 assert not email.errors
347 assert len(email.changelog_entries) == 2
348
349 def test_parse_git_name_status(self):
350 modified_files = GitCommit.parse_git_name_status(NAME_STATUS1)
351 assert len(modified_files) == 3
352 assert modified_files[1] == ('gcc/ada/libgnat/s-atopar.adb', 'D')
353 assert modified_files[2] == ('gcc/ada/libgnat/s-aoinar.adb', 'A')