blob: 624f388966e0dc986699cd20f0da10812f8a9d54 [file] [log] [blame]
Simon Glassdf1bc5c2017-05-29 15:31:31 -06001# -*- coding: utf-8 -*-
Tom Rini10e47792018-05-06 17:58:06 -04002# SPDX-License-Identifier: GPL-2.0+
Simon Glassdf1bc5c2017-05-29 15:31:31 -06003#
4# Copyright 2017 Google, Inc
5#
Simon Glassdf1bc5c2017-05-29 15:31:31 -06006
Simon Glasseb209e52020-10-29 21:46:15 -06007"""Functional tests for checking that patman behaves correctly"""
8
Simon Glass25b91c12025-04-29 07:22:19 -06009import asyncio
Maxim Cournoyer3ef23e92022-12-20 00:28:46 -050010import contextlib
Simon Glassdf1bc5c2017-05-29 15:31:31 -060011import os
Maxim Cournoyer0331edb2022-12-19 17:32:39 -050012import pathlib
Simon Glassdf1bc5c2017-05-29 15:31:31 -060013import re
14import shutil
15import sys
16import tempfile
17import unittest
18
Simon Glass3db916d2020-10-29 21:46:35 -060019
20from patman.commit import Commit
Simon Glass54f1c5b2020-07-05 21:41:50 -060021from patman import control
Simon Glassa997ea52020-04-17 18:09:04 -060022from patman import patchstream
Simon Glassa7fadab2020-10-29 21:46:26 -060023from patman.patchstream import PatchStream
Simon Glass232eefd2025-04-29 07:22:14 -060024from patman import patchwork
Simon Glassc0257982025-04-29 07:22:11 -060025from patman import send
Simon Glass3db916d2020-10-29 21:46:35 -060026from patman.series import Series
Simon Glassa997ea52020-04-17 18:09:04 -060027from patman import settings
Simon Glassba1b3b92025-02-09 14:26:00 -070028from u_boot_pylib import gitutil
Simon Glass131444f2023-02-23 18:18:04 -070029from u_boot_pylib import terminal
30from u_boot_pylib import tools
Simon Glassdf1bc5c2017-05-29 15:31:31 -060031
Tom Rini488ea972021-02-26 07:52:31 -050032import pygit2
33from patman import status
Simon Glassdf1bc5c2017-05-29 15:31:31 -060034
Maxim Cournoyer3ef23e92022-12-20 00:28:46 -050035PATMAN_DIR = pathlib.Path(__file__).parent
36TEST_DATA_DIR = PATMAN_DIR / 'test/'
Maxim Cournoyer0331edb2022-12-19 17:32:39 -050037
Maxim Cournoyer0331edb2022-12-19 17:32:39 -050038
Maxim Cournoyer3ef23e92022-12-20 00:28:46 -050039@contextlib.contextmanager
40def directory_excursion(directory):
41 """Change directory to `directory` for a limited to the context block."""
42 current = os.getcwd()
43 try:
44 os.chdir(directory)
45 yield
46 finally:
47 os.chdir(current)
48
Maxim Cournoyer0331edb2022-12-19 17:32:39 -050049
Simon Glassdf1bc5c2017-05-29 15:31:31 -060050class TestFunctional(unittest.TestCase):
Simon Glasseb209e52020-10-29 21:46:15 -060051 """Functional tests for checking that patman behaves correctly"""
Simon Glass06202d62020-10-29 21:46:27 -060052 leb = (b'Lord Edmund Blackadd\xc3\xabr <weasel@blackadder.org>'.
53 decode('utf-8'))
Simon Glass3b762cc2020-10-29 21:46:28 -060054 fred = 'Fred Bloggs <f.bloggs@napier.net>'
55 joe = 'Joe Bloggs <joe@napierwallies.co.nz>'
56 mary = 'Mary Bloggs <mary@napierwallies.co.nz>'
Simon Glass3db916d2020-10-29 21:46:35 -060057 commits = None
58 patches = None
Simon Glassed831d12025-04-29 07:22:10 -060059 verbosity = False
60 preserve_outdirs = False
61
62 @classmethod
63 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
64 toolpath=None, verbosity=None, no_capture=False):
65 """Accept arguments controlling test execution
66
67 Args:
68 preserve_indir: not used
69 preserve_outdir: Preserve the output directories used by tests.
70 Each test has its own, so this is normally only useful when
71 running a single test.
72 toolpath: not used
73 """
74 cls.preserve_outdirs = preserve_outdirs
75 cls.toolpath = toolpath
76 cls.verbosity = verbosity
77 cls.no_capture = no_capture
Simon Glass06202d62020-10-29 21:46:27 -060078
Simon Glassdf1bc5c2017-05-29 15:31:31 -060079 def setUp(self):
80 self.tmpdir = tempfile.mkdtemp(prefix='patman.')
Simon Glass54f1c5b2020-07-05 21:41:50 -060081 self.gitdir = os.path.join(self.tmpdir, 'git')
82 self.repo = None
Simon Glassdf1bc5c2017-05-29 15:31:31 -060083
84 def tearDown(self):
Simon Glassed831d12025-04-29 07:22:10 -060085 if self.preserve_outdirs:
86 print(f'Output dir: {self.tmpdir}')
87 else:
88 shutil.rmtree(self.tmpdir)
Simon Glass02811582022-01-29 14:14:18 -070089 terminal.set_print_test_mode(False)
Simon Glassdf1bc5c2017-05-29 15:31:31 -060090
91 @staticmethod
Simon Glasseb209e52020-10-29 21:46:15 -060092 def _get_path(fname):
93 """Get the path to a test file
94
95 Args:
96 fname (str): Filename to obtain
97
98 Returns:
99 str: Full path to file in the test directory
100 """
Maxim Cournoyer0331edb2022-12-19 17:32:39 -0500101 return TEST_DATA_DIR / fname
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600102
103 @classmethod
Simon Glasseb209e52020-10-29 21:46:15 -0600104 def _get_text(cls, fname):
105 """Read a file as text
106
107 Args:
108 fname (str): Filename to read
109
110 Returns:
111 str: Contents of file
112 """
113 return open(cls._get_path(fname), encoding='utf-8').read()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600114
115 @classmethod
Simon Glasseb209e52020-10-29 21:46:15 -0600116 def _get_patch_name(cls, subject):
117 """Get the filename of a patch given its subject
118
119 Args:
120 subject (str): Patch subject
121
122 Returns:
123 str: Filename for that patch
124 """
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600125 fname = re.sub('[ :]', '-', subject)
126 return fname.replace('--', '-')
127
Simon Glasseb209e52020-10-29 21:46:15 -0600128 def _create_patches_for_test(self, series):
129 """Create patch files for use by tests
130
131 This copies patch files from the test directory as needed by the series
132
133 Args:
134 series (Series): Series containing commits to convert
135
136 Returns:
137 tuple:
138 str: Cover-letter filename, or None if none
139 fname_list: list of str, each a patch filename
140 """
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600141 cover_fname = None
142 fname_list = []
143 for i, commit in enumerate(series.commits):
Simon Glasseb209e52020-10-29 21:46:15 -0600144 clean_subject = self._get_patch_name(commit.subject)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600145 src_fname = '%04d-%s.patch' % (i + 1, clean_subject[:52])
146 fname = os.path.join(self.tmpdir, src_fname)
Simon Glasseb209e52020-10-29 21:46:15 -0600147 shutil.copy(self._get_path(src_fname), fname)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600148 fname_list.append(fname)
149 if series.get('cover'):
150 src_fname = '0000-cover-letter.patch'
151 cover_fname = os.path.join(self.tmpdir, src_fname)
152 fname = os.path.join(self.tmpdir, src_fname)
Simon Glasseb209e52020-10-29 21:46:15 -0600153 shutil.copy(self._get_path(src_fname), fname)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600154
155 return cover_fname, fname_list
156
Simon Glassd85bb8f2022-01-29 14:14:09 -0700157 def test_basic(self):
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600158 """Tests the basic flow of patman
159
160 This creates a series from some hard-coded patches build from a simple
161 tree with the following metadata in the top commit:
162
163 Series-to: u-boot
164 Series-prefix: RFC
Sean Andersondc1cd132021-10-22 19:07:04 -0400165 Series-postfix: some-branch
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600166 Series-cc: Stefan Brüns <stefan.bruens@rwth-aachen.de>
167 Cover-letter-cc: Lord Mëlchett <clergy@palace.gov>
Sean Andersoncf13b862020-05-04 16:28:36 -0400168 Series-version: 3
169 Patch-cc: fred
170 Series-process-log: sort, uniq
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600171 Series-changes: 4
172 - Some changes
Sean Andersoncf13b862020-05-04 16:28:36 -0400173 - Multi
174 line
175 change
176
177 Commit-changes: 2
178 - Changes only for this commit
179
Simon Glassf1aab6f2025-04-29 07:22:07 -0600180 Cover-changes: 4
Sean Andersoncf13b862020-05-04 16:28:36 -0400181 - Some notes for the cover letter
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600182
183 Cover-letter:
184 test: A test patch series
185 This is a test of how the cover
Sean Andersoncf13b862020-05-04 16:28:36 -0400186 letter
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600187 works
188 END
189
190 and this in the first commit:
191
Sean Andersoncf13b862020-05-04 16:28:36 -0400192 Commit-changes: 2
193 - second revision change
194
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600195 Series-notes:
196 some notes
197 about some things
198 from the first commit
199 END
200
201 Commit-notes:
202 Some notes about
203 the first commit
204 END
205
206 with the following commands:
207
208 git log -n2 --reverse >/path/to/tools/patman/test/test01.txt
209 git format-patch --subject-prefix RFC --cover-letter HEAD~2
210 mv 00* /path/to/tools/patman/test
211
212 It checks these aspects:
213 - git log can be processed by patchstream
214 - emailing patches uses the correct command
215 - CC file has information on each commit
216 - cover letter has the expected text and subject
217 - each patch has the correct subject
218 - dry-run information prints out correctly
219 - unicode is handled correctly
Sean Andersondc1cd132021-10-22 19:07:04 -0400220 - Series-to, Series-cc, Series-prefix, Series-postfix, Cover-letter
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600221 - Cover-letter-cc, Series-version, Series-changes, Series-notes
222 - Commit-notes
223 """
224 process_tags = True
Simon Glass1f975b92021-01-23 08:56:15 -0700225 ignore_bad_tags = False
Simon Glassb3080ec2025-05-08 04:58:49 +0200226 stefan = (b'Stefan Br\xc3\xbcns <stefan.bruens@rwth-aachen.de>'
227 .decode('utf-8'))
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600228 rick = 'Richard III <richard@palace.gov>'
Simon Glass4f817892019-05-14 15:53:53 -0600229 mel = b'Lord M\xc3\xablchett <clergy@palace.gov>'.decode('utf-8')
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600230 add_maintainers = [stefan, rick]
231 dry_run = True
232 in_reply_to = mel
233 count = 2
Simon Glass5efa3662025-04-07 22:51:45 +1200234 alias = {
Simon Glass95745aa2020-10-29 21:46:13 -0600235 'fdt': ['simon'],
236 'u-boot': ['u-boot@lists.denx.de'],
Simon Glass06202d62020-10-29 21:46:27 -0600237 'simon': [self.leb],
Simon Glass3b762cc2020-10-29 21:46:28 -0600238 'fred': [self.fred],
Sean Anderson25978092024-04-18 22:36:31 -0400239 'joe': [self.joe],
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600240 }
241
Simon Glasseb209e52020-10-29 21:46:15 -0600242 text = self._get_text('test01.txt')
Simon Glass93f61c02020-10-29 21:46:19 -0600243 series = patchstream.get_metadata_for_test(text)
Simon Glass414f1e02025-02-27 12:27:30 -0700244 series.base_commit = Commit('1a44532')
245 series.branch = 'mybranch'
Simon Glasseb209e52020-10-29 21:46:15 -0600246 cover_fname, args = self._create_patches_for_test(series)
Maxim Cournoyer3ef23e92022-12-20 00:28:46 -0500247 get_maintainer_script = str(pathlib.Path(__file__).parent.parent.parent
248 / 'get_maintainer.pl') + ' --norolestats'
Simon Glass14d64e32025-04-29 07:21:59 -0600249 with terminal.capture() as out:
Simon Glass93f61c02020-10-29 21:46:19 -0600250 patchstream.fix_patches(series, args)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600251 if cover_fname and series.get('cover'):
Simon Glass93f61c02020-10-29 21:46:19 -0600252 patchstream.insert_cover_letter(cover_fname, series, count)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600253 series.DoChecks()
254 cc_file = series.MakeCcFile(process_tags, cover_fname,
Chris Packhamb84fb482018-06-07 20:45:06 +1200255 not ignore_bad_tags, add_maintainers,
Simon Glass9938b7b2025-04-07 22:51:46 +1200256 None, get_maintainer_script, alias)
Simon Glass761648b2022-01-29 14:14:11 -0700257 cmd = gitutil.email_patches(
Simon Glass95745aa2020-10-29 21:46:13 -0600258 series, cover_fname, args, dry_run, not ignore_bad_tags,
Simon Glass5efa3662025-04-07 22:51:45 +1200259 cc_file, alias, in_reply_to=in_reply_to, thread=None)
Simon Glass32f12a7e2025-04-07 22:51:47 +1200260 series.ShowActions(args, cmd, process_tags, alias)
Simon Glassf544a2d2019-10-31 07:42:51 -0600261 cc_lines = open(cc_file, encoding='utf-8').read().splitlines()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600262 os.remove(cc_file)
263
Simon Glassb3080ec2025-05-08 04:58:49 +0200264 itr = iter(out[0].getvalue().splitlines())
Simon Glass42e3d392020-10-29 21:46:29 -0600265 self.assertEqual('Cleaned %s patches' % len(series.commits),
Simon Glassb3080ec2025-05-08 04:58:49 +0200266 next(itr))
267 self.assertEqual('Change log missing for v2', next(itr))
268 self.assertEqual('Change log missing for v3', next(itr))
269 self.assertEqual('Change log for unknown version v4', next(itr))
270 self.assertEqual("Alias 'pci' not found", next(itr))
271 while next(itr) != 'Cc processing complete':
Simon Glass620639c2023-03-08 10:52:54 -0800272 pass
Simon Glassb3080ec2025-05-08 04:58:49 +0200273 self.assertIn('Dry run', next(itr))
274 self.assertEqual('', next(itr))
275 self.assertIn('Send a total of %d patches' % count, next(itr))
276 prev = next(itr)
Simon Glass42e3d392020-10-29 21:46:29 -0600277 for i, commit in enumerate(series.commits):
278 self.assertEqual(' %s' % args[i], prev)
279 while True:
Simon Glassb3080ec2025-05-08 04:58:49 +0200280 prev = next(itr)
Simon Glass42e3d392020-10-29 21:46:29 -0600281 if 'Cc:' not in prev:
282 break
283 self.assertEqual('To: u-boot@lists.denx.de', prev)
Simon Glassb3080ec2025-05-08 04:58:49 +0200284 self.assertEqual('Cc: %s' % stefan, next(itr))
285 self.assertEqual('Version: 3', next(itr))
286 self.assertEqual('Prefix:\t RFC', next(itr))
287 self.assertEqual('Postfix:\t some-branch', next(itr))
288 self.assertEqual('Cover: 4 lines', next(itr))
289 self.assertEqual(' Cc: %s' % self.fred, next(itr))
290 self.assertEqual(' Cc: %s' % self.joe, next(itr))
Simon Glass9dfb3112020-11-08 20:36:18 -0700291 self.assertEqual(' Cc: %s' % self.leb,
Simon Glassb3080ec2025-05-08 04:58:49 +0200292 next(itr))
293 self.assertEqual(' Cc: %s' % mel, next(itr))
294 self.assertEqual(' Cc: %s' % rick, next(itr))
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600295 expected = ('Git command: git send-email --annotate '
Simon Glassa8ba0792025-05-08 04:38:30 +0200296 '--in-reply-to="%s" --to u-boot@lists.denx.de '
Simon Glass1ee91c12020-11-03 13:54:10 -0700297 '--cc "%s" --cc-cmd "%s send --cc-cmd %s" %s %s'
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600298 % (in_reply_to, stefan, sys.argv[0], cc_file, cover_fname,
Simon Glass4f817892019-05-14 15:53:53 -0600299 ' '.join(args)))
Simon Glassb3080ec2025-05-08 04:58:49 +0200300 self.assertEqual(expected, next(itr))
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600301
Simon Glass9dfb3112020-11-08 20:36:18 -0700302 self.assertEqual(('%s %s\0%s' % (args[0], rick, stefan)), cc_lines[0])
Simon Glass95745aa2020-10-29 21:46:13 -0600303 self.assertEqual(
Sean Anderson25978092024-04-18 22:36:31 -0400304 '%s %s\0%s\0%s\0%s\0%s' % (args[1], self.fred, self.joe, self.leb,
305 rick, stefan),
Simon Glass9dfb3112020-11-08 20:36:18 -0700306 cc_lines[1])
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600307
308 expected = '''
309This is a test of how the cover
Sean Andersoncf13b862020-05-04 16:28:36 -0400310letter
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600311works
312
313some notes
314about some things
315from the first commit
316
317Changes in v4:
Sean Andersoncf13b862020-05-04 16:28:36 -0400318- Multi
319 line
320 change
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600321- Some changes
Sean Andersoncf13b862020-05-04 16:28:36 -0400322- Some notes for the cover letter
Sean Andersone45678c2024-04-18 22:36:32 -0400323- fdt: Correct cast for sandbox in fdtdec_setup_mem_size_base()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600324
325Simon Glass (2):
326 pci: Correct cast for sandbox
Siva Durga Prasad Paladugub3d55ea2018-07-16 15:56:11 +0530327 fdt: Correct cast for sandbox in fdtdec_setup_mem_size_base()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600328
329 cmd/pci.c | 3 ++-
330 fs/fat/fat.c | 1 +
331 lib/efi_loader/efi_memory.c | 1 +
332 lib/fdtdec.c | 3 ++-
333 4 files changed, 6 insertions(+), 2 deletions(-)
334
335--\x20
3362.7.4
337
Simon Glass414f1e02025-02-27 12:27:30 -0700338base-commit: 1a44532
339branch: mybranch
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600340'''
Simon Glassf544a2d2019-10-31 07:42:51 -0600341 lines = open(cover_fname, encoding='utf-8').read().splitlines()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600342 self.assertEqual(
Sean Andersondc1cd132021-10-22 19:07:04 -0400343 'Subject: [RFC PATCH some-branch v3 0/2] test: A test patch series',
Simon Glass95745aa2020-10-29 21:46:13 -0600344 lines[3])
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600345 self.assertEqual(expected.splitlines(), lines[7:])
346
347 for i, fname in enumerate(args):
Simon Glassf544a2d2019-10-31 07:42:51 -0600348 lines = open(fname, encoding='utf-8').read().splitlines()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600349 subject = [line for line in lines if line.startswith('Subject')]
350 self.assertEqual('Subject: [RFC %d/%d]' % (i + 1, count),
351 subject[0][:18])
Sean Andersoncf13b862020-05-04 16:28:36 -0400352
353 # Check that we got our commit notes
354 start = 0
355 expected = ''
356
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600357 if i == 0:
Sean Andersoncf13b862020-05-04 16:28:36 -0400358 start = 17
359 expected = '''---
360Some notes about
361the first commit
362
363(no changes since v2)
364
365Changes in v2:
366- second revision change'''
367 elif i == 1:
368 start = 17
369 expected = '''---
370
371Changes in v4:
372- Multi
373 line
374 change
Sean Andersone45678c2024-04-18 22:36:32 -0400375- New
Sean Andersoncf13b862020-05-04 16:28:36 -0400376- Some changes
377
378Changes in v2:
379- Changes only for this commit'''
380
381 if expected:
382 expected = expected.splitlines()
383 self.assertEqual(expected, lines[start:(start+len(expected))])
Simon Glass54f1c5b2020-07-05 21:41:50 -0600384
Simon Glassda1a6ec2025-03-28 07:02:20 -0600385 def test_base_commit(self):
386 """Test adding a base commit with no cover letter"""
387 orig_text = self._get_text('test01.txt')
388 pos = orig_text.index('commit 5ab48490f03051875ab13d288a4bf32b507d76fd')
389 text = orig_text[:pos]
390 series = patchstream.get_metadata_for_test(text)
391 series.base_commit = Commit('1a44532')
392 series.branch = 'mybranch'
393 cover_fname, args = self._create_patches_for_test(series)
394 self.assertFalse(cover_fname)
Simon Glass14d64e32025-04-29 07:21:59 -0600395 with terminal.capture() as out:
Simon Glassda1a6ec2025-03-28 07:02:20 -0600396 patchstream.fix_patches(series, args, insert_base_commit=True)
397 self.assertEqual('Cleaned 1 patch\n', out[0].getvalue())
398 lines = tools.read_file(args[0], binary=False).splitlines()
399 pos = lines.index('-- ')
400
401 # We expect these lines at the end:
402 # -- (with trailing space)
403 # 2.7.4
404 # (empty)
405 # base-commit: xxx
406 # branch: xxx
407 self.assertEqual('base-commit: 1a44532', lines[pos + 3])
408 self.assertEqual('branch: mybranch', lines[pos + 4])
409
Simon Glass54f1c5b2020-07-05 21:41:50 -0600410 def make_commit_with_file(self, subject, body, fname, text):
411 """Create a file and add it to the git repo with a new commit
412
413 Args:
414 subject (str): Subject for the commit
415 body (str): Body text of the commit
416 fname (str): Filename of file to create
417 text (str): Text to put into the file
418 """
419 path = os.path.join(self.gitdir, fname)
Simon Glass80025522022-01-29 14:14:04 -0700420 tools.write_file(path, text, binary=False)
Simon Glass54f1c5b2020-07-05 21:41:50 -0600421 index = self.repo.index
422 index.add(fname)
Simon Glass547cba62022-02-11 13:23:18 -0700423 # pylint doesn't seem to find this
424 # pylint: disable=E1101
Simon Glass95745aa2020-10-29 21:46:13 -0600425 author = pygit2.Signature('Test user', 'test@email.com')
Simon Glass54f1c5b2020-07-05 21:41:50 -0600426 committer = author
427 tree = index.write_tree()
428 message = subject + '\n' + body
429 self.repo.create_commit('HEAD', author, committer, message, tree,
430 [self.repo.head.target])
431
432 def make_git_tree(self):
433 """Make a simple git tree suitable for testing
434
435 It has three branches:
436 'base' has two commits: PCI, main
437 'first' has base as upstream and two more commits: I2C, SPI
438 'second' has base as upstream and three more: video, serial, bootm
439
440 Returns:
Simon Glasseb209e52020-10-29 21:46:15 -0600441 pygit2.Repository: repository
Simon Glass54f1c5b2020-07-05 21:41:50 -0600442 """
443 repo = pygit2.init_repository(self.gitdir)
444 self.repo = repo
445 new_tree = repo.TreeBuilder().write()
446
Simon Glass547cba62022-02-11 13:23:18 -0700447 # pylint doesn't seem to find this
448 # pylint: disable=E1101
Simon Glass54f1c5b2020-07-05 21:41:50 -0600449 author = pygit2.Signature('Test user', 'test@email.com')
450 committer = author
Simon Glasseb209e52020-10-29 21:46:15 -0600451 _ = repo.create_commit('HEAD', author, committer, 'Created master',
452 new_tree, [])
Simon Glass54f1c5b2020-07-05 21:41:50 -0600453
454 self.make_commit_with_file('Initial commit', '''
455Add a README
456
457''', 'README', '''This is the README file
458describing this project
459in very little detail''')
460
461 self.make_commit_with_file('pci: PCI implementation', '''
462Here is a basic PCI implementation
463
464''', 'pci.c', '''This is a file
465it has some contents
466and some more things''')
467 self.make_commit_with_file('main: Main program', '''
468Hello here is the second commit.
469''', 'main.c', '''This is the main file
470there is very little here
471but we can always add more later
472if we want to
473
474Series-to: u-boot
475Series-cc: Barry Crump <bcrump@whataroa.nz>
476''')
477 base_target = repo.revparse_single('HEAD')
478 self.make_commit_with_file('i2c: I2C things', '''
479This has some stuff to do with I2C
480''', 'i2c.c', '''And this is the file contents
481with some I2C-related things in it''')
482 self.make_commit_with_file('spi: SPI fixes', '''
483SPI needs some fixes
484and here they are
Simon Glassd0a0a582020-10-29 21:46:36 -0600485
486Signed-off-by: %s
487
488Series-to: u-boot
489Commit-notes:
490title of the series
491This is the cover letter for the series
492with various details
493END
494''' % self.leb, 'spi.c', '''Some fixes for SPI in this
Simon Glass54f1c5b2020-07-05 21:41:50 -0600495file to make SPI work
496better than before''')
497 first_target = repo.revparse_single('HEAD')
498
499 target = repo.revparse_single('HEAD~2')
Simon Glass547cba62022-02-11 13:23:18 -0700500 # pylint doesn't seem to find this
501 # pylint: disable=E1101
Simon Glass54f1c5b2020-07-05 21:41:50 -0600502 repo.reset(target.oid, pygit2.GIT_CHECKOUT_FORCE)
503 self.make_commit_with_file('video: Some video improvements', '''
504Fix up the video so that
505it looks more purple. Purple is
506a very nice colour.
507''', 'video.c', '''More purple here
508Purple and purple
509Even more purple
510Could not be any more purple''')
511 self.make_commit_with_file('serial: Add a serial driver', '''
512Here is the serial driver
513for my chip.
514
515Cover-letter:
516Series for my board
517This series implements support
518for my glorious board.
519END
Simon Glassa80986c2020-10-29 21:46:16 -0600520Series-links: 183237
Simon Glass54f1c5b2020-07-05 21:41:50 -0600521''', 'serial.c', '''The code for the
522serial driver is here''')
523 self.make_commit_with_file('bootm: Make it boot', '''
524This makes my board boot
525with a fix to the bootm
526command
527''', 'bootm.c', '''Fix up the bootm
528command to make the code as
529complicated as possible''')
530 second_target = repo.revparse_single('HEAD')
531
532 repo.branches.local.create('first', first_target)
533 repo.config.set_multivar('branch.first.remote', '', '.')
534 repo.config.set_multivar('branch.first.merge', '', 'refs/heads/base')
535
536 repo.branches.local.create('second', second_target)
537 repo.config.set_multivar('branch.second.remote', '', '.')
538 repo.config.set_multivar('branch.second.merge', '', 'refs/heads/base')
539
540 repo.branches.local.create('base', base_target)
541 return repo
542
Simon Glassd85bb8f2022-01-29 14:14:09 -0700543 def test_branch(self):
Simon Glass54f1c5b2020-07-05 21:41:50 -0600544 """Test creating patches from a branch"""
545 repo = self.make_git_tree()
546 target = repo.lookup_reference('refs/heads/first')
Simon Glass547cba62022-02-11 13:23:18 -0700547 # pylint doesn't seem to find this
548 # pylint: disable=E1101
Simon Glass54f1c5b2020-07-05 21:41:50 -0600549 self.repo.checkout(target, strategy=pygit2.GIT_CHECKOUT_FORCE)
550 control.setup()
Heinrich Schuchardtd01d6672023-04-20 20:07:29 +0200551 orig_dir = os.getcwd()
Simon Glass54f1c5b2020-07-05 21:41:50 -0600552 try:
Simon Glass54f1c5b2020-07-05 21:41:50 -0600553 os.chdir(self.gitdir)
554
555 # Check that it can detect the current branch
Simon Glass761648b2022-01-29 14:14:11 -0700556 self.assertEqual(2, gitutil.count_commits_to_branch(None))
Simon Glass54f1c5b2020-07-05 21:41:50 -0600557 col = terminal.Color()
Simon Glass14d64e32025-04-29 07:21:59 -0600558 with terminal.capture() as _:
Simon Glassc0257982025-04-29 07:22:11 -0600559 _, cover_fname, patch_files = send.prepare_patches(
Simon Glassb3bf4e12020-07-05 21:41:52 -0600560 col, branch=None, count=-1, start=0, end=0,
Philipp Tomsich858531a2020-11-24 18:14:52 +0100561 ignore_binary=False, signoff=True)
Simon Glass54f1c5b2020-07-05 21:41:50 -0600562 self.assertIsNone(cover_fname)
563 self.assertEqual(2, len(patch_files))
Simon Glass2eb4da72020-07-05 21:41:51 -0600564
565 # Check that it can detect a different branch
Simon Glass761648b2022-01-29 14:14:11 -0700566 self.assertEqual(3, gitutil.count_commits_to_branch('second'))
Simon Glass14d64e32025-04-29 07:21:59 -0600567 with terminal.capture() as _:
Simon Glassc0257982025-04-29 07:22:11 -0600568 series, cover_fname, patch_files = send.prepare_patches(
Simon Glassb3bf4e12020-07-05 21:41:52 -0600569 col, branch='second', count=-1, start=0, end=0,
Philipp Tomsich858531a2020-11-24 18:14:52 +0100570 ignore_binary=False, signoff=True)
Simon Glass2eb4da72020-07-05 21:41:51 -0600571 self.assertIsNotNone(cover_fname)
572 self.assertEqual(3, len(patch_files))
Simon Glassb3bf4e12020-07-05 21:41:52 -0600573
Simon Glass414f1e02025-02-27 12:27:30 -0700574 cover = tools.read_file(cover_fname, binary=False)
575 lines = cover.splitlines()[-2:]
576 base = repo.lookup_reference('refs/heads/base').target
577 self.assertEqual(f'base-commit: {base}', lines[0])
578 self.assertEqual('branch: second', lines[1])
579
Simon Glassda1a6ec2025-03-28 07:02:20 -0600580 # Make sure that the base-commit is not present when it is in the
581 # cover letter
582 for fname in patch_files:
583 self.assertNotIn(b'base-commit:', tools.read_file(fname))
584
Simon Glassb3bf4e12020-07-05 21:41:52 -0600585 # Check that it can skip patches at the end
Simon Glass14d64e32025-04-29 07:21:59 -0600586 with terminal.capture() as _:
Simon Glassc0257982025-04-29 07:22:11 -0600587 _, cover_fname, patch_files = send.prepare_patches(
Simon Glassb3bf4e12020-07-05 21:41:52 -0600588 col, branch='second', count=-1, start=0, end=1,
Philipp Tomsich858531a2020-11-24 18:14:52 +0100589 ignore_binary=False, signoff=True)
Simon Glassb3bf4e12020-07-05 21:41:52 -0600590 self.assertIsNotNone(cover_fname)
591 self.assertEqual(2, len(patch_files))
Simon Glass414f1e02025-02-27 12:27:30 -0700592
593 cover = tools.read_file(cover_fname, binary=False)
594 lines = cover.splitlines()[-2:]
595 base2 = repo.lookup_reference('refs/heads/second')
596 ref = base2.peel(pygit2.GIT_OBJ_COMMIT).parents[0].parents[0].id
597 self.assertEqual(f'base-commit: {ref}', lines[0])
598 self.assertEqual('branch: second', lines[1])
Simon Glass54f1c5b2020-07-05 21:41:50 -0600599 finally:
600 os.chdir(orig_dir)
Simon Glass06202d62020-10-29 21:46:27 -0600601
Maxim Cournoyer3ef23e92022-12-20 00:28:46 -0500602 def test_custom_get_maintainer_script(self):
603 """Validate that a custom get_maintainer script gets used."""
604 self.make_git_tree()
605 with directory_excursion(self.gitdir):
606 # Setup git.
607 os.environ['GIT_CONFIG_GLOBAL'] = '/dev/null'
608 os.environ['GIT_CONFIG_SYSTEM'] = '/dev/null'
609 tools.run('git', 'config', 'user.name', 'Dummy')
610 tools.run('git', 'config', 'user.email', 'dumdum@dummy.com')
611 tools.run('git', 'branch', 'upstream')
612 tools.run('git', 'branch', '--set-upstream-to=upstream')
613 tools.run('git', 'add', '.')
614 tools.run('git', 'commit', '-m', 'new commit')
615
616 # Setup patman configuration.
617 with open('.patman', 'w', buffering=1) as f:
618 f.write('[settings]\n'
619 'get_maintainer_script: dummy-script.sh\n'
Sean Andersona06df742024-04-18 22:36:30 -0400620 'check_patch: False\n'
621 'add_maintainers: True\n')
Maxim Cournoyer3ef23e92022-12-20 00:28:46 -0500622 with open('dummy-script.sh', 'w', buffering=1) as f:
623 f.write('#!/usr/bin/env python\n'
624 'print("hello@there.com")\n')
625 os.chmod('dummy-script.sh', 0x555)
626
627 # Finally, do the test
Simon Glass14d64e32025-04-29 07:21:59 -0600628 with terminal.capture():
Maxim Cournoyer3ef23e92022-12-20 00:28:46 -0500629 output = tools.run(PATMAN_DIR / 'patman', '--dry-run')
630 # Assert the email address is part of the dry-run
631 # output.
632 self.assertIn('hello@there.com', output)
633
Simon Glassd85bb8f2022-01-29 14:14:09 -0700634 def test_tags(self):
Simon Glass06202d62020-10-29 21:46:27 -0600635 """Test collection of tags in a patchstream"""
636 text = '''This is a patch
637
638Signed-off-by: Terminator
Simon Glass3b762cc2020-10-29 21:46:28 -0600639Reviewed-by: %s
640Reviewed-by: %s
Simon Glass06202d62020-10-29 21:46:27 -0600641Tested-by: %s
Simon Glass3b762cc2020-10-29 21:46:28 -0600642''' % (self.joe, self.mary, self.leb)
Simon Glass06202d62020-10-29 21:46:27 -0600643 pstrm = PatchStream.process_text(text)
644 self.assertEqual(pstrm.commit.rtags, {
Simon Glass3b762cc2020-10-29 21:46:28 -0600645 'Reviewed-by': {self.joe, self.mary},
Simon Glass06202d62020-10-29 21:46:27 -0600646 'Tested-by': {self.leb}})
Simon Glass3b762cc2020-10-29 21:46:28 -0600647
Simon Glassd85bb8f2022-01-29 14:14:09 -0700648 def test_invalid_tag(self):
Patrick Delaunay6bbdd0c2021-07-22 16:51:42 +0200649 """Test invalid tag in a patchstream"""
650 text = '''This is a patch
651
652Serie-version: 2
653'''
654 with self.assertRaises(ValueError) as exc:
655 pstrm = PatchStream.process_text(text)
656 self.assertEqual("Line 3: Invalid tag = 'Serie-version: 2'",
657 str(exc.exception))
658
Simon Glassd85bb8f2022-01-29 14:14:09 -0700659 def test_missing_end(self):
Simon Glass3b762cc2020-10-29 21:46:28 -0600660 """Test a missing END tag"""
661 text = '''This is a patch
662
663Cover-letter:
664This is the title
665missing END after this line
666Signed-off-by: Fred
667'''
668 pstrm = PatchStream.process_text(text)
669 self.assertEqual(["Missing 'END' in section 'cover'"],
670 pstrm.commit.warn)
671
Simon Glassd85bb8f2022-01-29 14:14:09 -0700672 def test_missing_blank_line(self):
Simon Glass3b762cc2020-10-29 21:46:28 -0600673 """Test a missing blank line after a tag"""
674 text = '''This is a patch
675
676Series-changes: 2
677- First line of changes
678- Missing blank line after this line
679Signed-off-by: Fred
680'''
681 pstrm = PatchStream.process_text(text)
682 self.assertEqual(["Missing 'blank line' in section 'Series-changes'"],
683 pstrm.commit.warn)
684
Simon Glassd85bb8f2022-01-29 14:14:09 -0700685 def test_invalid_commit_tag(self):
Simon Glass3b762cc2020-10-29 21:46:28 -0600686 """Test an invalid Commit-xxx tag"""
687 text = '''This is a patch
688
689Commit-fred: testing
690'''
691 pstrm = PatchStream.process_text(text)
692 self.assertEqual(["Line 3: Ignoring Commit-fred"], pstrm.commit.warn)
693
Simon Glassd85bb8f2022-01-29 14:14:09 -0700694 def test_self_test(self):
Simon Glass3b762cc2020-10-29 21:46:28 -0600695 """Test a tested by tag by this user"""
696 test_line = 'Tested-by: %s@napier.com' % os.getenv('USER')
697 text = '''This is a patch
698
699%s
700''' % test_line
701 pstrm = PatchStream.process_text(text)
702 self.assertEqual(["Ignoring '%s'" % test_line], pstrm.commit.warn)
703
Simon Glassd85bb8f2022-01-29 14:14:09 -0700704 def test_space_before_tab(self):
Simon Glass3b762cc2020-10-29 21:46:28 -0600705 """Test a space before a tab"""
706 text = '''This is a patch
707
708+ \tSomething
709'''
710 pstrm = PatchStream.process_text(text)
711 self.assertEqual(["Line 3/0 has space before tab"], pstrm.commit.warn)
712
Simon Glassd85bb8f2022-01-29 14:14:09 -0700713 def test_lines_after_test(self):
Simon Glass3b762cc2020-10-29 21:46:28 -0600714 """Test detecting lines after TEST= line"""
715 text = '''This is a patch
716
717TEST=sometest
718more lines
719here
720'''
721 pstrm = PatchStream.process_text(text)
722 self.assertEqual(["Found 2 lines after TEST="], pstrm.commit.warn)
723
Simon Glassd85bb8f2022-01-29 14:14:09 -0700724 def test_blank_line_at_end(self):
Simon Glass3b762cc2020-10-29 21:46:28 -0600725 """Test detecting a blank line at the end of a file"""
726 text = '''This is a patch
727
728diff --git a/lib/fdtdec.c b/lib/fdtdec.c
729index c072e54..942244f 100644
730--- a/lib/fdtdec.c
731+++ b/lib/fdtdec.c
732@@ -1200,7 +1200,8 @@ int fdtdec_setup_mem_size_base(void)
733 }
734
735 gd->ram_size = (phys_size_t)(res.end - res.start + 1);
736- debug("%s: Initial DRAM size %llx\n", __func__, (u64)gd->ram_size);
737+ debug("%s: Initial DRAM size %llx\n", __func__,
738+ (unsigned long long)gd->ram_size);
739+
740diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
741
742--
7432.7.4
744
745 '''
746 pstrm = PatchStream.process_text(text)
747 self.assertEqual(
748 ["Found possible blank line(s) at end of file 'lib/fdtdec.c'"],
749 pstrm.commit.warn)
Simon Glass1c1f2072020-10-29 21:46:34 -0600750
Simon Glassd85bb8f2022-01-29 14:14:09 -0700751 def test_no_upstream(self):
Simon Glass1c1f2072020-10-29 21:46:34 -0600752 """Test CountCommitsToBranch when there is no upstream"""
753 repo = self.make_git_tree()
754 target = repo.lookup_reference('refs/heads/base')
Simon Glass547cba62022-02-11 13:23:18 -0700755 # pylint doesn't seem to find this
756 # pylint: disable=E1101
Simon Glass1c1f2072020-10-29 21:46:34 -0600757 self.repo.checkout(target, strategy=pygit2.GIT_CHECKOUT_FORCE)
758
759 # Check that it can detect the current branch
Heinrich Schuchardtd01d6672023-04-20 20:07:29 +0200760 orig_dir = os.getcwd()
Simon Glass1c1f2072020-10-29 21:46:34 -0600761 try:
Simon Glass1c1f2072020-10-29 21:46:34 -0600762 os.chdir(self.gitdir)
763 with self.assertRaises(ValueError) as exc:
Simon Glass761648b2022-01-29 14:14:11 -0700764 gitutil.count_commits_to_branch(None)
Simon Glass1c1f2072020-10-29 21:46:34 -0600765 self.assertIn(
766 "Failed to determine upstream: fatal: no upstream configured for branch 'base'",
767 str(exc.exception))
768 finally:
769 os.chdir(orig_dir)
Simon Glass3db916d2020-10-29 21:46:35 -0600770
771 @staticmethod
Simon Glass25b91c12025-04-29 07:22:19 -0600772 def _fake_patchwork(subpath):
Simon Glass3db916d2020-10-29 21:46:35 -0600773 """Fake Patchwork server for the function below
774
775 This handles accessing a series, providing a list consisting of a
776 single patch
Simon Glassf9b03cf2020-11-03 13:54:14 -0700777
778 Args:
Simon Glassf9b03cf2020-11-03 13:54:14 -0700779 subpath (str): URL subpath to use
Simon Glass3db916d2020-10-29 21:46:35 -0600780 """
781 re_series = re.match(r'series/(\d*)/$', subpath)
782 if re_series:
783 series_num = re_series.group(1)
784 if series_num == '1234':
785 return {'patches': [
786 {'id': '1', 'name': 'Some patch'}]}
787 raise ValueError('Fake Patchwork does not understand: %s' % subpath)
788
Simon Glassd85bb8f2022-01-29 14:14:09 -0700789 def test_status_mismatch(self):
Simon Glass3db916d2020-10-29 21:46:35 -0600790 """Test Patchwork patches not matching the series"""
Simon Glass25b91c12025-04-29 07:22:19 -0600791 pwork = patchwork.Patchwork.for_testing(self._fake_patchwork)
Simon Glass14d64e32025-04-29 07:21:59 -0600792 with terminal.capture() as (_, err):
Simon Glass3729b8b2025-04-29 07:22:24 -0600793 patches = asyncio.run(status.check_status(1234, pwork))
Simon Glass27280f42025-04-29 07:22:17 -0600794 status.check_patch_count(0, len(patches))
Simon Glass3db916d2020-10-29 21:46:35 -0600795 self.assertIn('Warning: Patchwork reports 1 patches, series has 0',
796 err.getvalue())
797
Simon Glassd85bb8f2022-01-29 14:14:09 -0700798 def test_status_read_patch(self):
Simon Glass3db916d2020-10-29 21:46:35 -0600799 """Test handling a single patch in Patchwork"""
Simon Glass25b91c12025-04-29 07:22:19 -0600800 pwork = patchwork.Patchwork.for_testing(self._fake_patchwork)
Simon Glass3729b8b2025-04-29 07:22:24 -0600801 patches = asyncio.run(status.check_status(1234, pwork))
Simon Glass3db916d2020-10-29 21:46:35 -0600802 self.assertEqual(1, len(patches))
803 patch = patches[0]
804 self.assertEqual('1', patch.id)
805 self.assertEqual('Some patch', patch.raw_subject)
806
Simon Glassd85bb8f2022-01-29 14:14:09 -0700807 def test_parse_subject(self):
Simon Glass3db916d2020-10-29 21:46:35 -0600808 """Test parsing of the patch subject"""
Simon Glass232eefd2025-04-29 07:22:14 -0600809 patch = patchwork.Patch('1')
Simon Glass3db916d2020-10-29 21:46:35 -0600810
811 # Simple patch not in a series
812 patch.parse_subject('Testing')
813 self.assertEqual('Testing', patch.raw_subject)
814 self.assertEqual('Testing', patch.subject)
815 self.assertEqual(1, patch.seq)
816 self.assertEqual(1, patch.count)
817 self.assertEqual(None, patch.prefix)
818 self.assertEqual(None, patch.version)
819
820 # First patch in a series
821 patch.parse_subject('[1/2] Testing')
822 self.assertEqual('[1/2] Testing', patch.raw_subject)
823 self.assertEqual('Testing', patch.subject)
824 self.assertEqual(1, patch.seq)
825 self.assertEqual(2, patch.count)
826 self.assertEqual(None, patch.prefix)
827 self.assertEqual(None, patch.version)
828
829 # Second patch in a series
830 patch.parse_subject('[2/2] Testing')
831 self.assertEqual('Testing', patch.subject)
832 self.assertEqual(2, patch.seq)
833 self.assertEqual(2, patch.count)
834 self.assertEqual(None, patch.prefix)
835 self.assertEqual(None, patch.version)
836
837 # RFC patch
838 patch.parse_subject('[RFC,3/7] Testing')
839 self.assertEqual('Testing', patch.subject)
840 self.assertEqual(3, patch.seq)
841 self.assertEqual(7, patch.count)
842 self.assertEqual('RFC', patch.prefix)
843 self.assertEqual(None, patch.version)
844
845 # Version patch
846 patch.parse_subject('[v2,3/7] Testing')
847 self.assertEqual('Testing', patch.subject)
848 self.assertEqual(3, patch.seq)
849 self.assertEqual(7, patch.count)
850 self.assertEqual(None, patch.prefix)
851 self.assertEqual('v2', patch.version)
852
853 # All fields
854 patch.parse_subject('[RESEND,v2,3/7] Testing')
855 self.assertEqual('Testing', patch.subject)
856 self.assertEqual(3, patch.seq)
857 self.assertEqual(7, patch.count)
858 self.assertEqual('RESEND', patch.prefix)
859 self.assertEqual('v2', patch.version)
860
861 # RFC only
862 patch.parse_subject('[RESEND] Testing')
863 self.assertEqual('Testing', patch.subject)
864 self.assertEqual(1, patch.seq)
865 self.assertEqual(1, patch.count)
866 self.assertEqual('RESEND', patch.prefix)
867 self.assertEqual(None, patch.version)
868
Simon Glassd85bb8f2022-01-29 14:14:09 -0700869 def test_compare_series(self):
Simon Glass3db916d2020-10-29 21:46:35 -0600870 """Test operation of compare_with_series()"""
871 commit1 = Commit('abcd')
872 commit1.subject = 'Subject 1'
873 commit2 = Commit('ef12')
874 commit2.subject = 'Subject 2'
875 commit3 = Commit('3456')
876 commit3.subject = 'Subject 2'
877
Simon Glass232eefd2025-04-29 07:22:14 -0600878 patch1 = patchwork.Patch('1')
Simon Glass3db916d2020-10-29 21:46:35 -0600879 patch1.subject = 'Subject 1'
Simon Glass232eefd2025-04-29 07:22:14 -0600880 patch2 = patchwork.Patch('2')
Simon Glass3db916d2020-10-29 21:46:35 -0600881 patch2.subject = 'Subject 2'
Simon Glass232eefd2025-04-29 07:22:14 -0600882 patch3 = patchwork.Patch('3')
Simon Glass3db916d2020-10-29 21:46:35 -0600883 patch3.subject = 'Subject 2'
884
885 series = Series()
886 series.commits = [commit1]
887 patches = [patch1]
888 patch_for_commit, commit_for_patch, warnings = (
889 status.compare_with_series(series, patches))
890 self.assertEqual(1, len(patch_for_commit))
891 self.assertEqual(patch1, patch_for_commit[0])
892 self.assertEqual(1, len(commit_for_patch))
893 self.assertEqual(commit1, commit_for_patch[0])
894
895 series.commits = [commit1]
896 patches = [patch1, patch2]
897 patch_for_commit, commit_for_patch, warnings = (
898 status.compare_with_series(series, patches))
899 self.assertEqual(1, len(patch_for_commit))
900 self.assertEqual(patch1, patch_for_commit[0])
901 self.assertEqual(1, len(commit_for_patch))
902 self.assertEqual(commit1, commit_for_patch[0])
903 self.assertEqual(["Cannot find commit for patch 2 ('Subject 2')"],
904 warnings)
905
906 series.commits = [commit1, commit2]
907 patches = [patch1]
908 patch_for_commit, commit_for_patch, warnings = (
909 status.compare_with_series(series, patches))
910 self.assertEqual(1, len(patch_for_commit))
911 self.assertEqual(patch1, patch_for_commit[0])
912 self.assertEqual(1, len(commit_for_patch))
913 self.assertEqual(commit1, commit_for_patch[0])
914 self.assertEqual(["Cannot find patch for commit 2 ('Subject 2')"],
915 warnings)
916
917 series.commits = [commit1, commit2, commit3]
918 patches = [patch1, patch2]
919 patch_for_commit, commit_for_patch, warnings = (
920 status.compare_with_series(series, patches))
921 self.assertEqual(2, len(patch_for_commit))
922 self.assertEqual(patch1, patch_for_commit[0])
923 self.assertEqual(patch2, patch_for_commit[1])
924 self.assertEqual(1, len(commit_for_patch))
925 self.assertEqual(commit1, commit_for_patch[0])
926 self.assertEqual(["Cannot find patch for commit 3 ('Subject 2')",
927 "Multiple commits match patch 2 ('Subject 2'):\n"
928 ' Subject 2\n Subject 2'],
929 warnings)
930
931 series.commits = [commit1, commit2]
932 patches = [patch1, patch2, patch3]
933 patch_for_commit, commit_for_patch, warnings = (
934 status.compare_with_series(series, patches))
935 self.assertEqual(1, len(patch_for_commit))
936 self.assertEqual(patch1, patch_for_commit[0])
937 self.assertEqual(2, len(commit_for_patch))
938 self.assertEqual(commit1, commit_for_patch[0])
939 self.assertEqual(["Multiple patches match commit 2 ('Subject 2'):\n"
940 ' Subject 2\n Subject 2',
941 "Cannot find commit for patch 3 ('Subject 2')"],
942 warnings)
943
Simon Glass25b91c12025-04-29 07:22:19 -0600944 def _fake_patchwork2(self, subpath):
Simon Glass3db916d2020-10-29 21:46:35 -0600945 """Fake Patchwork server for the function below
946
947 This handles accessing series, patches and comments, providing the data
948 in self.patches to the caller
Simon Glassf9b03cf2020-11-03 13:54:14 -0700949
950 Args:
Simon Glassf9b03cf2020-11-03 13:54:14 -0700951 subpath (str): URL subpath to use
Simon Glass3db916d2020-10-29 21:46:35 -0600952 """
953 re_series = re.match(r'series/(\d*)/$', subpath)
954 re_patch = re.match(r'patches/(\d*)/$', subpath)
955 re_comments = re.match(r'patches/(\d*)/comments/$', subpath)
956 if re_series:
957 series_num = re_series.group(1)
958 if series_num == '1234':
959 return {'patches': self.patches}
960 elif re_patch:
961 patch_num = int(re_patch.group(1))
962 patch = self.patches[patch_num - 1]
963 return patch
964 elif re_comments:
965 patch_num = int(re_comments.group(1))
966 patch = self.patches[patch_num - 1]
967 return patch.comments
968 raise ValueError('Fake Patchwork does not understand: %s' % subpath)
969
Simon Glassd85bb8f2022-01-29 14:14:09 -0700970 def test_find_new_responses(self):
Simon Glass3db916d2020-10-29 21:46:35 -0600971 """Test operation of find_new_responses()"""
972 commit1 = Commit('abcd')
973 commit1.subject = 'Subject 1'
974 commit2 = Commit('ef12')
975 commit2.subject = 'Subject 2'
976
Simon Glass232eefd2025-04-29 07:22:14 -0600977 patch1 = patchwork.Patch('1')
Simon Glass3db916d2020-10-29 21:46:35 -0600978 patch1.parse_subject('[1/2] Subject 1')
979 patch1.name = patch1.raw_subject
980 patch1.content = 'This is my patch content'
981 comment1a = {'content': 'Reviewed-by: %s\n' % self.joe}
982
983 patch1.comments = [comment1a]
984
Simon Glass232eefd2025-04-29 07:22:14 -0600985 patch2 = patchwork.Patch('2')
Simon Glass3db916d2020-10-29 21:46:35 -0600986 patch2.parse_subject('[2/2] Subject 2')
987 patch2.name = patch2.raw_subject
988 patch2.content = 'Some other patch content'
989 comment2a = {
990 'content': 'Reviewed-by: %s\nTested-by: %s\n' %
991 (self.mary, self.leb)}
992 comment2b = {'content': 'Reviewed-by: %s' % self.fred}
993 patch2.comments = [comment2a, comment2b]
994
995 # This test works by setting up commits and patch for use by the fake
996 # Rest API function _fake_patchwork2(). It calls various functions in
997 # the status module after setting up tags in the commits, checking that
998 # things behaves as expected
999 self.commits = [commit1, commit2]
1000 self.patches = [patch1, patch2]
1001 count = 2
Simon Glass3db916d2020-10-29 21:46:35 -06001002
1003 # Check that the tags are picked up on the first patch
Simon Glass29771962025-04-29 07:22:20 -06001004 new_rtags, _ = status.process_reviews(patch1.content, patch1.comments,
1005 commit1.rtags)
1006 self.assertEqual(new_rtags, {'Reviewed-by': {self.joe}})
Simon Glass3db916d2020-10-29 21:46:35 -06001007
1008 # Now the second patch
Simon Glass29771962025-04-29 07:22:20 -06001009 new_rtags, _ = status.process_reviews(patch2.content, patch2.comments,
1010 commit2.rtags)
1011 self.assertEqual(new_rtags, {
Simon Glass3db916d2020-10-29 21:46:35 -06001012 'Reviewed-by': {self.mary, self.fred},
1013 'Tested-by': {self.leb}})
1014
1015 # Now add some tags to the commit, which means they should not appear as
1016 # 'new' tags when scanning comments
Simon Glass3db916d2020-10-29 21:46:35 -06001017 commit1.rtags = {'Reviewed-by': {self.joe}}
Simon Glass29771962025-04-29 07:22:20 -06001018 new_rtags, _ = status.process_reviews(patch1.content, patch1.comments,
1019 commit1.rtags)
1020 self.assertEqual(new_rtags, {})
Simon Glass3db916d2020-10-29 21:46:35 -06001021
1022 # For the second commit, add Ed and Fred, so only Mary should be left
1023 commit2.rtags = {
1024 'Tested-by': {self.leb},
1025 'Reviewed-by': {self.fred}}
Simon Glass29771962025-04-29 07:22:20 -06001026 new_rtags, _ = status.process_reviews(patch2.content, patch2.comments,
1027 commit2.rtags)
1028 self.assertEqual(new_rtags, {'Reviewed-by': {self.mary}})
Simon Glass3db916d2020-10-29 21:46:35 -06001029
1030 # Check that the output patches expectations:
1031 # 1 Subject 1
1032 # Reviewed-by: Joe Bloggs <joe@napierwallies.co.nz>
1033 # 2 Subject 2
1034 # Tested-by: Lord Edmund Blackaddër <weasel@blackadder.org>
1035 # Reviewed-by: Fred Bloggs <f.bloggs@napier.net>
1036 # + Reviewed-by: Mary Bloggs <mary@napierwallies.co.nz>
1037 # 1 new response available in patchwork
1038
1039 series = Series()
1040 series.commits = [commit1, commit2]
Simon Glass02811582022-01-29 14:14:18 -07001041 terminal.set_print_test_mode()
Simon Glass25b91c12025-04-29 07:22:19 -06001042 pwork = patchwork.Patchwork.for_testing(self._fake_patchwork2)
Simon Glassc100b262025-04-29 07:22:16 -06001043 status.check_and_show_status(series, '1234', None, None, False, False,
Simon Glass25b91c12025-04-29 07:22:19 -06001044 pwork)
Simon Glassb3080ec2025-05-08 04:58:49 +02001045 itr = iter(terminal.get_print_test_lines())
Simon Glass3db916d2020-10-29 21:46:35 -06001046 col = terminal.Color()
Simon Glassd4d3fb42025-04-29 07:22:21 -06001047 self.assertEqual(terminal.PrintLine(' 1 Subject 1', col.YELLOW),
Simon Glassb3080ec2025-05-08 04:58:49 +02001048 next(itr))
Simon Glass3db916d2020-10-29 21:46:35 -06001049 self.assertEqual(
1050 terminal.PrintLine(' Reviewed-by: ', col.GREEN, newline=False,
1051 bright=False),
Simon Glassb3080ec2025-05-08 04:58:49 +02001052 next(itr))
Simon Glass3db916d2020-10-29 21:46:35 -06001053 self.assertEqual(terminal.PrintLine(self.joe, col.WHITE, bright=False),
Simon Glassb3080ec2025-05-08 04:58:49 +02001054 next(itr))
Simon Glass3db916d2020-10-29 21:46:35 -06001055
Simon Glassd4d3fb42025-04-29 07:22:21 -06001056 self.assertEqual(terminal.PrintLine(' 2 Subject 2', col.YELLOW),
Simon Glassb3080ec2025-05-08 04:58:49 +02001057 next(itr))
Simon Glass3db916d2020-10-29 21:46:35 -06001058 self.assertEqual(
Simon Glass2112d072020-10-29 21:46:38 -06001059 terminal.PrintLine(' Reviewed-by: ', col.GREEN, newline=False,
Simon Glass3db916d2020-10-29 21:46:35 -06001060 bright=False),
Simon Glassb3080ec2025-05-08 04:58:49 +02001061 next(itr))
1062 self.assertEqual(terminal.PrintLine(self.fred, col.WHITE,
1063 bright=False), next(itr))
Simon Glass3db916d2020-10-29 21:46:35 -06001064 self.assertEqual(
Simon Glass2112d072020-10-29 21:46:38 -06001065 terminal.PrintLine(' Tested-by: ', col.GREEN, newline=False,
Simon Glass3db916d2020-10-29 21:46:35 -06001066 bright=False),
Simon Glassb3080ec2025-05-08 04:58:49 +02001067 next(itr))
Simon Glass2112d072020-10-29 21:46:38 -06001068 self.assertEqual(terminal.PrintLine(self.leb, col.WHITE, bright=False),
Simon Glassb3080ec2025-05-08 04:58:49 +02001069 next(itr))
Simon Glass3db916d2020-10-29 21:46:35 -06001070 self.assertEqual(
1071 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
Simon Glassb3080ec2025-05-08 04:58:49 +02001072 next(itr))
Simon Glass3db916d2020-10-29 21:46:35 -06001073 self.assertEqual(terminal.PrintLine(self.mary, col.WHITE),
Simon Glassb3080ec2025-05-08 04:58:49 +02001074 next(itr))
Simon Glass3db916d2020-10-29 21:46:35 -06001075 self.assertEqual(terminal.PrintLine(
Simon Glassd0a0a582020-10-29 21:46:36 -06001076 '1 new response available in patchwork (use -d to write them to a new branch)',
Simon Glassb3080ec2025-05-08 04:58:49 +02001077 None), next(itr))
Simon Glassd0a0a582020-10-29 21:46:36 -06001078
Simon Glass25b91c12025-04-29 07:22:19 -06001079 def _fake_patchwork3(self, subpath):
Simon Glassd0a0a582020-10-29 21:46:36 -06001080 """Fake Patchwork server for the function below
1081
1082 This handles accessing series, patches and comments, providing the data
1083 in self.patches to the caller
Simon Glassf9b03cf2020-11-03 13:54:14 -07001084
1085 Args:
Simon Glassf9b03cf2020-11-03 13:54:14 -07001086 subpath (str): URL subpath to use
Simon Glassd0a0a582020-10-29 21:46:36 -06001087 """
1088 re_series = re.match(r'series/(\d*)/$', subpath)
1089 re_patch = re.match(r'patches/(\d*)/$', subpath)
1090 re_comments = re.match(r'patches/(\d*)/comments/$', subpath)
1091 if re_series:
1092 series_num = re_series.group(1)
1093 if series_num == '1234':
1094 return {'patches': self.patches}
1095 elif re_patch:
1096 patch_num = int(re_patch.group(1))
1097 patch = self.patches[patch_num - 1]
1098 return patch
1099 elif re_comments:
1100 patch_num = int(re_comments.group(1))
1101 patch = self.patches[patch_num - 1]
1102 return patch.comments
1103 raise ValueError('Fake Patchwork does not understand: %s' % subpath)
1104
Simon Glassd85bb8f2022-01-29 14:14:09 -07001105 def test_create_branch(self):
Simon Glassd0a0a582020-10-29 21:46:36 -06001106 """Test operation of create_branch()"""
1107 repo = self.make_git_tree()
1108 branch = 'first'
1109 dest_branch = 'first2'
1110 count = 2
1111 gitdir = os.path.join(self.gitdir, '.git')
1112
1113 # Set up the test git tree. We use branch 'first' which has two commits
1114 # in it
1115 series = patchstream.get_metadata_for_list(branch, gitdir, count)
1116 self.assertEqual(2, len(series.commits))
1117
Simon Glass232eefd2025-04-29 07:22:14 -06001118 patch1 = patchwork.Patch('1')
Simon Glassd0a0a582020-10-29 21:46:36 -06001119 patch1.parse_subject('[1/2] %s' % series.commits[0].subject)
1120 patch1.name = patch1.raw_subject
1121 patch1.content = 'This is my patch content'
1122 comment1a = {'content': 'Reviewed-by: %s\n' % self.joe}
1123
1124 patch1.comments = [comment1a]
1125
Simon Glass232eefd2025-04-29 07:22:14 -06001126 patch2 = patchwork.Patch('2')
Simon Glassd0a0a582020-10-29 21:46:36 -06001127 patch2.parse_subject('[2/2] %s' % series.commits[1].subject)
1128 patch2.name = patch2.raw_subject
1129 patch2.content = 'Some other patch content'
1130 comment2a = {
1131 'content': 'Reviewed-by: %s\nTested-by: %s\n' %
1132 (self.mary, self.leb)}
1133 comment2b = {
1134 'content': 'Reviewed-by: %s' % self.fred}
1135 patch2.comments = [comment2a, comment2b]
1136
1137 # This test works by setting up patches for use by the fake Rest API
1138 # function _fake_patchwork3(). The fake patch comments above should
1139 # result in new review tags that are collected and added to the commits
1140 # created in the destination branch.
1141 self.patches = [patch1, patch2]
1142 count = 2
1143
1144 # Expected output:
1145 # 1 i2c: I2C things
1146 # + Reviewed-by: Joe Bloggs <joe@napierwallies.co.nz>
1147 # 2 spi: SPI fixes
1148 # + Reviewed-by: Fred Bloggs <f.bloggs@napier.net>
1149 # + Reviewed-by: Mary Bloggs <mary@napierwallies.co.nz>
1150 # + Tested-by: Lord Edmund Blackaddër <weasel@blackadder.org>
1151 # 4 new responses available in patchwork
1152 # 4 responses added from patchwork into new branch 'first2'
1153 # <unittest.result.TestResult run=8 errors=0 failures=0>
1154
Simon Glass02811582022-01-29 14:14:18 -07001155 terminal.set_print_test_mode()
Simon Glass25b91c12025-04-29 07:22:19 -06001156 pwork = patchwork.Patchwork.for_testing(self._fake_patchwork3)
Simon Glassc100b262025-04-29 07:22:16 -06001157 status.check_and_show_status(series, '1234', branch, dest_branch,
Simon Glass25b91c12025-04-29 07:22:19 -06001158 False, False, pwork, repo)
Simon Glass02811582022-01-29 14:14:18 -07001159 lines = terminal.get_print_test_lines()
Simon Glassd0a0a582020-10-29 21:46:36 -06001160 self.assertEqual(12, len(lines))
1161 self.assertEqual(
1162 "4 responses added from patchwork into new branch 'first2'",
1163 lines[11].text)
1164
1165 # Check that the destination branch has the new tags
1166 new_series = patchstream.get_metadata_for_list(dest_branch, gitdir,
1167 count)
1168 self.assertEqual(
1169 {'Reviewed-by': {self.joe}},
1170 new_series.commits[0].rtags)
1171 self.assertEqual(
1172 {'Tested-by': {self.leb},
1173 'Reviewed-by': {self.fred, self.mary}},
1174 new_series.commits[1].rtags)
1175
1176 # Now check the actual test of the first commit message. We expect to
1177 # see the new tags immediately below the old ones.
1178 stdout = patchstream.get_list(dest_branch, count=count, git_dir=gitdir)
Simon Glassb3080ec2025-05-08 04:58:49 +02001179 itr = iter([line.strip() for line in stdout.splitlines()
1180 if '-by:' in line])
Simon Glassd0a0a582020-10-29 21:46:36 -06001181
1182 # First patch should have the review tag
Simon Glassb3080ec2025-05-08 04:58:49 +02001183 self.assertEqual('Reviewed-by: %s' % self.joe, next(itr))
Simon Glassd0a0a582020-10-29 21:46:36 -06001184
1185 # Second patch should have the sign-off then the tested-by and two
1186 # reviewed-by tags
Simon Glassb3080ec2025-05-08 04:58:49 +02001187 self.assertEqual('Signed-off-by: %s' % self.leb, next(itr))
1188 self.assertEqual('Reviewed-by: %s' % self.fred, next(itr))
1189 self.assertEqual('Reviewed-by: %s' % self.mary, next(itr))
1190 self.assertEqual('Tested-by: %s' % self.leb, next(itr))
Simon Glassda8a2922020-10-29 21:46:37 -06001191
Simon Glassd85bb8f2022-01-29 14:14:09 -07001192 def test_parse_snippets(self):
Simon Glassda8a2922020-10-29 21:46:37 -06001193 """Test parsing of review snippets"""
1194 text = '''Hi Fred,
1195
1196This is a comment from someone.
1197
1198Something else
1199
1200On some recent date, Fred wrote:
1201> This is why I wrote the patch
1202> so here it is
1203
1204Now a comment about the commit message
1205A little more to say
1206
1207Even more
1208
1209> diff --git a/file.c b/file.c
1210> Some more code
1211> Code line 2
1212> Code line 3
1213> Code line 4
1214> Code line 5
1215> Code line 6
1216> Code line 7
1217> Code line 8
1218> Code line 9
1219
1220And another comment
1221
Simon Glassd85bb8f2022-01-29 14:14:09 -07001222> @@ -153,8 +143,13 @@ def check_patch(fname, show_types=False):
Simon Glassda8a2922020-10-29 21:46:37 -06001223> further down on the file
1224> and more code
1225> +Addition here
1226> +Another addition here
1227> codey
1228> more codey
1229
1230and another thing in same file
1231
1232> @@ -253,8 +243,13 @@
1233> with no function context
1234
1235one more thing
1236
1237> diff --git a/tools/patman/main.py b/tools/patman/main.py
1238> +line of code
1239now a very long comment in a different file
1240line2
1241line3
1242line4
1243line5
1244line6
1245line7
1246line8
1247'''
1248 pstrm = PatchStream.process_text(text, True)
1249 self.assertEqual([], pstrm.commit.warn)
1250
1251 # We expect to the filename and up to 5 lines of code context before
1252 # each comment. The 'On xxx wrote:' bit should be removed.
1253 self.assertEqual(
1254 [['Hi Fred,',
1255 'This is a comment from someone.',
1256 'Something else'],
1257 ['> This is why I wrote the patch',
1258 '> so here it is',
1259 'Now a comment about the commit message',
1260 'A little more to say', 'Even more'],
1261 ['> File: file.c', '> Code line 5', '> Code line 6',
1262 '> Code line 7', '> Code line 8', '> Code line 9',
1263 'And another comment'],
1264 ['> File: file.c',
Simon Glassd85bb8f2022-01-29 14:14:09 -07001265 '> Line: 153 / 143: def check_patch(fname, show_types=False):',
Simon Glassda8a2922020-10-29 21:46:37 -06001266 '> and more code', '> +Addition here', '> +Another addition here',
1267 '> codey', '> more codey', 'and another thing in same file'],
1268 ['> File: file.c', '> Line: 253 / 243',
1269 '> with no function context', 'one more thing'],
1270 ['> File: tools/patman/main.py', '> +line of code',
1271 'now a very long comment in a different file',
1272 'line2', 'line3', 'line4', 'line5', 'line6', 'line7', 'line8']],
1273 pstrm.snippets)
Simon Glass2112d072020-10-29 21:46:38 -06001274
Simon Glassd85bb8f2022-01-29 14:14:09 -07001275 def test_review_snippets(self):
Simon Glass2112d072020-10-29 21:46:38 -06001276 """Test showing of review snippets"""
1277 def _to_submitter(who):
1278 m_who = re.match('(.*) <(.*)>', who)
1279 return {
1280 'name': m_who.group(1),
1281 'email': m_who.group(2)
1282 }
1283
1284 commit1 = Commit('abcd')
1285 commit1.subject = 'Subject 1'
1286 commit2 = Commit('ef12')
1287 commit2.subject = 'Subject 2'
1288
Simon Glass232eefd2025-04-29 07:22:14 -06001289 patch1 = patchwork.Patch('1')
Simon Glass2112d072020-10-29 21:46:38 -06001290 patch1.parse_subject('[1/2] Subject 1')
1291 patch1.name = patch1.raw_subject
1292 patch1.content = 'This is my patch content'
1293 comment1a = {'submitter': _to_submitter(self.joe),
1294 'content': '''Hi Fred,
1295
1296On some date Fred wrote:
1297
1298> diff --git a/file.c b/file.c
1299> Some code
1300> and more code
1301
1302Here is my comment above the above...
1303
1304
1305Reviewed-by: %s
1306''' % self.joe}
1307
1308 patch1.comments = [comment1a]
1309
Simon Glass232eefd2025-04-29 07:22:14 -06001310 patch2 = patchwork.Patch('2')
Simon Glass2112d072020-10-29 21:46:38 -06001311 patch2.parse_subject('[2/2] Subject 2')
1312 patch2.name = patch2.raw_subject
1313 patch2.content = 'Some other patch content'
1314 comment2a = {
1315 'content': 'Reviewed-by: %s\nTested-by: %s\n' %
1316 (self.mary, self.leb)}
1317 comment2b = {'submitter': _to_submitter(self.fred),
1318 'content': '''Hi Fred,
1319
1320On some date Fred wrote:
1321
1322> diff --git a/tools/patman/commit.py b/tools/patman/commit.py
1323> @@ -41,6 +41,9 @@ class Commit:
1324> self.rtags = collections.defaultdict(set)
1325> self.warn = []
1326>
1327> + def __str__(self):
1328> + return self.subject
1329> +
Simon Glassd85bb8f2022-01-29 14:14:09 -07001330> def add_change(self, version, info):
Simon Glass2112d072020-10-29 21:46:38 -06001331> """Add a new change line to the change list for a version.
1332>
1333A comment
1334
1335Reviewed-by: %s
1336''' % self.fred}
1337 patch2.comments = [comment2a, comment2b]
1338
1339 # This test works by setting up commits and patch for use by the fake
1340 # Rest API function _fake_patchwork2(). It calls various functions in
1341 # the status module after setting up tags in the commits, checking that
1342 # things behaves as expected
1343 self.commits = [commit1, commit2]
1344 self.patches = [patch1, patch2]
1345
1346 # Check that the output patches expectations:
1347 # 1 Subject 1
1348 # Reviewed-by: Joe Bloggs <joe@napierwallies.co.nz>
1349 # 2 Subject 2
1350 # Tested-by: Lord Edmund Blackaddër <weasel@blackadder.org>
1351 # Reviewed-by: Fred Bloggs <f.bloggs@napier.net>
1352 # + Reviewed-by: Mary Bloggs <mary@napierwallies.co.nz>
1353 # 1 new response available in patchwork
1354
1355 series = Series()
1356 series.commits = [commit1, commit2]
Simon Glass02811582022-01-29 14:14:18 -07001357 terminal.set_print_test_mode()
Simon Glass25b91c12025-04-29 07:22:19 -06001358 pwork = patchwork.Patchwork.for_testing(self._fake_patchwork2)
Simon Glassc100b262025-04-29 07:22:16 -06001359 status.check_and_show_status(series, '1234', None, None, False, True,
Simon Glass25b91c12025-04-29 07:22:19 -06001360 pwork)
Simon Glassb3080ec2025-05-08 04:58:49 +02001361 itr = iter(terminal.get_print_test_lines())
Simon Glass2112d072020-10-29 21:46:38 -06001362 col = terminal.Color()
Simon Glassd4d3fb42025-04-29 07:22:21 -06001363 self.assertEqual(terminal.PrintLine(' 1 Subject 1', col.YELLOW),
Simon Glassb3080ec2025-05-08 04:58:49 +02001364 next(itr))
Simon Glass2112d072020-10-29 21:46:38 -06001365 self.assertEqual(
1366 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
Simon Glassb3080ec2025-05-08 04:58:49 +02001367 next(itr))
1368 self.assertEqual(terminal.PrintLine(self.joe, col.WHITE), next(itr))
Simon Glass2112d072020-10-29 21:46:38 -06001369
1370 self.assertEqual(terminal.PrintLine('Review: %s' % self.joe, col.RED),
Simon Glassb3080ec2025-05-08 04:58:49 +02001371 next(itr))
1372 self.assertEqual(terminal.PrintLine(' Hi Fred,', None), next(itr))
1373 self.assertEqual(terminal.PrintLine('', None), next(itr))
Simon Glass2112d072020-10-29 21:46:38 -06001374 self.assertEqual(terminal.PrintLine(' > File: file.c', col.MAGENTA),
Simon Glassb3080ec2025-05-08 04:58:49 +02001375 next(itr))
Simon Glass2112d072020-10-29 21:46:38 -06001376 self.assertEqual(terminal.PrintLine(' > Some code', col.MAGENTA),
Simon Glassb3080ec2025-05-08 04:58:49 +02001377 next(itr))
1378 self.assertEqual(terminal.PrintLine(' > and more code',
1379 col.MAGENTA),
1380 next(itr))
Simon Glass2112d072020-10-29 21:46:38 -06001381 self.assertEqual(terminal.PrintLine(
Simon Glassb3080ec2025-05-08 04:58:49 +02001382 ' Here is my comment above the above...', None), next(itr))
1383 self.assertEqual(terminal.PrintLine('', None), next(itr))
Simon Glass2112d072020-10-29 21:46:38 -06001384
Simon Glassd4d3fb42025-04-29 07:22:21 -06001385 self.assertEqual(terminal.PrintLine(' 2 Subject 2', col.YELLOW),
Simon Glassb3080ec2025-05-08 04:58:49 +02001386 next(itr))
Simon Glass2112d072020-10-29 21:46:38 -06001387 self.assertEqual(
1388 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
Simon Glassb3080ec2025-05-08 04:58:49 +02001389 next(itr))
Simon Glass2112d072020-10-29 21:46:38 -06001390 self.assertEqual(terminal.PrintLine(self.fred, col.WHITE),
Simon Glassb3080ec2025-05-08 04:58:49 +02001391 next(itr))
Simon Glass2112d072020-10-29 21:46:38 -06001392 self.assertEqual(
1393 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
Simon Glassb3080ec2025-05-08 04:58:49 +02001394 next(itr))
Simon Glass2112d072020-10-29 21:46:38 -06001395 self.assertEqual(terminal.PrintLine(self.mary, col.WHITE),
Simon Glassb3080ec2025-05-08 04:58:49 +02001396 next(itr))
Simon Glass2112d072020-10-29 21:46:38 -06001397 self.assertEqual(
1398 terminal.PrintLine(' + Tested-by: ', col.GREEN, newline=False),
Simon Glassb3080ec2025-05-08 04:58:49 +02001399 next(itr))
Simon Glass2112d072020-10-29 21:46:38 -06001400 self.assertEqual(terminal.PrintLine(self.leb, col.WHITE),
Simon Glassb3080ec2025-05-08 04:58:49 +02001401 next(itr))
Simon Glass2112d072020-10-29 21:46:38 -06001402
1403 self.assertEqual(terminal.PrintLine('Review: %s' % self.fred, col.RED),
Simon Glassb3080ec2025-05-08 04:58:49 +02001404 next(itr))
1405 self.assertEqual(terminal.PrintLine(' Hi Fred,', None), next(itr))
1406 self.assertEqual(terminal.PrintLine('', None), next(itr))
Simon Glass2112d072020-10-29 21:46:38 -06001407 self.assertEqual(terminal.PrintLine(
Simon Glassb3080ec2025-05-08 04:58:49 +02001408 ' > File: tools/patman/commit.py', col.MAGENTA), next(itr))
Simon Glass2112d072020-10-29 21:46:38 -06001409 self.assertEqual(terminal.PrintLine(
Simon Glassb3080ec2025-05-08 04:58:49 +02001410 ' > Line: 41 / 41: class Commit:', col.MAGENTA), next(itr))
Simon Glass2112d072020-10-29 21:46:38 -06001411 self.assertEqual(terminal.PrintLine(
Simon Glassb3080ec2025-05-08 04:58:49 +02001412 ' > + return self.subject', col.MAGENTA), next(itr))
Simon Glass2112d072020-10-29 21:46:38 -06001413 self.assertEqual(terminal.PrintLine(
Simon Glassb3080ec2025-05-08 04:58:49 +02001414 ' > +', col.MAGENTA), next(itr))
Simon Glass2112d072020-10-29 21:46:38 -06001415 self.assertEqual(
Simon Glassb3080ec2025-05-08 04:58:49 +02001416 terminal.PrintLine(
1417 ' > def add_change(self, version, info):',
1418 col.MAGENTA),
1419 next(itr))
Simon Glass2112d072020-10-29 21:46:38 -06001420 self.assertEqual(terminal.PrintLine(
1421 ' > """Add a new change line to the change list for a version.',
Simon Glassb3080ec2025-05-08 04:58:49 +02001422 col.MAGENTA), next(itr))
Simon Glass2112d072020-10-29 21:46:38 -06001423 self.assertEqual(terminal.PrintLine(
Simon Glassb3080ec2025-05-08 04:58:49 +02001424 ' >', col.MAGENTA), next(itr))
Simon Glass2112d072020-10-29 21:46:38 -06001425 self.assertEqual(terminal.PrintLine(
Simon Glassb3080ec2025-05-08 04:58:49 +02001426 ' A comment', None), next(itr))
1427 self.assertEqual(terminal.PrintLine('', None), next(itr))
Simon Glass2112d072020-10-29 21:46:38 -06001428
1429 self.assertEqual(terminal.PrintLine(
1430 '4 new responses available in patchwork (use -d to write them to a new branch)',
Simon Glassb3080ec2025-05-08 04:58:49 +02001431 None), next(itr))
Simon Glass6a222e62021-08-01 16:02:39 -06001432
Simon Glassd85bb8f2022-01-29 14:14:09 -07001433 def test_insert_tags(self):
Simon Glass6a222e62021-08-01 16:02:39 -06001434 """Test inserting of review tags"""
1435 msg = '''first line
1436second line.'''
1437 tags = [
1438 'Reviewed-by: Bin Meng <bmeng.cn@gmail.com>',
1439 'Tested-by: Bin Meng <bmeng.cn@gmail.com>'
1440 ]
1441 signoff = 'Signed-off-by: Simon Glass <sjg@chromium.com>'
1442 tag_str = '\n'.join(tags)
1443
1444 new_msg = patchstream.insert_tags(msg, tags)
1445 self.assertEqual(msg + '\n\n' + tag_str, new_msg)
1446
1447 new_msg = patchstream.insert_tags(msg + '\n', tags)
1448 self.assertEqual(msg + '\n\n' + tag_str, new_msg)
1449
1450 msg += '\n\n' + signoff
1451 new_msg = patchstream.insert_tags(msg, tags)
1452 self.assertEqual(msg + '\n' + tag_str, new_msg)