blob: b3145612f9fdecc461a0231c6e67a396c6d018ee [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
Maxim Cournoyer3ef23e92022-12-20 00:28:46 -05009import contextlib
Simon Glassdf1bc5c2017-05-29 15:31:31 -060010import os
Maxim Cournoyer0331edb2022-12-19 17:32:39 -050011import pathlib
Simon Glassdf1bc5c2017-05-29 15:31:31 -060012import re
13import shutil
14import sys
15import tempfile
16import unittest
17
Simon Glass3db916d2020-10-29 21:46:35 -060018
19from patman.commit import Commit
Simon Glass54f1c5b2020-07-05 21:41:50 -060020from patman import control
Simon Glassa997ea52020-04-17 18:09:04 -060021from patman import patchstream
Simon Glassa7fadab2020-10-29 21:46:26 -060022from patman.patchstream import PatchStream
Simon Glassc0257982025-04-29 07:22:11 -060023from patman import send
Simon Glass3db916d2020-10-29 21:46:35 -060024from patman.series import Series
Simon Glassa997ea52020-04-17 18:09:04 -060025from patman import settings
Simon Glassba1b3b92025-02-09 14:26:00 -070026from u_boot_pylib import gitutil
Simon Glass131444f2023-02-23 18:18:04 -070027from u_boot_pylib import terminal
28from u_boot_pylib import tools
Simon Glassdf1bc5c2017-05-29 15:31:31 -060029
Tom Rini488ea972021-02-26 07:52:31 -050030import pygit2
31from patman import status
Simon Glassdf1bc5c2017-05-29 15:31:31 -060032
Maxim Cournoyer3ef23e92022-12-20 00:28:46 -050033PATMAN_DIR = pathlib.Path(__file__).parent
34TEST_DATA_DIR = PATMAN_DIR / 'test/'
Maxim Cournoyer0331edb2022-12-19 17:32:39 -050035
Maxim Cournoyer0331edb2022-12-19 17:32:39 -050036
Maxim Cournoyer3ef23e92022-12-20 00:28:46 -050037@contextlib.contextmanager
38def directory_excursion(directory):
39 """Change directory to `directory` for a limited to the context block."""
40 current = os.getcwd()
41 try:
42 os.chdir(directory)
43 yield
44 finally:
45 os.chdir(current)
46
Maxim Cournoyer0331edb2022-12-19 17:32:39 -050047
Simon Glassdf1bc5c2017-05-29 15:31:31 -060048class TestFunctional(unittest.TestCase):
Simon Glasseb209e52020-10-29 21:46:15 -060049 """Functional tests for checking that patman behaves correctly"""
Simon Glass06202d62020-10-29 21:46:27 -060050 leb = (b'Lord Edmund Blackadd\xc3\xabr <weasel@blackadder.org>'.
51 decode('utf-8'))
Simon Glass3b762cc2020-10-29 21:46:28 -060052 fred = 'Fred Bloggs <f.bloggs@napier.net>'
53 joe = 'Joe Bloggs <joe@napierwallies.co.nz>'
54 mary = 'Mary Bloggs <mary@napierwallies.co.nz>'
Simon Glass3db916d2020-10-29 21:46:35 -060055 commits = None
56 patches = None
Simon Glassed831d12025-04-29 07:22:10 -060057 verbosity = False
58 preserve_outdirs = False
59
60 @classmethod
61 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
62 toolpath=None, verbosity=None, no_capture=False):
63 """Accept arguments controlling test execution
64
65 Args:
66 preserve_indir: not used
67 preserve_outdir: Preserve the output directories used by tests.
68 Each test has its own, so this is normally only useful when
69 running a single test.
70 toolpath: not used
71 """
72 cls.preserve_outdirs = preserve_outdirs
73 cls.toolpath = toolpath
74 cls.verbosity = verbosity
75 cls.no_capture = no_capture
Simon Glass06202d62020-10-29 21:46:27 -060076
Simon Glassdf1bc5c2017-05-29 15:31:31 -060077 def setUp(self):
78 self.tmpdir = tempfile.mkdtemp(prefix='patman.')
Simon Glass54f1c5b2020-07-05 21:41:50 -060079 self.gitdir = os.path.join(self.tmpdir, 'git')
80 self.repo = None
Simon Glassdf1bc5c2017-05-29 15:31:31 -060081
82 def tearDown(self):
Simon Glassed831d12025-04-29 07:22:10 -060083 if self.preserve_outdirs:
84 print(f'Output dir: {self.tmpdir}')
85 else:
86 shutil.rmtree(self.tmpdir)
Simon Glass02811582022-01-29 14:14:18 -070087 terminal.set_print_test_mode(False)
Simon Glassdf1bc5c2017-05-29 15:31:31 -060088
89 @staticmethod
Simon Glasseb209e52020-10-29 21:46:15 -060090 def _get_path(fname):
91 """Get the path to a test file
92
93 Args:
94 fname (str): Filename to obtain
95
96 Returns:
97 str: Full path to file in the test directory
98 """
Maxim Cournoyer0331edb2022-12-19 17:32:39 -050099 return TEST_DATA_DIR / fname
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600100
101 @classmethod
Simon Glasseb209e52020-10-29 21:46:15 -0600102 def _get_text(cls, fname):
103 """Read a file as text
104
105 Args:
106 fname (str): Filename to read
107
108 Returns:
109 str: Contents of file
110 """
111 return open(cls._get_path(fname), encoding='utf-8').read()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600112
113 @classmethod
Simon Glasseb209e52020-10-29 21:46:15 -0600114 def _get_patch_name(cls, subject):
115 """Get the filename of a patch given its subject
116
117 Args:
118 subject (str): Patch subject
119
120 Returns:
121 str: Filename for that patch
122 """
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600123 fname = re.sub('[ :]', '-', subject)
124 return fname.replace('--', '-')
125
Simon Glasseb209e52020-10-29 21:46:15 -0600126 def _create_patches_for_test(self, series):
127 """Create patch files for use by tests
128
129 This copies patch files from the test directory as needed by the series
130
131 Args:
132 series (Series): Series containing commits to convert
133
134 Returns:
135 tuple:
136 str: Cover-letter filename, or None if none
137 fname_list: list of str, each a patch filename
138 """
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600139 cover_fname = None
140 fname_list = []
141 for i, commit in enumerate(series.commits):
Simon Glasseb209e52020-10-29 21:46:15 -0600142 clean_subject = self._get_patch_name(commit.subject)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600143 src_fname = '%04d-%s.patch' % (i + 1, clean_subject[:52])
144 fname = os.path.join(self.tmpdir, src_fname)
Simon Glasseb209e52020-10-29 21:46:15 -0600145 shutil.copy(self._get_path(src_fname), fname)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600146 fname_list.append(fname)
147 if series.get('cover'):
148 src_fname = '0000-cover-letter.patch'
149 cover_fname = os.path.join(self.tmpdir, src_fname)
150 fname = os.path.join(self.tmpdir, src_fname)
Simon Glasseb209e52020-10-29 21:46:15 -0600151 shutil.copy(self._get_path(src_fname), fname)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600152
153 return cover_fname, fname_list
154
Simon Glassd85bb8f2022-01-29 14:14:09 -0700155 def test_basic(self):
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600156 """Tests the basic flow of patman
157
158 This creates a series from some hard-coded patches build from a simple
159 tree with the following metadata in the top commit:
160
161 Series-to: u-boot
162 Series-prefix: RFC
Sean Andersondc1cd132021-10-22 19:07:04 -0400163 Series-postfix: some-branch
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600164 Series-cc: Stefan Brüns <stefan.bruens@rwth-aachen.de>
165 Cover-letter-cc: Lord Mëlchett <clergy@palace.gov>
Sean Andersoncf13b862020-05-04 16:28:36 -0400166 Series-version: 3
167 Patch-cc: fred
168 Series-process-log: sort, uniq
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600169 Series-changes: 4
170 - Some changes
Sean Andersoncf13b862020-05-04 16:28:36 -0400171 - Multi
172 line
173 change
174
175 Commit-changes: 2
176 - Changes only for this commit
177
Simon Glassf1aab6f2025-04-29 07:22:07 -0600178 Cover-changes: 4
Sean Andersoncf13b862020-05-04 16:28:36 -0400179 - Some notes for the cover letter
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600180
181 Cover-letter:
182 test: A test patch series
183 This is a test of how the cover
Sean Andersoncf13b862020-05-04 16:28:36 -0400184 letter
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600185 works
186 END
187
188 and this in the first commit:
189
Sean Andersoncf13b862020-05-04 16:28:36 -0400190 Commit-changes: 2
191 - second revision change
192
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600193 Series-notes:
194 some notes
195 about some things
196 from the first commit
197 END
198
199 Commit-notes:
200 Some notes about
201 the first commit
202 END
203
204 with the following commands:
205
206 git log -n2 --reverse >/path/to/tools/patman/test/test01.txt
207 git format-patch --subject-prefix RFC --cover-letter HEAD~2
208 mv 00* /path/to/tools/patman/test
209
210 It checks these aspects:
211 - git log can be processed by patchstream
212 - emailing patches uses the correct command
213 - CC file has information on each commit
214 - cover letter has the expected text and subject
215 - each patch has the correct subject
216 - dry-run information prints out correctly
217 - unicode is handled correctly
Sean Andersondc1cd132021-10-22 19:07:04 -0400218 - Series-to, Series-cc, Series-prefix, Series-postfix, Cover-letter
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600219 - Cover-letter-cc, Series-version, Series-changes, Series-notes
220 - Commit-notes
221 """
222 process_tags = True
Simon Glass1f975b92021-01-23 08:56:15 -0700223 ignore_bad_tags = False
Simon Glass4f817892019-05-14 15:53:53 -0600224 stefan = b'Stefan Br\xc3\xbcns <stefan.bruens@rwth-aachen.de>'.decode('utf-8')
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600225 rick = 'Richard III <richard@palace.gov>'
Simon Glass4f817892019-05-14 15:53:53 -0600226 mel = b'Lord M\xc3\xablchett <clergy@palace.gov>'.decode('utf-8')
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600227 add_maintainers = [stefan, rick]
228 dry_run = True
229 in_reply_to = mel
230 count = 2
231 settings.alias = {
Simon Glass95745aa2020-10-29 21:46:13 -0600232 'fdt': ['simon'],
233 'u-boot': ['u-boot@lists.denx.de'],
Simon Glass06202d62020-10-29 21:46:27 -0600234 'simon': [self.leb],
Simon Glass3b762cc2020-10-29 21:46:28 -0600235 'fred': [self.fred],
Sean Anderson25978092024-04-18 22:36:31 -0400236 'joe': [self.joe],
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600237 }
238
Simon Glasseb209e52020-10-29 21:46:15 -0600239 text = self._get_text('test01.txt')
Simon Glass93f61c02020-10-29 21:46:19 -0600240 series = patchstream.get_metadata_for_test(text)
Simon Glass414f1e02025-02-27 12:27:30 -0700241 series.base_commit = Commit('1a44532')
242 series.branch = 'mybranch'
Simon Glasseb209e52020-10-29 21:46:15 -0600243 cover_fname, args = self._create_patches_for_test(series)
Maxim Cournoyer3ef23e92022-12-20 00:28:46 -0500244 get_maintainer_script = str(pathlib.Path(__file__).parent.parent.parent
245 / 'get_maintainer.pl') + ' --norolestats'
Simon Glass14d64e32025-04-29 07:21:59 -0600246 with terminal.capture() as out:
Simon Glass93f61c02020-10-29 21:46:19 -0600247 patchstream.fix_patches(series, args)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600248 if cover_fname and series.get('cover'):
Simon Glass93f61c02020-10-29 21:46:19 -0600249 patchstream.insert_cover_letter(cover_fname, series, count)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600250 series.DoChecks()
251 cc_file = series.MakeCcFile(process_tags, cover_fname,
Chris Packhamb84fb482018-06-07 20:45:06 +1200252 not ignore_bad_tags, add_maintainers,
Maxim Cournoyer3ef23e92022-12-20 00:28:46 -0500253 None, get_maintainer_script)
Simon Glass761648b2022-01-29 14:14:11 -0700254 cmd = gitutil.email_patches(
Simon Glass95745aa2020-10-29 21:46:13 -0600255 series, cover_fname, args, dry_run, not ignore_bad_tags,
256 cc_file, in_reply_to=in_reply_to, thread=None)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600257 series.ShowActions(args, cmd, process_tags)
Simon Glassf544a2d2019-10-31 07:42:51 -0600258 cc_lines = open(cc_file, encoding='utf-8').read().splitlines()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600259 os.remove(cc_file)
260
Simon Glass42e3d392020-10-29 21:46:29 -0600261 lines = iter(out[0].getvalue().splitlines())
262 self.assertEqual('Cleaned %s patches' % len(series.commits),
263 next(lines))
264 self.assertEqual('Change log missing for v2', next(lines))
265 self.assertEqual('Change log missing for v3', next(lines))
266 self.assertEqual('Change log for unknown version v4', next(lines))
267 self.assertEqual("Alias 'pci' not found", next(lines))
Simon Glass620639c2023-03-08 10:52:54 -0800268 while next(lines) != 'Cc processing complete':
269 pass
Simon Glass42e3d392020-10-29 21:46:29 -0600270 self.assertIn('Dry run', next(lines))
271 self.assertEqual('', next(lines))
272 self.assertIn('Send a total of %d patches' % count, next(lines))
273 prev = next(lines)
274 for i, commit in enumerate(series.commits):
275 self.assertEqual(' %s' % args[i], prev)
276 while True:
277 prev = next(lines)
278 if 'Cc:' not in prev:
279 break
280 self.assertEqual('To: u-boot@lists.denx.de', prev)
Simon Glass9dfb3112020-11-08 20:36:18 -0700281 self.assertEqual('Cc: %s' % stefan, next(lines))
Simon Glass42e3d392020-10-29 21:46:29 -0600282 self.assertEqual('Version: 3', next(lines))
283 self.assertEqual('Prefix:\t RFC', next(lines))
Sean Andersondc1cd132021-10-22 19:07:04 -0400284 self.assertEqual('Postfix:\t some-branch', next(lines))
Simon Glass42e3d392020-10-29 21:46:29 -0600285 self.assertEqual('Cover: 4 lines', next(lines))
286 self.assertEqual(' Cc: %s' % self.fred, next(lines))
Sean Anderson25978092024-04-18 22:36:31 -0400287 self.assertEqual(' Cc: %s' % self.joe, next(lines))
Simon Glass9dfb3112020-11-08 20:36:18 -0700288 self.assertEqual(' Cc: %s' % self.leb,
Simon Glass42e3d392020-10-29 21:46:29 -0600289 next(lines))
Simon Glass9dfb3112020-11-08 20:36:18 -0700290 self.assertEqual(' Cc: %s' % mel, next(lines))
Simon Glass42e3d392020-10-29 21:46:29 -0600291 self.assertEqual(' Cc: %s' % rick, next(lines))
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600292 expected = ('Git command: git send-email --annotate '
293 '--in-reply-to="%s" --to "u-boot@lists.denx.de" '
Simon Glass1ee91c12020-11-03 13:54:10 -0700294 '--cc "%s" --cc-cmd "%s send --cc-cmd %s" %s %s'
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600295 % (in_reply_to, stefan, sys.argv[0], cc_file, cover_fname,
Simon Glass4f817892019-05-14 15:53:53 -0600296 ' '.join(args)))
Simon Glass9dfb3112020-11-08 20:36:18 -0700297 self.assertEqual(expected, next(lines))
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600298
Simon Glass9dfb3112020-11-08 20:36:18 -0700299 self.assertEqual(('%s %s\0%s' % (args[0], rick, stefan)), cc_lines[0])
Simon Glass95745aa2020-10-29 21:46:13 -0600300 self.assertEqual(
Sean Anderson25978092024-04-18 22:36:31 -0400301 '%s %s\0%s\0%s\0%s\0%s' % (args[1], self.fred, self.joe, self.leb,
302 rick, stefan),
Simon Glass9dfb3112020-11-08 20:36:18 -0700303 cc_lines[1])
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600304
305 expected = '''
306This is a test of how the cover
Sean Andersoncf13b862020-05-04 16:28:36 -0400307letter
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600308works
309
310some notes
311about some things
312from the first commit
313
314Changes in v4:
Sean Andersoncf13b862020-05-04 16:28:36 -0400315- Multi
316 line
317 change
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600318- Some changes
Sean Andersoncf13b862020-05-04 16:28:36 -0400319- Some notes for the cover letter
Sean Andersone45678c2024-04-18 22:36:32 -0400320- fdt: Correct cast for sandbox in fdtdec_setup_mem_size_base()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600321
322Simon Glass (2):
323 pci: Correct cast for sandbox
Siva Durga Prasad Paladugub3d55ea2018-07-16 15:56:11 +0530324 fdt: Correct cast for sandbox in fdtdec_setup_mem_size_base()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600325
326 cmd/pci.c | 3 ++-
327 fs/fat/fat.c | 1 +
328 lib/efi_loader/efi_memory.c | 1 +
329 lib/fdtdec.c | 3 ++-
330 4 files changed, 6 insertions(+), 2 deletions(-)
331
332--\x20
3332.7.4
334
Simon Glass414f1e02025-02-27 12:27:30 -0700335base-commit: 1a44532
336branch: mybranch
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600337'''
Simon Glassf544a2d2019-10-31 07:42:51 -0600338 lines = open(cover_fname, encoding='utf-8').read().splitlines()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600339 self.assertEqual(
Sean Andersondc1cd132021-10-22 19:07:04 -0400340 'Subject: [RFC PATCH some-branch v3 0/2] test: A test patch series',
Simon Glass95745aa2020-10-29 21:46:13 -0600341 lines[3])
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600342 self.assertEqual(expected.splitlines(), lines[7:])
343
344 for i, fname in enumerate(args):
Simon Glassf544a2d2019-10-31 07:42:51 -0600345 lines = open(fname, encoding='utf-8').read().splitlines()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600346 subject = [line for line in lines if line.startswith('Subject')]
347 self.assertEqual('Subject: [RFC %d/%d]' % (i + 1, count),
348 subject[0][:18])
Sean Andersoncf13b862020-05-04 16:28:36 -0400349
350 # Check that we got our commit notes
351 start = 0
352 expected = ''
353
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600354 if i == 0:
Sean Andersoncf13b862020-05-04 16:28:36 -0400355 start = 17
356 expected = '''---
357Some notes about
358the first commit
359
360(no changes since v2)
361
362Changes in v2:
363- second revision change'''
364 elif i == 1:
365 start = 17
366 expected = '''---
367
368Changes in v4:
369- Multi
370 line
371 change
Sean Andersone45678c2024-04-18 22:36:32 -0400372- New
Sean Andersoncf13b862020-05-04 16:28:36 -0400373- Some changes
374
375Changes in v2:
376- Changes only for this commit'''
377
378 if expected:
379 expected = expected.splitlines()
380 self.assertEqual(expected, lines[start:(start+len(expected))])
Simon Glass54f1c5b2020-07-05 21:41:50 -0600381
Simon Glassda1a6ec2025-03-28 07:02:20 -0600382 def test_base_commit(self):
383 """Test adding a base commit with no cover letter"""
384 orig_text = self._get_text('test01.txt')
385 pos = orig_text.index('commit 5ab48490f03051875ab13d288a4bf32b507d76fd')
386 text = orig_text[:pos]
387 series = patchstream.get_metadata_for_test(text)
388 series.base_commit = Commit('1a44532')
389 series.branch = 'mybranch'
390 cover_fname, args = self._create_patches_for_test(series)
391 self.assertFalse(cover_fname)
Simon Glass14d64e32025-04-29 07:21:59 -0600392 with terminal.capture() as out:
Simon Glassda1a6ec2025-03-28 07:02:20 -0600393 patchstream.fix_patches(series, args, insert_base_commit=True)
394 self.assertEqual('Cleaned 1 patch\n', out[0].getvalue())
395 lines = tools.read_file(args[0], binary=False).splitlines()
396 pos = lines.index('-- ')
397
398 # We expect these lines at the end:
399 # -- (with trailing space)
400 # 2.7.4
401 # (empty)
402 # base-commit: xxx
403 # branch: xxx
404 self.assertEqual('base-commit: 1a44532', lines[pos + 3])
405 self.assertEqual('branch: mybranch', lines[pos + 4])
406
Simon Glass54f1c5b2020-07-05 21:41:50 -0600407 def make_commit_with_file(self, subject, body, fname, text):
408 """Create a file and add it to the git repo with a new commit
409
410 Args:
411 subject (str): Subject for the commit
412 body (str): Body text of the commit
413 fname (str): Filename of file to create
414 text (str): Text to put into the file
415 """
416 path = os.path.join(self.gitdir, fname)
Simon Glass80025522022-01-29 14:14:04 -0700417 tools.write_file(path, text, binary=False)
Simon Glass54f1c5b2020-07-05 21:41:50 -0600418 index = self.repo.index
419 index.add(fname)
Simon Glass547cba62022-02-11 13:23:18 -0700420 # pylint doesn't seem to find this
421 # pylint: disable=E1101
Simon Glass95745aa2020-10-29 21:46:13 -0600422 author = pygit2.Signature('Test user', 'test@email.com')
Simon Glass54f1c5b2020-07-05 21:41:50 -0600423 committer = author
424 tree = index.write_tree()
425 message = subject + '\n' + body
426 self.repo.create_commit('HEAD', author, committer, message, tree,
427 [self.repo.head.target])
428
429 def make_git_tree(self):
430 """Make a simple git tree suitable for testing
431
432 It has three branches:
433 'base' has two commits: PCI, main
434 'first' has base as upstream and two more commits: I2C, SPI
435 'second' has base as upstream and three more: video, serial, bootm
436
437 Returns:
Simon Glasseb209e52020-10-29 21:46:15 -0600438 pygit2.Repository: repository
Simon Glass54f1c5b2020-07-05 21:41:50 -0600439 """
440 repo = pygit2.init_repository(self.gitdir)
441 self.repo = repo
442 new_tree = repo.TreeBuilder().write()
443
Simon Glass547cba62022-02-11 13:23:18 -0700444 # pylint doesn't seem to find this
445 # pylint: disable=E1101
Simon Glass54f1c5b2020-07-05 21:41:50 -0600446 author = pygit2.Signature('Test user', 'test@email.com')
447 committer = author
Simon Glasseb209e52020-10-29 21:46:15 -0600448 _ = repo.create_commit('HEAD', author, committer, 'Created master',
449 new_tree, [])
Simon Glass54f1c5b2020-07-05 21:41:50 -0600450
451 self.make_commit_with_file('Initial commit', '''
452Add a README
453
454''', 'README', '''This is the README file
455describing this project
456in very little detail''')
457
458 self.make_commit_with_file('pci: PCI implementation', '''
459Here is a basic PCI implementation
460
461''', 'pci.c', '''This is a file
462it has some contents
463and some more things''')
464 self.make_commit_with_file('main: Main program', '''
465Hello here is the second commit.
466''', 'main.c', '''This is the main file
467there is very little here
468but we can always add more later
469if we want to
470
471Series-to: u-boot
472Series-cc: Barry Crump <bcrump@whataroa.nz>
473''')
474 base_target = repo.revparse_single('HEAD')
475 self.make_commit_with_file('i2c: I2C things', '''
476This has some stuff to do with I2C
477''', 'i2c.c', '''And this is the file contents
478with some I2C-related things in it''')
479 self.make_commit_with_file('spi: SPI fixes', '''
480SPI needs some fixes
481and here they are
Simon Glassd0a0a582020-10-29 21:46:36 -0600482
483Signed-off-by: %s
484
485Series-to: u-boot
486Commit-notes:
487title of the series
488This is the cover letter for the series
489with various details
490END
491''' % self.leb, 'spi.c', '''Some fixes for SPI in this
Simon Glass54f1c5b2020-07-05 21:41:50 -0600492file to make SPI work
493better than before''')
494 first_target = repo.revparse_single('HEAD')
495
496 target = repo.revparse_single('HEAD~2')
Simon Glass547cba62022-02-11 13:23:18 -0700497 # pylint doesn't seem to find this
498 # pylint: disable=E1101
Simon Glass54f1c5b2020-07-05 21:41:50 -0600499 repo.reset(target.oid, pygit2.GIT_CHECKOUT_FORCE)
500 self.make_commit_with_file('video: Some video improvements', '''
501Fix up the video so that
502it looks more purple. Purple is
503a very nice colour.
504''', 'video.c', '''More purple here
505Purple and purple
506Even more purple
507Could not be any more purple''')
508 self.make_commit_with_file('serial: Add a serial driver', '''
509Here is the serial driver
510for my chip.
511
512Cover-letter:
513Series for my board
514This series implements support
515for my glorious board.
516END
Simon Glassa80986c2020-10-29 21:46:16 -0600517Series-links: 183237
Simon Glass54f1c5b2020-07-05 21:41:50 -0600518''', 'serial.c', '''The code for the
519serial driver is here''')
520 self.make_commit_with_file('bootm: Make it boot', '''
521This makes my board boot
522with a fix to the bootm
523command
524''', 'bootm.c', '''Fix up the bootm
525command to make the code as
526complicated as possible''')
527 second_target = repo.revparse_single('HEAD')
528
529 repo.branches.local.create('first', first_target)
530 repo.config.set_multivar('branch.first.remote', '', '.')
531 repo.config.set_multivar('branch.first.merge', '', 'refs/heads/base')
532
533 repo.branches.local.create('second', second_target)
534 repo.config.set_multivar('branch.second.remote', '', '.')
535 repo.config.set_multivar('branch.second.merge', '', 'refs/heads/base')
536
537 repo.branches.local.create('base', base_target)
538 return repo
539
Simon Glassd85bb8f2022-01-29 14:14:09 -0700540 def test_branch(self):
Simon Glass54f1c5b2020-07-05 21:41:50 -0600541 """Test creating patches from a branch"""
542 repo = self.make_git_tree()
543 target = repo.lookup_reference('refs/heads/first')
Simon Glass547cba62022-02-11 13:23:18 -0700544 # pylint doesn't seem to find this
545 # pylint: disable=E1101
Simon Glass54f1c5b2020-07-05 21:41:50 -0600546 self.repo.checkout(target, strategy=pygit2.GIT_CHECKOUT_FORCE)
547 control.setup()
Heinrich Schuchardtd01d6672023-04-20 20:07:29 +0200548 orig_dir = os.getcwd()
Simon Glass54f1c5b2020-07-05 21:41:50 -0600549 try:
Simon Glass54f1c5b2020-07-05 21:41:50 -0600550 os.chdir(self.gitdir)
551
552 # Check that it can detect the current branch
Simon Glass761648b2022-01-29 14:14:11 -0700553 self.assertEqual(2, gitutil.count_commits_to_branch(None))
Simon Glass54f1c5b2020-07-05 21:41:50 -0600554 col = terminal.Color()
Simon Glass14d64e32025-04-29 07:21:59 -0600555 with terminal.capture() as _:
Simon Glassc0257982025-04-29 07:22:11 -0600556 _, cover_fname, patch_files = send.prepare_patches(
Simon Glassb3bf4e12020-07-05 21:41:52 -0600557 col, branch=None, count=-1, start=0, end=0,
Philipp Tomsich858531a2020-11-24 18:14:52 +0100558 ignore_binary=False, signoff=True)
Simon Glass54f1c5b2020-07-05 21:41:50 -0600559 self.assertIsNone(cover_fname)
560 self.assertEqual(2, len(patch_files))
Simon Glass2eb4da72020-07-05 21:41:51 -0600561
562 # Check that it can detect a different branch
Simon Glass761648b2022-01-29 14:14:11 -0700563 self.assertEqual(3, gitutil.count_commits_to_branch('second'))
Simon Glass14d64e32025-04-29 07:21:59 -0600564 with terminal.capture() as _:
Simon Glassc0257982025-04-29 07:22:11 -0600565 series, cover_fname, patch_files = send.prepare_patches(
Simon Glassb3bf4e12020-07-05 21:41:52 -0600566 col, branch='second', count=-1, start=0, end=0,
Philipp Tomsich858531a2020-11-24 18:14:52 +0100567 ignore_binary=False, signoff=True)
Simon Glass2eb4da72020-07-05 21:41:51 -0600568 self.assertIsNotNone(cover_fname)
569 self.assertEqual(3, len(patch_files))
Simon Glassb3bf4e12020-07-05 21:41:52 -0600570
Simon Glass414f1e02025-02-27 12:27:30 -0700571 cover = tools.read_file(cover_fname, binary=False)
572 lines = cover.splitlines()[-2:]
573 base = repo.lookup_reference('refs/heads/base').target
574 self.assertEqual(f'base-commit: {base}', lines[0])
575 self.assertEqual('branch: second', lines[1])
576
Simon Glassda1a6ec2025-03-28 07:02:20 -0600577 # Make sure that the base-commit is not present when it is in the
578 # cover letter
579 for fname in patch_files:
580 self.assertNotIn(b'base-commit:', tools.read_file(fname))
581
Simon Glassb3bf4e12020-07-05 21:41:52 -0600582 # Check that it can skip patches at the end
Simon Glass14d64e32025-04-29 07:21:59 -0600583 with terminal.capture() as _:
Simon Glassc0257982025-04-29 07:22:11 -0600584 _, cover_fname, patch_files = send.prepare_patches(
Simon Glassb3bf4e12020-07-05 21:41:52 -0600585 col, branch='second', count=-1, start=0, end=1,
Philipp Tomsich858531a2020-11-24 18:14:52 +0100586 ignore_binary=False, signoff=True)
Simon Glassb3bf4e12020-07-05 21:41:52 -0600587 self.assertIsNotNone(cover_fname)
588 self.assertEqual(2, len(patch_files))
Simon Glass414f1e02025-02-27 12:27:30 -0700589
590 cover = tools.read_file(cover_fname, binary=False)
591 lines = cover.splitlines()[-2:]
592 base2 = repo.lookup_reference('refs/heads/second')
593 ref = base2.peel(pygit2.GIT_OBJ_COMMIT).parents[0].parents[0].id
594 self.assertEqual(f'base-commit: {ref}', lines[0])
595 self.assertEqual('branch: second', lines[1])
Simon Glass54f1c5b2020-07-05 21:41:50 -0600596 finally:
597 os.chdir(orig_dir)
Simon Glass06202d62020-10-29 21:46:27 -0600598
Maxim Cournoyer3ef23e92022-12-20 00:28:46 -0500599 def test_custom_get_maintainer_script(self):
600 """Validate that a custom get_maintainer script gets used."""
601 self.make_git_tree()
602 with directory_excursion(self.gitdir):
603 # Setup git.
604 os.environ['GIT_CONFIG_GLOBAL'] = '/dev/null'
605 os.environ['GIT_CONFIG_SYSTEM'] = '/dev/null'
606 tools.run('git', 'config', 'user.name', 'Dummy')
607 tools.run('git', 'config', 'user.email', 'dumdum@dummy.com')
608 tools.run('git', 'branch', 'upstream')
609 tools.run('git', 'branch', '--set-upstream-to=upstream')
610 tools.run('git', 'add', '.')
611 tools.run('git', 'commit', '-m', 'new commit')
612
613 # Setup patman configuration.
614 with open('.patman', 'w', buffering=1) as f:
615 f.write('[settings]\n'
616 'get_maintainer_script: dummy-script.sh\n'
Sean Andersona06df742024-04-18 22:36:30 -0400617 'check_patch: False\n'
618 'add_maintainers: True\n')
Maxim Cournoyer3ef23e92022-12-20 00:28:46 -0500619 with open('dummy-script.sh', 'w', buffering=1) as f:
620 f.write('#!/usr/bin/env python\n'
621 'print("hello@there.com")\n')
622 os.chmod('dummy-script.sh', 0x555)
623
624 # Finally, do the test
Simon Glass14d64e32025-04-29 07:21:59 -0600625 with terminal.capture():
Maxim Cournoyer3ef23e92022-12-20 00:28:46 -0500626 output = tools.run(PATMAN_DIR / 'patman', '--dry-run')
627 # Assert the email address is part of the dry-run
628 # output.
629 self.assertIn('hello@there.com', output)
630
Simon Glassd85bb8f2022-01-29 14:14:09 -0700631 def test_tags(self):
Simon Glass06202d62020-10-29 21:46:27 -0600632 """Test collection of tags in a patchstream"""
633 text = '''This is a patch
634
635Signed-off-by: Terminator
Simon Glass3b762cc2020-10-29 21:46:28 -0600636Reviewed-by: %s
637Reviewed-by: %s
Simon Glass06202d62020-10-29 21:46:27 -0600638Tested-by: %s
Simon Glass3b762cc2020-10-29 21:46:28 -0600639''' % (self.joe, self.mary, self.leb)
Simon Glass06202d62020-10-29 21:46:27 -0600640 pstrm = PatchStream.process_text(text)
641 self.assertEqual(pstrm.commit.rtags, {
Simon Glass3b762cc2020-10-29 21:46:28 -0600642 'Reviewed-by': {self.joe, self.mary},
Simon Glass06202d62020-10-29 21:46:27 -0600643 'Tested-by': {self.leb}})
Simon Glass3b762cc2020-10-29 21:46:28 -0600644
Simon Glassd85bb8f2022-01-29 14:14:09 -0700645 def test_invalid_tag(self):
Patrick Delaunay6bbdd0c2021-07-22 16:51:42 +0200646 """Test invalid tag in a patchstream"""
647 text = '''This is a patch
648
649Serie-version: 2
650'''
651 with self.assertRaises(ValueError) as exc:
652 pstrm = PatchStream.process_text(text)
653 self.assertEqual("Line 3: Invalid tag = 'Serie-version: 2'",
654 str(exc.exception))
655
Simon Glassd85bb8f2022-01-29 14:14:09 -0700656 def test_missing_end(self):
Simon Glass3b762cc2020-10-29 21:46:28 -0600657 """Test a missing END tag"""
658 text = '''This is a patch
659
660Cover-letter:
661This is the title
662missing END after this line
663Signed-off-by: Fred
664'''
665 pstrm = PatchStream.process_text(text)
666 self.assertEqual(["Missing 'END' in section 'cover'"],
667 pstrm.commit.warn)
668
Simon Glassd85bb8f2022-01-29 14:14:09 -0700669 def test_missing_blank_line(self):
Simon Glass3b762cc2020-10-29 21:46:28 -0600670 """Test a missing blank line after a tag"""
671 text = '''This is a patch
672
673Series-changes: 2
674- First line of changes
675- Missing blank line after this line
676Signed-off-by: Fred
677'''
678 pstrm = PatchStream.process_text(text)
679 self.assertEqual(["Missing 'blank line' in section 'Series-changes'"],
680 pstrm.commit.warn)
681
Simon Glassd85bb8f2022-01-29 14:14:09 -0700682 def test_invalid_commit_tag(self):
Simon Glass3b762cc2020-10-29 21:46:28 -0600683 """Test an invalid Commit-xxx tag"""
684 text = '''This is a patch
685
686Commit-fred: testing
687'''
688 pstrm = PatchStream.process_text(text)
689 self.assertEqual(["Line 3: Ignoring Commit-fred"], pstrm.commit.warn)
690
Simon Glassd85bb8f2022-01-29 14:14:09 -0700691 def test_self_test(self):
Simon Glass3b762cc2020-10-29 21:46:28 -0600692 """Test a tested by tag by this user"""
693 test_line = 'Tested-by: %s@napier.com' % os.getenv('USER')
694 text = '''This is a patch
695
696%s
697''' % test_line
698 pstrm = PatchStream.process_text(text)
699 self.assertEqual(["Ignoring '%s'" % test_line], pstrm.commit.warn)
700
Simon Glassd85bb8f2022-01-29 14:14:09 -0700701 def test_space_before_tab(self):
Simon Glass3b762cc2020-10-29 21:46:28 -0600702 """Test a space before a tab"""
703 text = '''This is a patch
704
705+ \tSomething
706'''
707 pstrm = PatchStream.process_text(text)
708 self.assertEqual(["Line 3/0 has space before tab"], pstrm.commit.warn)
709
Simon Glassd85bb8f2022-01-29 14:14:09 -0700710 def test_lines_after_test(self):
Simon Glass3b762cc2020-10-29 21:46:28 -0600711 """Test detecting lines after TEST= line"""
712 text = '''This is a patch
713
714TEST=sometest
715more lines
716here
717'''
718 pstrm = PatchStream.process_text(text)
719 self.assertEqual(["Found 2 lines after TEST="], pstrm.commit.warn)
720
Simon Glassd85bb8f2022-01-29 14:14:09 -0700721 def test_blank_line_at_end(self):
Simon Glass3b762cc2020-10-29 21:46:28 -0600722 """Test detecting a blank line at the end of a file"""
723 text = '''This is a patch
724
725diff --git a/lib/fdtdec.c b/lib/fdtdec.c
726index c072e54..942244f 100644
727--- a/lib/fdtdec.c
728+++ b/lib/fdtdec.c
729@@ -1200,7 +1200,8 @@ int fdtdec_setup_mem_size_base(void)
730 }
731
732 gd->ram_size = (phys_size_t)(res.end - res.start + 1);
733- debug("%s: Initial DRAM size %llx\n", __func__, (u64)gd->ram_size);
734+ debug("%s: Initial DRAM size %llx\n", __func__,
735+ (unsigned long long)gd->ram_size);
736+
737diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
738
739--
7402.7.4
741
742 '''
743 pstrm = PatchStream.process_text(text)
744 self.assertEqual(
745 ["Found possible blank line(s) at end of file 'lib/fdtdec.c'"],
746 pstrm.commit.warn)
Simon Glass1c1f2072020-10-29 21:46:34 -0600747
Simon Glassd85bb8f2022-01-29 14:14:09 -0700748 def test_no_upstream(self):
Simon Glass1c1f2072020-10-29 21:46:34 -0600749 """Test CountCommitsToBranch when there is no upstream"""
750 repo = self.make_git_tree()
751 target = repo.lookup_reference('refs/heads/base')
Simon Glass547cba62022-02-11 13:23:18 -0700752 # pylint doesn't seem to find this
753 # pylint: disable=E1101
Simon Glass1c1f2072020-10-29 21:46:34 -0600754 self.repo.checkout(target, strategy=pygit2.GIT_CHECKOUT_FORCE)
755
756 # Check that it can detect the current branch
Heinrich Schuchardtd01d6672023-04-20 20:07:29 +0200757 orig_dir = os.getcwd()
Simon Glass1c1f2072020-10-29 21:46:34 -0600758 try:
Simon Glass1c1f2072020-10-29 21:46:34 -0600759 os.chdir(self.gitdir)
760 with self.assertRaises(ValueError) as exc:
Simon Glass761648b2022-01-29 14:14:11 -0700761 gitutil.count_commits_to_branch(None)
Simon Glass1c1f2072020-10-29 21:46:34 -0600762 self.assertIn(
763 "Failed to determine upstream: fatal: no upstream configured for branch 'base'",
764 str(exc.exception))
765 finally:
766 os.chdir(orig_dir)
Simon Glass3db916d2020-10-29 21:46:35 -0600767
768 @staticmethod
Simon Glassf9b03cf2020-11-03 13:54:14 -0700769 def _fake_patchwork(url, subpath):
Simon Glass3db916d2020-10-29 21:46:35 -0600770 """Fake Patchwork server for the function below
771
772 This handles accessing a series, providing a list consisting of a
773 single patch
Simon Glassf9b03cf2020-11-03 13:54:14 -0700774
775 Args:
776 url (str): URL of patchwork server
777 subpath (str): URL subpath to use
Simon Glass3db916d2020-10-29 21:46:35 -0600778 """
779 re_series = re.match(r'series/(\d*)/$', subpath)
780 if re_series:
781 series_num = re_series.group(1)
782 if series_num == '1234':
783 return {'patches': [
784 {'id': '1', 'name': 'Some patch'}]}
785 raise ValueError('Fake Patchwork does not understand: %s' % subpath)
786
Simon Glassd85bb8f2022-01-29 14:14:09 -0700787 def test_status_mismatch(self):
Simon Glass3db916d2020-10-29 21:46:35 -0600788 """Test Patchwork patches not matching the series"""
789 series = Series()
790
Simon Glass14d64e32025-04-29 07:21:59 -0600791 with terminal.capture() as (_, err):
Simon Glassf9b03cf2020-11-03 13:54:14 -0700792 status.collect_patches(series, 1234, None, self._fake_patchwork)
Simon Glass3db916d2020-10-29 21:46:35 -0600793 self.assertIn('Warning: Patchwork reports 1 patches, series has 0',
794 err.getvalue())
795
Simon Glassd85bb8f2022-01-29 14:14:09 -0700796 def test_status_read_patch(self):
Simon Glass3db916d2020-10-29 21:46:35 -0600797 """Test handling a single patch in Patchwork"""
798 series = Series()
799 series.commits = [Commit('abcd')]
800
Simon Glassf9b03cf2020-11-03 13:54:14 -0700801 patches = status.collect_patches(series, 1234, None,
802 self._fake_patchwork)
Simon Glass3db916d2020-10-29 21:46:35 -0600803 self.assertEqual(1, len(patches))
804 patch = patches[0]
805 self.assertEqual('1', patch.id)
806 self.assertEqual('Some patch', patch.raw_subject)
807
Simon Glassd85bb8f2022-01-29 14:14:09 -0700808 def test_parse_subject(self):
Simon Glass3db916d2020-10-29 21:46:35 -0600809 """Test parsing of the patch subject"""
810 patch = status.Patch('1')
811
812 # Simple patch not in a series
813 patch.parse_subject('Testing')
814 self.assertEqual('Testing', patch.raw_subject)
815 self.assertEqual('Testing', patch.subject)
816 self.assertEqual(1, patch.seq)
817 self.assertEqual(1, patch.count)
818 self.assertEqual(None, patch.prefix)
819 self.assertEqual(None, patch.version)
820
821 # First patch in a series
822 patch.parse_subject('[1/2] Testing')
823 self.assertEqual('[1/2] Testing', patch.raw_subject)
824 self.assertEqual('Testing', patch.subject)
825 self.assertEqual(1, patch.seq)
826 self.assertEqual(2, patch.count)
827 self.assertEqual(None, patch.prefix)
828 self.assertEqual(None, patch.version)
829
830 # Second patch in a series
831 patch.parse_subject('[2/2] Testing')
832 self.assertEqual('Testing', patch.subject)
833 self.assertEqual(2, patch.seq)
834 self.assertEqual(2, patch.count)
835 self.assertEqual(None, patch.prefix)
836 self.assertEqual(None, patch.version)
837
838 # RFC patch
839 patch.parse_subject('[RFC,3/7] Testing')
840 self.assertEqual('Testing', patch.subject)
841 self.assertEqual(3, patch.seq)
842 self.assertEqual(7, patch.count)
843 self.assertEqual('RFC', patch.prefix)
844 self.assertEqual(None, patch.version)
845
846 # Version patch
847 patch.parse_subject('[v2,3/7] Testing')
848 self.assertEqual('Testing', patch.subject)
849 self.assertEqual(3, patch.seq)
850 self.assertEqual(7, patch.count)
851 self.assertEqual(None, patch.prefix)
852 self.assertEqual('v2', patch.version)
853
854 # All fields
855 patch.parse_subject('[RESEND,v2,3/7] Testing')
856 self.assertEqual('Testing', patch.subject)
857 self.assertEqual(3, patch.seq)
858 self.assertEqual(7, patch.count)
859 self.assertEqual('RESEND', patch.prefix)
860 self.assertEqual('v2', patch.version)
861
862 # RFC only
863 patch.parse_subject('[RESEND] Testing')
864 self.assertEqual('Testing', patch.subject)
865 self.assertEqual(1, patch.seq)
866 self.assertEqual(1, patch.count)
867 self.assertEqual('RESEND', patch.prefix)
868 self.assertEqual(None, patch.version)
869
Simon Glassd85bb8f2022-01-29 14:14:09 -0700870 def test_compare_series(self):
Simon Glass3db916d2020-10-29 21:46:35 -0600871 """Test operation of compare_with_series()"""
872 commit1 = Commit('abcd')
873 commit1.subject = 'Subject 1'
874 commit2 = Commit('ef12')
875 commit2.subject = 'Subject 2'
876 commit3 = Commit('3456')
877 commit3.subject = 'Subject 2'
878
879 patch1 = status.Patch('1')
880 patch1.subject = 'Subject 1'
881 patch2 = status.Patch('2')
882 patch2.subject = 'Subject 2'
883 patch3 = status.Patch('3')
884 patch3.subject = 'Subject 2'
885
886 series = Series()
887 series.commits = [commit1]
888 patches = [patch1]
889 patch_for_commit, commit_for_patch, warnings = (
890 status.compare_with_series(series, patches))
891 self.assertEqual(1, len(patch_for_commit))
892 self.assertEqual(patch1, patch_for_commit[0])
893 self.assertEqual(1, len(commit_for_patch))
894 self.assertEqual(commit1, commit_for_patch[0])
895
896 series.commits = [commit1]
897 patches = [patch1, patch2]
898 patch_for_commit, commit_for_patch, warnings = (
899 status.compare_with_series(series, patches))
900 self.assertEqual(1, len(patch_for_commit))
901 self.assertEqual(patch1, patch_for_commit[0])
902 self.assertEqual(1, len(commit_for_patch))
903 self.assertEqual(commit1, commit_for_patch[0])
904 self.assertEqual(["Cannot find commit for patch 2 ('Subject 2')"],
905 warnings)
906
907 series.commits = [commit1, commit2]
908 patches = [patch1]
909 patch_for_commit, commit_for_patch, warnings = (
910 status.compare_with_series(series, patches))
911 self.assertEqual(1, len(patch_for_commit))
912 self.assertEqual(patch1, patch_for_commit[0])
913 self.assertEqual(1, len(commit_for_patch))
914 self.assertEqual(commit1, commit_for_patch[0])
915 self.assertEqual(["Cannot find patch for commit 2 ('Subject 2')"],
916 warnings)
917
918 series.commits = [commit1, commit2, commit3]
919 patches = [patch1, patch2]
920 patch_for_commit, commit_for_patch, warnings = (
921 status.compare_with_series(series, patches))
922 self.assertEqual(2, len(patch_for_commit))
923 self.assertEqual(patch1, patch_for_commit[0])
924 self.assertEqual(patch2, patch_for_commit[1])
925 self.assertEqual(1, len(commit_for_patch))
926 self.assertEqual(commit1, commit_for_patch[0])
927 self.assertEqual(["Cannot find patch for commit 3 ('Subject 2')",
928 "Multiple commits match patch 2 ('Subject 2'):\n"
929 ' Subject 2\n Subject 2'],
930 warnings)
931
932 series.commits = [commit1, commit2]
933 patches = [patch1, patch2, patch3]
934 patch_for_commit, commit_for_patch, warnings = (
935 status.compare_with_series(series, patches))
936 self.assertEqual(1, len(patch_for_commit))
937 self.assertEqual(patch1, patch_for_commit[0])
938 self.assertEqual(2, len(commit_for_patch))
939 self.assertEqual(commit1, commit_for_patch[0])
940 self.assertEqual(["Multiple patches match commit 2 ('Subject 2'):\n"
941 ' Subject 2\n Subject 2',
942 "Cannot find commit for patch 3 ('Subject 2')"],
943 warnings)
944
Simon Glassf9b03cf2020-11-03 13:54:14 -0700945 def _fake_patchwork2(self, url, subpath):
Simon Glass3db916d2020-10-29 21:46:35 -0600946 """Fake Patchwork server for the function below
947
948 This handles accessing series, patches and comments, providing the data
949 in self.patches to the caller
Simon Glassf9b03cf2020-11-03 13:54:14 -0700950
951 Args:
952 url (str): URL of patchwork server
953 subpath (str): URL subpath to use
Simon Glass3db916d2020-10-29 21:46:35 -0600954 """
955 re_series = re.match(r'series/(\d*)/$', subpath)
956 re_patch = re.match(r'patches/(\d*)/$', subpath)
957 re_comments = re.match(r'patches/(\d*)/comments/$', subpath)
958 if re_series:
959 series_num = re_series.group(1)
960 if series_num == '1234':
961 return {'patches': self.patches}
962 elif re_patch:
963 patch_num = int(re_patch.group(1))
964 patch = self.patches[patch_num - 1]
965 return patch
966 elif re_comments:
967 patch_num = int(re_comments.group(1))
968 patch = self.patches[patch_num - 1]
969 return patch.comments
970 raise ValueError('Fake Patchwork does not understand: %s' % subpath)
971
Simon Glassd85bb8f2022-01-29 14:14:09 -0700972 def test_find_new_responses(self):
Simon Glass3db916d2020-10-29 21:46:35 -0600973 """Test operation of find_new_responses()"""
974 commit1 = Commit('abcd')
975 commit1.subject = 'Subject 1'
976 commit2 = Commit('ef12')
977 commit2.subject = 'Subject 2'
978
979 patch1 = status.Patch('1')
980 patch1.parse_subject('[1/2] Subject 1')
981 patch1.name = patch1.raw_subject
982 patch1.content = 'This is my patch content'
983 comment1a = {'content': 'Reviewed-by: %s\n' % self.joe}
984
985 patch1.comments = [comment1a]
986
987 patch2 = status.Patch('2')
988 patch2.parse_subject('[2/2] Subject 2')
989 patch2.name = patch2.raw_subject
990 patch2.content = 'Some other patch content'
991 comment2a = {
992 'content': 'Reviewed-by: %s\nTested-by: %s\n' %
993 (self.mary, self.leb)}
994 comment2b = {'content': 'Reviewed-by: %s' % self.fred}
995 patch2.comments = [comment2a, comment2b]
996
997 # This test works by setting up commits and patch for use by the fake
998 # Rest API function _fake_patchwork2(). It calls various functions in
999 # the status module after setting up tags in the commits, checking that
1000 # things behaves as expected
1001 self.commits = [commit1, commit2]
1002 self.patches = [patch1, patch2]
1003 count = 2
1004 new_rtag_list = [None] * count
Simon Glass2112d072020-10-29 21:46:38 -06001005 review_list = [None, None]
Simon Glass3db916d2020-10-29 21:46:35 -06001006
1007 # Check that the tags are picked up on the first patch
Simon Glass2112d072020-10-29 21:46:38 -06001008 status.find_new_responses(new_rtag_list, review_list, 0, commit1,
Simon Glassf9b03cf2020-11-03 13:54:14 -07001009 patch1, None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -06001010 self.assertEqual(new_rtag_list[0], {'Reviewed-by': {self.joe}})
1011
1012 # Now the second patch
Simon Glass2112d072020-10-29 21:46:38 -06001013 status.find_new_responses(new_rtag_list, review_list, 1, commit2,
Simon Glassf9b03cf2020-11-03 13:54:14 -07001014 patch2, None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -06001015 self.assertEqual(new_rtag_list[1], {
1016 'Reviewed-by': {self.mary, self.fred},
1017 'Tested-by': {self.leb}})
1018
1019 # Now add some tags to the commit, which means they should not appear as
1020 # 'new' tags when scanning comments
1021 new_rtag_list = [None] * count
1022 commit1.rtags = {'Reviewed-by': {self.joe}}
Simon Glass2112d072020-10-29 21:46:38 -06001023 status.find_new_responses(new_rtag_list, review_list, 0, commit1,
Simon Glassf9b03cf2020-11-03 13:54:14 -07001024 patch1, None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -06001025 self.assertEqual(new_rtag_list[0], {})
1026
1027 # For the second commit, add Ed and Fred, so only Mary should be left
1028 commit2.rtags = {
1029 'Tested-by': {self.leb},
1030 'Reviewed-by': {self.fred}}
Simon Glass2112d072020-10-29 21:46:38 -06001031 status.find_new_responses(new_rtag_list, review_list, 1, commit2,
Simon Glassf9b03cf2020-11-03 13:54:14 -07001032 patch2, None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -06001033 self.assertEqual(new_rtag_list[1], {'Reviewed-by': {self.mary}})
1034
1035 # Check that the output patches expectations:
1036 # 1 Subject 1
1037 # Reviewed-by: Joe Bloggs <joe@napierwallies.co.nz>
1038 # 2 Subject 2
1039 # Tested-by: Lord Edmund Blackaddër <weasel@blackadder.org>
1040 # Reviewed-by: Fred Bloggs <f.bloggs@napier.net>
1041 # + Reviewed-by: Mary Bloggs <mary@napierwallies.co.nz>
1042 # 1 new response available in patchwork
1043
1044 series = Series()
1045 series.commits = [commit1, commit2]
Simon Glass02811582022-01-29 14:14:18 -07001046 terminal.set_print_test_mode()
Simon Glass2112d072020-10-29 21:46:38 -06001047 status.check_patchwork_status(series, '1234', None, None, False, False,
Simon Glassf9b03cf2020-11-03 13:54:14 -07001048 None, self._fake_patchwork2)
Simon Glass02811582022-01-29 14:14:18 -07001049 lines = iter(terminal.get_print_test_lines())
Simon Glass3db916d2020-10-29 21:46:35 -06001050 col = terminal.Color()
1051 self.assertEqual(terminal.PrintLine(' 1 Subject 1', col.BLUE),
1052 next(lines))
1053 self.assertEqual(
1054 terminal.PrintLine(' Reviewed-by: ', col.GREEN, newline=False,
1055 bright=False),
1056 next(lines))
1057 self.assertEqual(terminal.PrintLine(self.joe, col.WHITE, bright=False),
1058 next(lines))
1059
1060 self.assertEqual(terminal.PrintLine(' 2 Subject 2', col.BLUE),
1061 next(lines))
1062 self.assertEqual(
Simon Glass2112d072020-10-29 21:46:38 -06001063 terminal.PrintLine(' Reviewed-by: ', col.GREEN, newline=False,
Simon Glass3db916d2020-10-29 21:46:35 -06001064 bright=False),
1065 next(lines))
Simon Glass2112d072020-10-29 21:46:38 -06001066 self.assertEqual(terminal.PrintLine(self.fred, col.WHITE, bright=False),
Simon Glass3db916d2020-10-29 21:46:35 -06001067 next(lines))
1068 self.assertEqual(
Simon Glass2112d072020-10-29 21:46:38 -06001069 terminal.PrintLine(' Tested-by: ', col.GREEN, newline=False,
Simon Glass3db916d2020-10-29 21:46:35 -06001070 bright=False),
1071 next(lines))
Simon Glass2112d072020-10-29 21:46:38 -06001072 self.assertEqual(terminal.PrintLine(self.leb, col.WHITE, bright=False),
Simon Glass3db916d2020-10-29 21:46:35 -06001073 next(lines))
1074 self.assertEqual(
1075 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
1076 next(lines))
1077 self.assertEqual(terminal.PrintLine(self.mary, col.WHITE),
1078 next(lines))
1079 self.assertEqual(terminal.PrintLine(
Simon Glassd0a0a582020-10-29 21:46:36 -06001080 '1 new response available in patchwork (use -d to write them to a new branch)',
1081 None), next(lines))
1082
Simon Glassf9b03cf2020-11-03 13:54:14 -07001083 def _fake_patchwork3(self, url, subpath):
Simon Glassd0a0a582020-10-29 21:46:36 -06001084 """Fake Patchwork server for the function below
1085
1086 This handles accessing series, patches and comments, providing the data
1087 in self.patches to the caller
Simon Glassf9b03cf2020-11-03 13:54:14 -07001088
1089 Args:
1090 url (str): URL of patchwork server
1091 subpath (str): URL subpath to use
Simon Glassd0a0a582020-10-29 21:46:36 -06001092 """
1093 re_series = re.match(r'series/(\d*)/$', subpath)
1094 re_patch = re.match(r'patches/(\d*)/$', subpath)
1095 re_comments = re.match(r'patches/(\d*)/comments/$', subpath)
1096 if re_series:
1097 series_num = re_series.group(1)
1098 if series_num == '1234':
1099 return {'patches': self.patches}
1100 elif re_patch:
1101 patch_num = int(re_patch.group(1))
1102 patch = self.patches[patch_num - 1]
1103 return patch
1104 elif re_comments:
1105 patch_num = int(re_comments.group(1))
1106 patch = self.patches[patch_num - 1]
1107 return patch.comments
1108 raise ValueError('Fake Patchwork does not understand: %s' % subpath)
1109
Simon Glassd85bb8f2022-01-29 14:14:09 -07001110 def test_create_branch(self):
Simon Glassd0a0a582020-10-29 21:46:36 -06001111 """Test operation of create_branch()"""
1112 repo = self.make_git_tree()
1113 branch = 'first'
1114 dest_branch = 'first2'
1115 count = 2
1116 gitdir = os.path.join(self.gitdir, '.git')
1117
1118 # Set up the test git tree. We use branch 'first' which has two commits
1119 # in it
1120 series = patchstream.get_metadata_for_list(branch, gitdir, count)
1121 self.assertEqual(2, len(series.commits))
1122
1123 patch1 = status.Patch('1')
1124 patch1.parse_subject('[1/2] %s' % series.commits[0].subject)
1125 patch1.name = patch1.raw_subject
1126 patch1.content = 'This is my patch content'
1127 comment1a = {'content': 'Reviewed-by: %s\n' % self.joe}
1128
1129 patch1.comments = [comment1a]
1130
1131 patch2 = status.Patch('2')
1132 patch2.parse_subject('[2/2] %s' % series.commits[1].subject)
1133 patch2.name = patch2.raw_subject
1134 patch2.content = 'Some other patch content'
1135 comment2a = {
1136 'content': 'Reviewed-by: %s\nTested-by: %s\n' %
1137 (self.mary, self.leb)}
1138 comment2b = {
1139 'content': 'Reviewed-by: %s' % self.fred}
1140 patch2.comments = [comment2a, comment2b]
1141
1142 # This test works by setting up patches for use by the fake Rest API
1143 # function _fake_patchwork3(). The fake patch comments above should
1144 # result in new review tags that are collected and added to the commits
1145 # created in the destination branch.
1146 self.patches = [patch1, patch2]
1147 count = 2
1148
1149 # Expected output:
1150 # 1 i2c: I2C things
1151 # + Reviewed-by: Joe Bloggs <joe@napierwallies.co.nz>
1152 # 2 spi: SPI fixes
1153 # + Reviewed-by: Fred Bloggs <f.bloggs@napier.net>
1154 # + Reviewed-by: Mary Bloggs <mary@napierwallies.co.nz>
1155 # + Tested-by: Lord Edmund Blackaddër <weasel@blackadder.org>
1156 # 4 new responses available in patchwork
1157 # 4 responses added from patchwork into new branch 'first2'
1158 # <unittest.result.TestResult run=8 errors=0 failures=0>
1159
Simon Glass02811582022-01-29 14:14:18 -07001160 terminal.set_print_test_mode()
Simon Glassd0a0a582020-10-29 21:46:36 -06001161 status.check_patchwork_status(series, '1234', branch, dest_branch,
Simon Glassf9b03cf2020-11-03 13:54:14 -07001162 False, False, None, self._fake_patchwork3,
1163 repo)
Simon Glass02811582022-01-29 14:14:18 -07001164 lines = terminal.get_print_test_lines()
Simon Glassd0a0a582020-10-29 21:46:36 -06001165 self.assertEqual(12, len(lines))
1166 self.assertEqual(
1167 "4 responses added from patchwork into new branch 'first2'",
1168 lines[11].text)
1169
1170 # Check that the destination branch has the new tags
1171 new_series = patchstream.get_metadata_for_list(dest_branch, gitdir,
1172 count)
1173 self.assertEqual(
1174 {'Reviewed-by': {self.joe}},
1175 new_series.commits[0].rtags)
1176 self.assertEqual(
1177 {'Tested-by': {self.leb},
1178 'Reviewed-by': {self.fred, self.mary}},
1179 new_series.commits[1].rtags)
1180
1181 # Now check the actual test of the first commit message. We expect to
1182 # see the new tags immediately below the old ones.
1183 stdout = patchstream.get_list(dest_branch, count=count, git_dir=gitdir)
1184 lines = iter([line.strip() for line in stdout.splitlines()
1185 if '-by:' in line])
1186
1187 # First patch should have the review tag
1188 self.assertEqual('Reviewed-by: %s' % self.joe, next(lines))
1189
1190 # Second patch should have the sign-off then the tested-by and two
1191 # reviewed-by tags
1192 self.assertEqual('Signed-off-by: %s' % self.leb, next(lines))
1193 self.assertEqual('Reviewed-by: %s' % self.fred, next(lines))
1194 self.assertEqual('Reviewed-by: %s' % self.mary, next(lines))
1195 self.assertEqual('Tested-by: %s' % self.leb, next(lines))
Simon Glassda8a2922020-10-29 21:46:37 -06001196
Simon Glassd85bb8f2022-01-29 14:14:09 -07001197 def test_parse_snippets(self):
Simon Glassda8a2922020-10-29 21:46:37 -06001198 """Test parsing of review snippets"""
1199 text = '''Hi Fred,
1200
1201This is a comment from someone.
1202
1203Something else
1204
1205On some recent date, Fred wrote:
1206> This is why I wrote the patch
1207> so here it is
1208
1209Now a comment about the commit message
1210A little more to say
1211
1212Even more
1213
1214> diff --git a/file.c b/file.c
1215> Some more code
1216> Code line 2
1217> Code line 3
1218> Code line 4
1219> Code line 5
1220> Code line 6
1221> Code line 7
1222> Code line 8
1223> Code line 9
1224
1225And another comment
1226
Simon Glassd85bb8f2022-01-29 14:14:09 -07001227> @@ -153,8 +143,13 @@ def check_patch(fname, show_types=False):
Simon Glassda8a2922020-10-29 21:46:37 -06001228> further down on the file
1229> and more code
1230> +Addition here
1231> +Another addition here
1232> codey
1233> more codey
1234
1235and another thing in same file
1236
1237> @@ -253,8 +243,13 @@
1238> with no function context
1239
1240one more thing
1241
1242> diff --git a/tools/patman/main.py b/tools/patman/main.py
1243> +line of code
1244now a very long comment in a different file
1245line2
1246line3
1247line4
1248line5
1249line6
1250line7
1251line8
1252'''
1253 pstrm = PatchStream.process_text(text, True)
1254 self.assertEqual([], pstrm.commit.warn)
1255
1256 # We expect to the filename and up to 5 lines of code context before
1257 # each comment. The 'On xxx wrote:' bit should be removed.
1258 self.assertEqual(
1259 [['Hi Fred,',
1260 'This is a comment from someone.',
1261 'Something else'],
1262 ['> This is why I wrote the patch',
1263 '> so here it is',
1264 'Now a comment about the commit message',
1265 'A little more to say', 'Even more'],
1266 ['> File: file.c', '> Code line 5', '> Code line 6',
1267 '> Code line 7', '> Code line 8', '> Code line 9',
1268 'And another comment'],
1269 ['> File: file.c',
Simon Glassd85bb8f2022-01-29 14:14:09 -07001270 '> Line: 153 / 143: def check_patch(fname, show_types=False):',
Simon Glassda8a2922020-10-29 21:46:37 -06001271 '> and more code', '> +Addition here', '> +Another addition here',
1272 '> codey', '> more codey', 'and another thing in same file'],
1273 ['> File: file.c', '> Line: 253 / 243',
1274 '> with no function context', 'one more thing'],
1275 ['> File: tools/patman/main.py', '> +line of code',
1276 'now a very long comment in a different file',
1277 'line2', 'line3', 'line4', 'line5', 'line6', 'line7', 'line8']],
1278 pstrm.snippets)
Simon Glass2112d072020-10-29 21:46:38 -06001279
Simon Glassd85bb8f2022-01-29 14:14:09 -07001280 def test_review_snippets(self):
Simon Glass2112d072020-10-29 21:46:38 -06001281 """Test showing of review snippets"""
1282 def _to_submitter(who):
1283 m_who = re.match('(.*) <(.*)>', who)
1284 return {
1285 'name': m_who.group(1),
1286 'email': m_who.group(2)
1287 }
1288
1289 commit1 = Commit('abcd')
1290 commit1.subject = 'Subject 1'
1291 commit2 = Commit('ef12')
1292 commit2.subject = 'Subject 2'
1293
1294 patch1 = status.Patch('1')
1295 patch1.parse_subject('[1/2] Subject 1')
1296 patch1.name = patch1.raw_subject
1297 patch1.content = 'This is my patch content'
1298 comment1a = {'submitter': _to_submitter(self.joe),
1299 'content': '''Hi Fred,
1300
1301On some date Fred wrote:
1302
1303> diff --git a/file.c b/file.c
1304> Some code
1305> and more code
1306
1307Here is my comment above the above...
1308
1309
1310Reviewed-by: %s
1311''' % self.joe}
1312
1313 patch1.comments = [comment1a]
1314
1315 patch2 = status.Patch('2')
1316 patch2.parse_subject('[2/2] Subject 2')
1317 patch2.name = patch2.raw_subject
1318 patch2.content = 'Some other patch content'
1319 comment2a = {
1320 'content': 'Reviewed-by: %s\nTested-by: %s\n' %
1321 (self.mary, self.leb)}
1322 comment2b = {'submitter': _to_submitter(self.fred),
1323 'content': '''Hi Fred,
1324
1325On some date Fred wrote:
1326
1327> diff --git a/tools/patman/commit.py b/tools/patman/commit.py
1328> @@ -41,6 +41,9 @@ class Commit:
1329> self.rtags = collections.defaultdict(set)
1330> self.warn = []
1331>
1332> + def __str__(self):
1333> + return self.subject
1334> +
Simon Glassd85bb8f2022-01-29 14:14:09 -07001335> def add_change(self, version, info):
Simon Glass2112d072020-10-29 21:46:38 -06001336> """Add a new change line to the change list for a version.
1337>
1338A comment
1339
1340Reviewed-by: %s
1341''' % self.fred}
1342 patch2.comments = [comment2a, comment2b]
1343
1344 # This test works by setting up commits and patch for use by the fake
1345 # Rest API function _fake_patchwork2(). It calls various functions in
1346 # the status module after setting up tags in the commits, checking that
1347 # things behaves as expected
1348 self.commits = [commit1, commit2]
1349 self.patches = [patch1, patch2]
1350
1351 # Check that the output patches expectations:
1352 # 1 Subject 1
1353 # Reviewed-by: Joe Bloggs <joe@napierwallies.co.nz>
1354 # 2 Subject 2
1355 # Tested-by: Lord Edmund Blackaddër <weasel@blackadder.org>
1356 # Reviewed-by: Fred Bloggs <f.bloggs@napier.net>
1357 # + Reviewed-by: Mary Bloggs <mary@napierwallies.co.nz>
1358 # 1 new response available in patchwork
1359
1360 series = Series()
1361 series.commits = [commit1, commit2]
Simon Glass02811582022-01-29 14:14:18 -07001362 terminal.set_print_test_mode()
Simon Glass2112d072020-10-29 21:46:38 -06001363 status.check_patchwork_status(series, '1234', None, None, False, True,
Simon Glassf9b03cf2020-11-03 13:54:14 -07001364 None, self._fake_patchwork2)
Simon Glass02811582022-01-29 14:14:18 -07001365 lines = iter(terminal.get_print_test_lines())
Simon Glass2112d072020-10-29 21:46:38 -06001366 col = terminal.Color()
1367 self.assertEqual(terminal.PrintLine(' 1 Subject 1', col.BLUE),
1368 next(lines))
1369 self.assertEqual(
1370 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
1371 next(lines))
1372 self.assertEqual(terminal.PrintLine(self.joe, col.WHITE), next(lines))
1373
1374 self.assertEqual(terminal.PrintLine('Review: %s' % self.joe, col.RED),
1375 next(lines))
1376 self.assertEqual(terminal.PrintLine(' Hi Fred,', None), next(lines))
1377 self.assertEqual(terminal.PrintLine('', None), next(lines))
1378 self.assertEqual(terminal.PrintLine(' > File: file.c', col.MAGENTA),
1379 next(lines))
1380 self.assertEqual(terminal.PrintLine(' > Some code', col.MAGENTA),
1381 next(lines))
1382 self.assertEqual(terminal.PrintLine(' > and more code', col.MAGENTA),
1383 next(lines))
1384 self.assertEqual(terminal.PrintLine(
1385 ' Here is my comment above the above...', None), next(lines))
1386 self.assertEqual(terminal.PrintLine('', None), next(lines))
1387
1388 self.assertEqual(terminal.PrintLine(' 2 Subject 2', col.BLUE),
1389 next(lines))
1390 self.assertEqual(
1391 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
1392 next(lines))
1393 self.assertEqual(terminal.PrintLine(self.fred, col.WHITE),
1394 next(lines))
1395 self.assertEqual(
1396 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
1397 next(lines))
1398 self.assertEqual(terminal.PrintLine(self.mary, col.WHITE),
1399 next(lines))
1400 self.assertEqual(
1401 terminal.PrintLine(' + Tested-by: ', col.GREEN, newline=False),
1402 next(lines))
1403 self.assertEqual(terminal.PrintLine(self.leb, col.WHITE),
1404 next(lines))
1405
1406 self.assertEqual(terminal.PrintLine('Review: %s' % self.fred, col.RED),
1407 next(lines))
1408 self.assertEqual(terminal.PrintLine(' Hi Fred,', None), next(lines))
1409 self.assertEqual(terminal.PrintLine('', None), next(lines))
1410 self.assertEqual(terminal.PrintLine(
1411 ' > File: tools/patman/commit.py', col.MAGENTA), next(lines))
1412 self.assertEqual(terminal.PrintLine(
1413 ' > Line: 41 / 41: class Commit:', col.MAGENTA), next(lines))
1414 self.assertEqual(terminal.PrintLine(
1415 ' > + return self.subject', col.MAGENTA), next(lines))
1416 self.assertEqual(terminal.PrintLine(
1417 ' > +', col.MAGENTA), next(lines))
1418 self.assertEqual(
Simon Glassd85bb8f2022-01-29 14:14:09 -07001419 terminal.PrintLine(' > def add_change(self, version, info):',
Simon Glass2112d072020-10-29 21:46:38 -06001420 col.MAGENTA),
1421 next(lines))
1422 self.assertEqual(terminal.PrintLine(
1423 ' > """Add a new change line to the change list for a version.',
1424 col.MAGENTA), next(lines))
1425 self.assertEqual(terminal.PrintLine(
1426 ' >', col.MAGENTA), next(lines))
1427 self.assertEqual(terminal.PrintLine(
1428 ' A comment', None), next(lines))
1429 self.assertEqual(terminal.PrintLine('', None), next(lines))
1430
1431 self.assertEqual(terminal.PrintLine(
1432 '4 new responses available in patchwork (use -d to write them to a new branch)',
1433 None), next(lines))
Simon Glass6a222e62021-08-01 16:02:39 -06001434
Simon Glassd85bb8f2022-01-29 14:14:09 -07001435 def test_insert_tags(self):
Simon Glass6a222e62021-08-01 16:02:39 -06001436 """Test inserting of review tags"""
1437 msg = '''first line
1438second line.'''
1439 tags = [
1440 'Reviewed-by: Bin Meng <bmeng.cn@gmail.com>',
1441 'Tested-by: Bin Meng <bmeng.cn@gmail.com>'
1442 ]
1443 signoff = 'Signed-off-by: Simon Glass <sjg@chromium.com>'
1444 tag_str = '\n'.join(tags)
1445
1446 new_msg = patchstream.insert_tags(msg, tags)
1447 self.assertEqual(msg + '\n\n' + tag_str, new_msg)
1448
1449 new_msg = patchstream.insert_tags(msg + '\n', tags)
1450 self.assertEqual(msg + '\n\n' + tag_str, new_msg)
1451
1452 msg += '\n\n' + signoff
1453 new_msg = patchstream.insert_tags(msg, tags)
1454 self.assertEqual(msg + '\n' + tag_str, new_msg)