blob: 85e7b475d904c14ea54c23fbf6dd5b18f7f141c0 [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 Glass3db916d2020-10-29 21:46:35 -060023from patman.series import Series
Simon Glassa997ea52020-04-17 18:09:04 -060024from patman import settings
Simon Glassba1b3b92025-02-09 14:26:00 -070025from u_boot_pylib import gitutil
Simon Glass131444f2023-02-23 18:18:04 -070026from u_boot_pylib import terminal
27from u_boot_pylib import tools
Simon Glassdf1bc5c2017-05-29 15:31:31 -060028
Tom Rini488ea972021-02-26 07:52:31 -050029import pygit2
30from patman import status
Simon Glassdf1bc5c2017-05-29 15:31:31 -060031
Maxim Cournoyer3ef23e92022-12-20 00:28:46 -050032PATMAN_DIR = pathlib.Path(__file__).parent
33TEST_DATA_DIR = PATMAN_DIR / 'test/'
Maxim Cournoyer0331edb2022-12-19 17:32:39 -050034
Maxim Cournoyer0331edb2022-12-19 17:32:39 -050035
Maxim Cournoyer3ef23e92022-12-20 00:28:46 -050036@contextlib.contextmanager
37def directory_excursion(directory):
38 """Change directory to `directory` for a limited to the context block."""
39 current = os.getcwd()
40 try:
41 os.chdir(directory)
42 yield
43 finally:
44 os.chdir(current)
45
Maxim Cournoyer0331edb2022-12-19 17:32:39 -050046
Simon Glassdf1bc5c2017-05-29 15:31:31 -060047class TestFunctional(unittest.TestCase):
Simon Glasseb209e52020-10-29 21:46:15 -060048 """Functional tests for checking that patman behaves correctly"""
Simon Glass06202d62020-10-29 21:46:27 -060049 leb = (b'Lord Edmund Blackadd\xc3\xabr <weasel@blackadder.org>'.
50 decode('utf-8'))
Simon Glass3b762cc2020-10-29 21:46:28 -060051 fred = 'Fred Bloggs <f.bloggs@napier.net>'
52 joe = 'Joe Bloggs <joe@napierwallies.co.nz>'
53 mary = 'Mary Bloggs <mary@napierwallies.co.nz>'
Simon Glass3db916d2020-10-29 21:46:35 -060054 commits = None
55 patches = None
Simon Glassed831d12025-04-29 07:22:10 -060056 verbosity = False
57 preserve_outdirs = False
58
59 @classmethod
60 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
61 toolpath=None, verbosity=None, no_capture=False):
62 """Accept arguments controlling test execution
63
64 Args:
65 preserve_indir: not used
66 preserve_outdir: Preserve the output directories used by tests.
67 Each test has its own, so this is normally only useful when
68 running a single test.
69 toolpath: not used
70 """
71 cls.preserve_outdirs = preserve_outdirs
72 cls.toolpath = toolpath
73 cls.verbosity = verbosity
74 cls.no_capture = no_capture
Simon Glass06202d62020-10-29 21:46:27 -060075
Simon Glassdf1bc5c2017-05-29 15:31:31 -060076 def setUp(self):
77 self.tmpdir = tempfile.mkdtemp(prefix='patman.')
Simon Glass54f1c5b2020-07-05 21:41:50 -060078 self.gitdir = os.path.join(self.tmpdir, 'git')
79 self.repo = None
Simon Glassdf1bc5c2017-05-29 15:31:31 -060080
81 def tearDown(self):
Simon Glassed831d12025-04-29 07:22:10 -060082 if self.preserve_outdirs:
83 print(f'Output dir: {self.tmpdir}')
84 else:
85 shutil.rmtree(self.tmpdir)
Simon Glass02811582022-01-29 14:14:18 -070086 terminal.set_print_test_mode(False)
Simon Glassdf1bc5c2017-05-29 15:31:31 -060087
88 @staticmethod
Simon Glasseb209e52020-10-29 21:46:15 -060089 def _get_path(fname):
90 """Get the path to a test file
91
92 Args:
93 fname (str): Filename to obtain
94
95 Returns:
96 str: Full path to file in the test directory
97 """
Maxim Cournoyer0331edb2022-12-19 17:32:39 -050098 return TEST_DATA_DIR / fname
Simon Glassdf1bc5c2017-05-29 15:31:31 -060099
100 @classmethod
Simon Glasseb209e52020-10-29 21:46:15 -0600101 def _get_text(cls, fname):
102 """Read a file as text
103
104 Args:
105 fname (str): Filename to read
106
107 Returns:
108 str: Contents of file
109 """
110 return open(cls._get_path(fname), encoding='utf-8').read()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600111
112 @classmethod
Simon Glasseb209e52020-10-29 21:46:15 -0600113 def _get_patch_name(cls, subject):
114 """Get the filename of a patch given its subject
115
116 Args:
117 subject (str): Patch subject
118
119 Returns:
120 str: Filename for that patch
121 """
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600122 fname = re.sub('[ :]', '-', subject)
123 return fname.replace('--', '-')
124
Simon Glasseb209e52020-10-29 21:46:15 -0600125 def _create_patches_for_test(self, series):
126 """Create patch files for use by tests
127
128 This copies patch files from the test directory as needed by the series
129
130 Args:
131 series (Series): Series containing commits to convert
132
133 Returns:
134 tuple:
135 str: Cover-letter filename, or None if none
136 fname_list: list of str, each a patch filename
137 """
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600138 cover_fname = None
139 fname_list = []
140 for i, commit in enumerate(series.commits):
Simon Glasseb209e52020-10-29 21:46:15 -0600141 clean_subject = self._get_patch_name(commit.subject)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600142 src_fname = '%04d-%s.patch' % (i + 1, clean_subject[:52])
143 fname = os.path.join(self.tmpdir, src_fname)
Simon Glasseb209e52020-10-29 21:46:15 -0600144 shutil.copy(self._get_path(src_fname), fname)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600145 fname_list.append(fname)
146 if series.get('cover'):
147 src_fname = '0000-cover-letter.patch'
148 cover_fname = os.path.join(self.tmpdir, src_fname)
149 fname = os.path.join(self.tmpdir, src_fname)
Simon Glasseb209e52020-10-29 21:46:15 -0600150 shutil.copy(self._get_path(src_fname), fname)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600151
152 return cover_fname, fname_list
153
Simon Glassd85bb8f2022-01-29 14:14:09 -0700154 def test_basic(self):
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600155 """Tests the basic flow of patman
156
157 This creates a series from some hard-coded patches build from a simple
158 tree with the following metadata in the top commit:
159
160 Series-to: u-boot
161 Series-prefix: RFC
Sean Andersondc1cd132021-10-22 19:07:04 -0400162 Series-postfix: some-branch
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600163 Series-cc: Stefan Brüns <stefan.bruens@rwth-aachen.de>
164 Cover-letter-cc: Lord Mëlchett <clergy@palace.gov>
Sean Andersoncf13b862020-05-04 16:28:36 -0400165 Series-version: 3
166 Patch-cc: fred
167 Series-process-log: sort, uniq
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600168 Series-changes: 4
169 - Some changes
Sean Andersoncf13b862020-05-04 16:28:36 -0400170 - Multi
171 line
172 change
173
174 Commit-changes: 2
175 - Changes only for this commit
176
Simon Glassf1aab6f2025-04-29 07:22:07 -0600177 Cover-changes: 4
Sean Andersoncf13b862020-05-04 16:28:36 -0400178 - Some notes for the cover letter
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600179
180 Cover-letter:
181 test: A test patch series
182 This is a test of how the cover
Sean Andersoncf13b862020-05-04 16:28:36 -0400183 letter
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600184 works
185 END
186
187 and this in the first commit:
188
Sean Andersoncf13b862020-05-04 16:28:36 -0400189 Commit-changes: 2
190 - second revision change
191
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600192 Series-notes:
193 some notes
194 about some things
195 from the first commit
196 END
197
198 Commit-notes:
199 Some notes about
200 the first commit
201 END
202
203 with the following commands:
204
205 git log -n2 --reverse >/path/to/tools/patman/test/test01.txt
206 git format-patch --subject-prefix RFC --cover-letter HEAD~2
207 mv 00* /path/to/tools/patman/test
208
209 It checks these aspects:
210 - git log can be processed by patchstream
211 - emailing patches uses the correct command
212 - CC file has information on each commit
213 - cover letter has the expected text and subject
214 - each patch has the correct subject
215 - dry-run information prints out correctly
216 - unicode is handled correctly
Sean Andersondc1cd132021-10-22 19:07:04 -0400217 - Series-to, Series-cc, Series-prefix, Series-postfix, Cover-letter
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600218 - Cover-letter-cc, Series-version, Series-changes, Series-notes
219 - Commit-notes
220 """
221 process_tags = True
Simon Glass1f975b92021-01-23 08:56:15 -0700222 ignore_bad_tags = False
Simon Glass4f817892019-05-14 15:53:53 -0600223 stefan = b'Stefan Br\xc3\xbcns <stefan.bruens@rwth-aachen.de>'.decode('utf-8')
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600224 rick = 'Richard III <richard@palace.gov>'
Simon Glass4f817892019-05-14 15:53:53 -0600225 mel = b'Lord M\xc3\xablchett <clergy@palace.gov>'.decode('utf-8')
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600226 add_maintainers = [stefan, rick]
227 dry_run = True
228 in_reply_to = mel
229 count = 2
230 settings.alias = {
Simon Glass95745aa2020-10-29 21:46:13 -0600231 'fdt': ['simon'],
232 'u-boot': ['u-boot@lists.denx.de'],
Simon Glass06202d62020-10-29 21:46:27 -0600233 'simon': [self.leb],
Simon Glass3b762cc2020-10-29 21:46:28 -0600234 'fred': [self.fred],
Sean Anderson25978092024-04-18 22:36:31 -0400235 'joe': [self.joe],
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600236 }
237
Simon Glasseb209e52020-10-29 21:46:15 -0600238 text = self._get_text('test01.txt')
Simon Glass93f61c02020-10-29 21:46:19 -0600239 series = patchstream.get_metadata_for_test(text)
Simon Glass414f1e02025-02-27 12:27:30 -0700240 series.base_commit = Commit('1a44532')
241 series.branch = 'mybranch'
Simon Glasseb209e52020-10-29 21:46:15 -0600242 cover_fname, args = self._create_patches_for_test(series)
Maxim Cournoyer3ef23e92022-12-20 00:28:46 -0500243 get_maintainer_script = str(pathlib.Path(__file__).parent.parent.parent
244 / 'get_maintainer.pl') + ' --norolestats'
Simon Glass14d64e32025-04-29 07:21:59 -0600245 with terminal.capture() as out:
Simon Glass93f61c02020-10-29 21:46:19 -0600246 patchstream.fix_patches(series, args)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600247 if cover_fname and series.get('cover'):
Simon Glass93f61c02020-10-29 21:46:19 -0600248 patchstream.insert_cover_letter(cover_fname, series, count)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600249 series.DoChecks()
250 cc_file = series.MakeCcFile(process_tags, cover_fname,
Chris Packhamb84fb482018-06-07 20:45:06 +1200251 not ignore_bad_tags, add_maintainers,
Maxim Cournoyer3ef23e92022-12-20 00:28:46 -0500252 None, get_maintainer_script)
Simon Glass761648b2022-01-29 14:14:11 -0700253 cmd = gitutil.email_patches(
Simon Glass95745aa2020-10-29 21:46:13 -0600254 series, cover_fname, args, dry_run, not ignore_bad_tags,
255 cc_file, in_reply_to=in_reply_to, thread=None)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600256 series.ShowActions(args, cmd, process_tags)
Simon Glassf544a2d2019-10-31 07:42:51 -0600257 cc_lines = open(cc_file, encoding='utf-8').read().splitlines()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600258 os.remove(cc_file)
259
Simon Glass42e3d392020-10-29 21:46:29 -0600260 lines = iter(out[0].getvalue().splitlines())
261 self.assertEqual('Cleaned %s patches' % len(series.commits),
262 next(lines))
263 self.assertEqual('Change log missing for v2', next(lines))
264 self.assertEqual('Change log missing for v3', next(lines))
265 self.assertEqual('Change log for unknown version v4', next(lines))
266 self.assertEqual("Alias 'pci' not found", next(lines))
Simon Glass620639c2023-03-08 10:52:54 -0800267 while next(lines) != 'Cc processing complete':
268 pass
Simon Glass42e3d392020-10-29 21:46:29 -0600269 self.assertIn('Dry run', next(lines))
270 self.assertEqual('', next(lines))
271 self.assertIn('Send a total of %d patches' % count, next(lines))
272 prev = next(lines)
273 for i, commit in enumerate(series.commits):
274 self.assertEqual(' %s' % args[i], prev)
275 while True:
276 prev = next(lines)
277 if 'Cc:' not in prev:
278 break
279 self.assertEqual('To: u-boot@lists.denx.de', prev)
Simon Glass9dfb3112020-11-08 20:36:18 -0700280 self.assertEqual('Cc: %s' % stefan, next(lines))
Simon Glass42e3d392020-10-29 21:46:29 -0600281 self.assertEqual('Version: 3', next(lines))
282 self.assertEqual('Prefix:\t RFC', next(lines))
Sean Andersondc1cd132021-10-22 19:07:04 -0400283 self.assertEqual('Postfix:\t some-branch', next(lines))
Simon Glass42e3d392020-10-29 21:46:29 -0600284 self.assertEqual('Cover: 4 lines', next(lines))
285 self.assertEqual(' Cc: %s' % self.fred, next(lines))
Sean Anderson25978092024-04-18 22:36:31 -0400286 self.assertEqual(' Cc: %s' % self.joe, next(lines))
Simon Glass9dfb3112020-11-08 20:36:18 -0700287 self.assertEqual(' Cc: %s' % self.leb,
Simon Glass42e3d392020-10-29 21:46:29 -0600288 next(lines))
Simon Glass9dfb3112020-11-08 20:36:18 -0700289 self.assertEqual(' Cc: %s' % mel, next(lines))
Simon Glass42e3d392020-10-29 21:46:29 -0600290 self.assertEqual(' Cc: %s' % rick, next(lines))
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600291 expected = ('Git command: git send-email --annotate '
292 '--in-reply-to="%s" --to "u-boot@lists.denx.de" '
Simon Glass1ee91c12020-11-03 13:54:10 -0700293 '--cc "%s" --cc-cmd "%s send --cc-cmd %s" %s %s'
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600294 % (in_reply_to, stefan, sys.argv[0], cc_file, cover_fname,
Simon Glass4f817892019-05-14 15:53:53 -0600295 ' '.join(args)))
Simon Glass9dfb3112020-11-08 20:36:18 -0700296 self.assertEqual(expected, next(lines))
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600297
Simon Glass9dfb3112020-11-08 20:36:18 -0700298 self.assertEqual(('%s %s\0%s' % (args[0], rick, stefan)), cc_lines[0])
Simon Glass95745aa2020-10-29 21:46:13 -0600299 self.assertEqual(
Sean Anderson25978092024-04-18 22:36:31 -0400300 '%s %s\0%s\0%s\0%s\0%s' % (args[1], self.fred, self.joe, self.leb,
301 rick, stefan),
Simon Glass9dfb3112020-11-08 20:36:18 -0700302 cc_lines[1])
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600303
304 expected = '''
305This is a test of how the cover
Sean Andersoncf13b862020-05-04 16:28:36 -0400306letter
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600307works
308
309some notes
310about some things
311from the first commit
312
313Changes in v4:
Sean Andersoncf13b862020-05-04 16:28:36 -0400314- Multi
315 line
316 change
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600317- Some changes
Sean Andersoncf13b862020-05-04 16:28:36 -0400318- Some notes for the cover letter
Sean Andersone45678c2024-04-18 22:36:32 -0400319- fdt: Correct cast for sandbox in fdtdec_setup_mem_size_base()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600320
321Simon Glass (2):
322 pci: Correct cast for sandbox
Siva Durga Prasad Paladugub3d55ea2018-07-16 15:56:11 +0530323 fdt: Correct cast for sandbox in fdtdec_setup_mem_size_base()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600324
325 cmd/pci.c | 3 ++-
326 fs/fat/fat.c | 1 +
327 lib/efi_loader/efi_memory.c | 1 +
328 lib/fdtdec.c | 3 ++-
329 4 files changed, 6 insertions(+), 2 deletions(-)
330
331--\x20
3322.7.4
333
Simon Glass414f1e02025-02-27 12:27:30 -0700334base-commit: 1a44532
335branch: mybranch
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600336'''
Simon Glassf544a2d2019-10-31 07:42:51 -0600337 lines = open(cover_fname, encoding='utf-8').read().splitlines()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600338 self.assertEqual(
Sean Andersondc1cd132021-10-22 19:07:04 -0400339 'Subject: [RFC PATCH some-branch v3 0/2] test: A test patch series',
Simon Glass95745aa2020-10-29 21:46:13 -0600340 lines[3])
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600341 self.assertEqual(expected.splitlines(), lines[7:])
342
343 for i, fname in enumerate(args):
Simon Glassf544a2d2019-10-31 07:42:51 -0600344 lines = open(fname, encoding='utf-8').read().splitlines()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600345 subject = [line for line in lines if line.startswith('Subject')]
346 self.assertEqual('Subject: [RFC %d/%d]' % (i + 1, count),
347 subject[0][:18])
Sean Andersoncf13b862020-05-04 16:28:36 -0400348
349 # Check that we got our commit notes
350 start = 0
351 expected = ''
352
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600353 if i == 0:
Sean Andersoncf13b862020-05-04 16:28:36 -0400354 start = 17
355 expected = '''---
356Some notes about
357the first commit
358
359(no changes since v2)
360
361Changes in v2:
362- second revision change'''
363 elif i == 1:
364 start = 17
365 expected = '''---
366
367Changes in v4:
368- Multi
369 line
370 change
Sean Andersone45678c2024-04-18 22:36:32 -0400371- New
Sean Andersoncf13b862020-05-04 16:28:36 -0400372- Some changes
373
374Changes in v2:
375- Changes only for this commit'''
376
377 if expected:
378 expected = expected.splitlines()
379 self.assertEqual(expected, lines[start:(start+len(expected))])
Simon Glass54f1c5b2020-07-05 21:41:50 -0600380
Simon Glassda1a6ec2025-03-28 07:02:20 -0600381 def test_base_commit(self):
382 """Test adding a base commit with no cover letter"""
383 orig_text = self._get_text('test01.txt')
384 pos = orig_text.index('commit 5ab48490f03051875ab13d288a4bf32b507d76fd')
385 text = orig_text[:pos]
386 series = patchstream.get_metadata_for_test(text)
387 series.base_commit = Commit('1a44532')
388 series.branch = 'mybranch'
389 cover_fname, args = self._create_patches_for_test(series)
390 self.assertFalse(cover_fname)
Simon Glass14d64e32025-04-29 07:21:59 -0600391 with terminal.capture() as out:
Simon Glassda1a6ec2025-03-28 07:02:20 -0600392 patchstream.fix_patches(series, args, insert_base_commit=True)
393 self.assertEqual('Cleaned 1 patch\n', out[0].getvalue())
394 lines = tools.read_file(args[0], binary=False).splitlines()
395 pos = lines.index('-- ')
396
397 # We expect these lines at the end:
398 # -- (with trailing space)
399 # 2.7.4
400 # (empty)
401 # base-commit: xxx
402 # branch: xxx
403 self.assertEqual('base-commit: 1a44532', lines[pos + 3])
404 self.assertEqual('branch: mybranch', lines[pos + 4])
405
Simon Glass54f1c5b2020-07-05 21:41:50 -0600406 def make_commit_with_file(self, subject, body, fname, text):
407 """Create a file and add it to the git repo with a new commit
408
409 Args:
410 subject (str): Subject for the commit
411 body (str): Body text of the commit
412 fname (str): Filename of file to create
413 text (str): Text to put into the file
414 """
415 path = os.path.join(self.gitdir, fname)
Simon Glass80025522022-01-29 14:14:04 -0700416 tools.write_file(path, text, binary=False)
Simon Glass54f1c5b2020-07-05 21:41:50 -0600417 index = self.repo.index
418 index.add(fname)
Simon Glass547cba62022-02-11 13:23:18 -0700419 # pylint doesn't seem to find this
420 # pylint: disable=E1101
Simon Glass95745aa2020-10-29 21:46:13 -0600421 author = pygit2.Signature('Test user', 'test@email.com')
Simon Glass54f1c5b2020-07-05 21:41:50 -0600422 committer = author
423 tree = index.write_tree()
424 message = subject + '\n' + body
425 self.repo.create_commit('HEAD', author, committer, message, tree,
426 [self.repo.head.target])
427
428 def make_git_tree(self):
429 """Make a simple git tree suitable for testing
430
431 It has three branches:
432 'base' has two commits: PCI, main
433 'first' has base as upstream and two more commits: I2C, SPI
434 'second' has base as upstream and three more: video, serial, bootm
435
436 Returns:
Simon Glasseb209e52020-10-29 21:46:15 -0600437 pygit2.Repository: repository
Simon Glass54f1c5b2020-07-05 21:41:50 -0600438 """
439 repo = pygit2.init_repository(self.gitdir)
440 self.repo = repo
441 new_tree = repo.TreeBuilder().write()
442
Simon Glass547cba62022-02-11 13:23:18 -0700443 # pylint doesn't seem to find this
444 # pylint: disable=E1101
Simon Glass54f1c5b2020-07-05 21:41:50 -0600445 author = pygit2.Signature('Test user', 'test@email.com')
446 committer = author
Simon Glasseb209e52020-10-29 21:46:15 -0600447 _ = repo.create_commit('HEAD', author, committer, 'Created master',
448 new_tree, [])
Simon Glass54f1c5b2020-07-05 21:41:50 -0600449
450 self.make_commit_with_file('Initial commit', '''
451Add a README
452
453''', 'README', '''This is the README file
454describing this project
455in very little detail''')
456
457 self.make_commit_with_file('pci: PCI implementation', '''
458Here is a basic PCI implementation
459
460''', 'pci.c', '''This is a file
461it has some contents
462and some more things''')
463 self.make_commit_with_file('main: Main program', '''
464Hello here is the second commit.
465''', 'main.c', '''This is the main file
466there is very little here
467but we can always add more later
468if we want to
469
470Series-to: u-boot
471Series-cc: Barry Crump <bcrump@whataroa.nz>
472''')
473 base_target = repo.revparse_single('HEAD')
474 self.make_commit_with_file('i2c: I2C things', '''
475This has some stuff to do with I2C
476''', 'i2c.c', '''And this is the file contents
477with some I2C-related things in it''')
478 self.make_commit_with_file('spi: SPI fixes', '''
479SPI needs some fixes
480and here they are
Simon Glassd0a0a582020-10-29 21:46:36 -0600481
482Signed-off-by: %s
483
484Series-to: u-boot
485Commit-notes:
486title of the series
487This is the cover letter for the series
488with various details
489END
490''' % self.leb, 'spi.c', '''Some fixes for SPI in this
Simon Glass54f1c5b2020-07-05 21:41:50 -0600491file to make SPI work
492better than before''')
493 first_target = repo.revparse_single('HEAD')
494
495 target = repo.revparse_single('HEAD~2')
Simon Glass547cba62022-02-11 13:23:18 -0700496 # pylint doesn't seem to find this
497 # pylint: disable=E1101
Simon Glass54f1c5b2020-07-05 21:41:50 -0600498 repo.reset(target.oid, pygit2.GIT_CHECKOUT_FORCE)
499 self.make_commit_with_file('video: Some video improvements', '''
500Fix up the video so that
501it looks more purple. Purple is
502a very nice colour.
503''', 'video.c', '''More purple here
504Purple and purple
505Even more purple
506Could not be any more purple''')
507 self.make_commit_with_file('serial: Add a serial driver', '''
508Here is the serial driver
509for my chip.
510
511Cover-letter:
512Series for my board
513This series implements support
514for my glorious board.
515END
Simon Glassa80986c2020-10-29 21:46:16 -0600516Series-links: 183237
Simon Glass54f1c5b2020-07-05 21:41:50 -0600517''', 'serial.c', '''The code for the
518serial driver is here''')
519 self.make_commit_with_file('bootm: Make it boot', '''
520This makes my board boot
521with a fix to the bootm
522command
523''', 'bootm.c', '''Fix up the bootm
524command to make the code as
525complicated as possible''')
526 second_target = repo.revparse_single('HEAD')
527
528 repo.branches.local.create('first', first_target)
529 repo.config.set_multivar('branch.first.remote', '', '.')
530 repo.config.set_multivar('branch.first.merge', '', 'refs/heads/base')
531
532 repo.branches.local.create('second', second_target)
533 repo.config.set_multivar('branch.second.remote', '', '.')
534 repo.config.set_multivar('branch.second.merge', '', 'refs/heads/base')
535
536 repo.branches.local.create('base', base_target)
537 return repo
538
Simon Glassd85bb8f2022-01-29 14:14:09 -0700539 def test_branch(self):
Simon Glass54f1c5b2020-07-05 21:41:50 -0600540 """Test creating patches from a branch"""
541 repo = self.make_git_tree()
542 target = repo.lookup_reference('refs/heads/first')
Simon Glass547cba62022-02-11 13:23:18 -0700543 # pylint doesn't seem to find this
544 # pylint: disable=E1101
Simon Glass54f1c5b2020-07-05 21:41:50 -0600545 self.repo.checkout(target, strategy=pygit2.GIT_CHECKOUT_FORCE)
546 control.setup()
Heinrich Schuchardtd01d6672023-04-20 20:07:29 +0200547 orig_dir = os.getcwd()
Simon Glass54f1c5b2020-07-05 21:41:50 -0600548 try:
Simon Glass54f1c5b2020-07-05 21:41:50 -0600549 os.chdir(self.gitdir)
550
551 # Check that it can detect the current branch
Simon Glass761648b2022-01-29 14:14:11 -0700552 self.assertEqual(2, gitutil.count_commits_to_branch(None))
Simon Glass54f1c5b2020-07-05 21:41:50 -0600553 col = terminal.Color()
Simon Glass14d64e32025-04-29 07:21:59 -0600554 with terminal.capture() as _:
Simon Glass54f1c5b2020-07-05 21:41:50 -0600555 _, cover_fname, patch_files = control.prepare_patches(
Simon Glassb3bf4e12020-07-05 21:41:52 -0600556 col, branch=None, count=-1, start=0, end=0,
Philipp Tomsich858531a2020-11-24 18:14:52 +0100557 ignore_binary=False, signoff=True)
Simon Glass54f1c5b2020-07-05 21:41:50 -0600558 self.assertIsNone(cover_fname)
559 self.assertEqual(2, len(patch_files))
Simon Glass2eb4da72020-07-05 21:41:51 -0600560
561 # Check that it can detect a different branch
Simon Glass761648b2022-01-29 14:14:11 -0700562 self.assertEqual(3, gitutil.count_commits_to_branch('second'))
Simon Glass14d64e32025-04-29 07:21:59 -0600563 with terminal.capture() as _:
Simon Glass414f1e02025-02-27 12:27:30 -0700564 series, cover_fname, patch_files = control.prepare_patches(
Simon Glassb3bf4e12020-07-05 21:41:52 -0600565 col, branch='second', count=-1, start=0, end=0,
Philipp Tomsich858531a2020-11-24 18:14:52 +0100566 ignore_binary=False, signoff=True)
Simon Glass2eb4da72020-07-05 21:41:51 -0600567 self.assertIsNotNone(cover_fname)
568 self.assertEqual(3, len(patch_files))
Simon Glassb3bf4e12020-07-05 21:41:52 -0600569
Simon Glass414f1e02025-02-27 12:27:30 -0700570 cover = tools.read_file(cover_fname, binary=False)
571 lines = cover.splitlines()[-2:]
572 base = repo.lookup_reference('refs/heads/base').target
573 self.assertEqual(f'base-commit: {base}', lines[0])
574 self.assertEqual('branch: second', lines[1])
575
Simon Glassda1a6ec2025-03-28 07:02:20 -0600576 # Make sure that the base-commit is not present when it is in the
577 # cover letter
578 for fname in patch_files:
579 self.assertNotIn(b'base-commit:', tools.read_file(fname))
580
Simon Glassb3bf4e12020-07-05 21:41:52 -0600581 # Check that it can skip patches at the end
Simon Glass14d64e32025-04-29 07:21:59 -0600582 with terminal.capture() as _:
Simon Glassb3bf4e12020-07-05 21:41:52 -0600583 _, cover_fname, patch_files = control.prepare_patches(
584 col, branch='second', count=-1, start=0, end=1,
Philipp Tomsich858531a2020-11-24 18:14:52 +0100585 ignore_binary=False, signoff=True)
Simon Glassb3bf4e12020-07-05 21:41:52 -0600586 self.assertIsNotNone(cover_fname)
587 self.assertEqual(2, len(patch_files))
Simon Glass414f1e02025-02-27 12:27:30 -0700588
589 cover = tools.read_file(cover_fname, binary=False)
590 lines = cover.splitlines()[-2:]
591 base2 = repo.lookup_reference('refs/heads/second')
592 ref = base2.peel(pygit2.GIT_OBJ_COMMIT).parents[0].parents[0].id
593 self.assertEqual(f'base-commit: {ref}', lines[0])
594 self.assertEqual('branch: second', lines[1])
Simon Glass54f1c5b2020-07-05 21:41:50 -0600595 finally:
596 os.chdir(orig_dir)
Simon Glass06202d62020-10-29 21:46:27 -0600597
Maxim Cournoyer3ef23e92022-12-20 00:28:46 -0500598 def test_custom_get_maintainer_script(self):
599 """Validate that a custom get_maintainer script gets used."""
600 self.make_git_tree()
601 with directory_excursion(self.gitdir):
602 # Setup git.
603 os.environ['GIT_CONFIG_GLOBAL'] = '/dev/null'
604 os.environ['GIT_CONFIG_SYSTEM'] = '/dev/null'
605 tools.run('git', 'config', 'user.name', 'Dummy')
606 tools.run('git', 'config', 'user.email', 'dumdum@dummy.com')
607 tools.run('git', 'branch', 'upstream')
608 tools.run('git', 'branch', '--set-upstream-to=upstream')
609 tools.run('git', 'add', '.')
610 tools.run('git', 'commit', '-m', 'new commit')
611
612 # Setup patman configuration.
613 with open('.patman', 'w', buffering=1) as f:
614 f.write('[settings]\n'
615 'get_maintainer_script: dummy-script.sh\n'
Sean Andersona06df742024-04-18 22:36:30 -0400616 'check_patch: False\n'
617 'add_maintainers: True\n')
Maxim Cournoyer3ef23e92022-12-20 00:28:46 -0500618 with open('dummy-script.sh', 'w', buffering=1) as f:
619 f.write('#!/usr/bin/env python\n'
620 'print("hello@there.com")\n')
621 os.chmod('dummy-script.sh', 0x555)
622
623 # Finally, do the test
Simon Glass14d64e32025-04-29 07:21:59 -0600624 with terminal.capture():
Maxim Cournoyer3ef23e92022-12-20 00:28:46 -0500625 output = tools.run(PATMAN_DIR / 'patman', '--dry-run')
626 # Assert the email address is part of the dry-run
627 # output.
628 self.assertIn('hello@there.com', output)
629
Simon Glassd85bb8f2022-01-29 14:14:09 -0700630 def test_tags(self):
Simon Glass06202d62020-10-29 21:46:27 -0600631 """Test collection of tags in a patchstream"""
632 text = '''This is a patch
633
634Signed-off-by: Terminator
Simon Glass3b762cc2020-10-29 21:46:28 -0600635Reviewed-by: %s
636Reviewed-by: %s
Simon Glass06202d62020-10-29 21:46:27 -0600637Tested-by: %s
Simon Glass3b762cc2020-10-29 21:46:28 -0600638''' % (self.joe, self.mary, self.leb)
Simon Glass06202d62020-10-29 21:46:27 -0600639 pstrm = PatchStream.process_text(text)
640 self.assertEqual(pstrm.commit.rtags, {
Simon Glass3b762cc2020-10-29 21:46:28 -0600641 'Reviewed-by': {self.joe, self.mary},
Simon Glass06202d62020-10-29 21:46:27 -0600642 'Tested-by': {self.leb}})
Simon Glass3b762cc2020-10-29 21:46:28 -0600643
Simon Glassd85bb8f2022-01-29 14:14:09 -0700644 def test_invalid_tag(self):
Patrick Delaunay6bbdd0c2021-07-22 16:51:42 +0200645 """Test invalid tag in a patchstream"""
646 text = '''This is a patch
647
648Serie-version: 2
649'''
650 with self.assertRaises(ValueError) as exc:
651 pstrm = PatchStream.process_text(text)
652 self.assertEqual("Line 3: Invalid tag = 'Serie-version: 2'",
653 str(exc.exception))
654
Simon Glassd85bb8f2022-01-29 14:14:09 -0700655 def test_missing_end(self):
Simon Glass3b762cc2020-10-29 21:46:28 -0600656 """Test a missing END tag"""
657 text = '''This is a patch
658
659Cover-letter:
660This is the title
661missing END after this line
662Signed-off-by: Fred
663'''
664 pstrm = PatchStream.process_text(text)
665 self.assertEqual(["Missing 'END' in section 'cover'"],
666 pstrm.commit.warn)
667
Simon Glassd85bb8f2022-01-29 14:14:09 -0700668 def test_missing_blank_line(self):
Simon Glass3b762cc2020-10-29 21:46:28 -0600669 """Test a missing blank line after a tag"""
670 text = '''This is a patch
671
672Series-changes: 2
673- First line of changes
674- Missing blank line after this line
675Signed-off-by: Fred
676'''
677 pstrm = PatchStream.process_text(text)
678 self.assertEqual(["Missing 'blank line' in section 'Series-changes'"],
679 pstrm.commit.warn)
680
Simon Glassd85bb8f2022-01-29 14:14:09 -0700681 def test_invalid_commit_tag(self):
Simon Glass3b762cc2020-10-29 21:46:28 -0600682 """Test an invalid Commit-xxx tag"""
683 text = '''This is a patch
684
685Commit-fred: testing
686'''
687 pstrm = PatchStream.process_text(text)
688 self.assertEqual(["Line 3: Ignoring Commit-fred"], pstrm.commit.warn)
689
Simon Glassd85bb8f2022-01-29 14:14:09 -0700690 def test_self_test(self):
Simon Glass3b762cc2020-10-29 21:46:28 -0600691 """Test a tested by tag by this user"""
692 test_line = 'Tested-by: %s@napier.com' % os.getenv('USER')
693 text = '''This is a patch
694
695%s
696''' % test_line
697 pstrm = PatchStream.process_text(text)
698 self.assertEqual(["Ignoring '%s'" % test_line], pstrm.commit.warn)
699
Simon Glassd85bb8f2022-01-29 14:14:09 -0700700 def test_space_before_tab(self):
Simon Glass3b762cc2020-10-29 21:46:28 -0600701 """Test a space before a tab"""
702 text = '''This is a patch
703
704+ \tSomething
705'''
706 pstrm = PatchStream.process_text(text)
707 self.assertEqual(["Line 3/0 has space before tab"], pstrm.commit.warn)
708
Simon Glassd85bb8f2022-01-29 14:14:09 -0700709 def test_lines_after_test(self):
Simon Glass3b762cc2020-10-29 21:46:28 -0600710 """Test detecting lines after TEST= line"""
711 text = '''This is a patch
712
713TEST=sometest
714more lines
715here
716'''
717 pstrm = PatchStream.process_text(text)
718 self.assertEqual(["Found 2 lines after TEST="], pstrm.commit.warn)
719
Simon Glassd85bb8f2022-01-29 14:14:09 -0700720 def test_blank_line_at_end(self):
Simon Glass3b762cc2020-10-29 21:46:28 -0600721 """Test detecting a blank line at the end of a file"""
722 text = '''This is a patch
723
724diff --git a/lib/fdtdec.c b/lib/fdtdec.c
725index c072e54..942244f 100644
726--- a/lib/fdtdec.c
727+++ b/lib/fdtdec.c
728@@ -1200,7 +1200,8 @@ int fdtdec_setup_mem_size_base(void)
729 }
730
731 gd->ram_size = (phys_size_t)(res.end - res.start + 1);
732- debug("%s: Initial DRAM size %llx\n", __func__, (u64)gd->ram_size);
733+ debug("%s: Initial DRAM size %llx\n", __func__,
734+ (unsigned long long)gd->ram_size);
735+
736diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
737
738--
7392.7.4
740
741 '''
742 pstrm = PatchStream.process_text(text)
743 self.assertEqual(
744 ["Found possible blank line(s) at end of file 'lib/fdtdec.c'"],
745 pstrm.commit.warn)
Simon Glass1c1f2072020-10-29 21:46:34 -0600746
Simon Glassd85bb8f2022-01-29 14:14:09 -0700747 def test_no_upstream(self):
Simon Glass1c1f2072020-10-29 21:46:34 -0600748 """Test CountCommitsToBranch when there is no upstream"""
749 repo = self.make_git_tree()
750 target = repo.lookup_reference('refs/heads/base')
Simon Glass547cba62022-02-11 13:23:18 -0700751 # pylint doesn't seem to find this
752 # pylint: disable=E1101
Simon Glass1c1f2072020-10-29 21:46:34 -0600753 self.repo.checkout(target, strategy=pygit2.GIT_CHECKOUT_FORCE)
754
755 # Check that it can detect the current branch
Heinrich Schuchardtd01d6672023-04-20 20:07:29 +0200756 orig_dir = os.getcwd()
Simon Glass1c1f2072020-10-29 21:46:34 -0600757 try:
Simon Glass1c1f2072020-10-29 21:46:34 -0600758 os.chdir(self.gitdir)
759 with self.assertRaises(ValueError) as exc:
Simon Glass761648b2022-01-29 14:14:11 -0700760 gitutil.count_commits_to_branch(None)
Simon Glass1c1f2072020-10-29 21:46:34 -0600761 self.assertIn(
762 "Failed to determine upstream: fatal: no upstream configured for branch 'base'",
763 str(exc.exception))
764 finally:
765 os.chdir(orig_dir)
Simon Glass3db916d2020-10-29 21:46:35 -0600766
767 @staticmethod
Simon Glassf9b03cf2020-11-03 13:54:14 -0700768 def _fake_patchwork(url, subpath):
Simon Glass3db916d2020-10-29 21:46:35 -0600769 """Fake Patchwork server for the function below
770
771 This handles accessing a series, providing a list consisting of a
772 single patch
Simon Glassf9b03cf2020-11-03 13:54:14 -0700773
774 Args:
775 url (str): URL of patchwork server
776 subpath (str): URL subpath to use
Simon Glass3db916d2020-10-29 21:46:35 -0600777 """
778 re_series = re.match(r'series/(\d*)/$', subpath)
779 if re_series:
780 series_num = re_series.group(1)
781 if series_num == '1234':
782 return {'patches': [
783 {'id': '1', 'name': 'Some patch'}]}
784 raise ValueError('Fake Patchwork does not understand: %s' % subpath)
785
Simon Glassd85bb8f2022-01-29 14:14:09 -0700786 def test_status_mismatch(self):
Simon Glass3db916d2020-10-29 21:46:35 -0600787 """Test Patchwork patches not matching the series"""
788 series = Series()
789
Simon Glass14d64e32025-04-29 07:21:59 -0600790 with terminal.capture() as (_, err):
Simon Glassf9b03cf2020-11-03 13:54:14 -0700791 status.collect_patches(series, 1234, None, self._fake_patchwork)
Simon Glass3db916d2020-10-29 21:46:35 -0600792 self.assertIn('Warning: Patchwork reports 1 patches, series has 0',
793 err.getvalue())
794
Simon Glassd85bb8f2022-01-29 14:14:09 -0700795 def test_status_read_patch(self):
Simon Glass3db916d2020-10-29 21:46:35 -0600796 """Test handling a single patch in Patchwork"""
797 series = Series()
798 series.commits = [Commit('abcd')]
799
Simon Glassf9b03cf2020-11-03 13:54:14 -0700800 patches = status.collect_patches(series, 1234, None,
801 self._fake_patchwork)
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"""
809 patch = status.Patch('1')
810
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
878 patch1 = status.Patch('1')
879 patch1.subject = 'Subject 1'
880 patch2 = status.Patch('2')
881 patch2.subject = 'Subject 2'
882 patch3 = status.Patch('3')
883 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 Glassf9b03cf2020-11-03 13:54:14 -0700944 def _fake_patchwork2(self, url, 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:
951 url (str): URL of patchwork server
952 subpath (str): URL subpath to use
Simon Glass3db916d2020-10-29 21:46:35 -0600953 """
954 re_series = re.match(r'series/(\d*)/$', subpath)
955 re_patch = re.match(r'patches/(\d*)/$', subpath)
956 re_comments = re.match(r'patches/(\d*)/comments/$', subpath)
957 if re_series:
958 series_num = re_series.group(1)
959 if series_num == '1234':
960 return {'patches': self.patches}
961 elif re_patch:
962 patch_num = int(re_patch.group(1))
963 patch = self.patches[patch_num - 1]
964 return patch
965 elif re_comments:
966 patch_num = int(re_comments.group(1))
967 patch = self.patches[patch_num - 1]
968 return patch.comments
969 raise ValueError('Fake Patchwork does not understand: %s' % subpath)
970
Simon Glassd85bb8f2022-01-29 14:14:09 -0700971 def test_find_new_responses(self):
Simon Glass3db916d2020-10-29 21:46:35 -0600972 """Test operation of find_new_responses()"""
973 commit1 = Commit('abcd')
974 commit1.subject = 'Subject 1'
975 commit2 = Commit('ef12')
976 commit2.subject = 'Subject 2'
977
978 patch1 = status.Patch('1')
979 patch1.parse_subject('[1/2] Subject 1')
980 patch1.name = patch1.raw_subject
981 patch1.content = 'This is my patch content'
982 comment1a = {'content': 'Reviewed-by: %s\n' % self.joe}
983
984 patch1.comments = [comment1a]
985
986 patch2 = status.Patch('2')
987 patch2.parse_subject('[2/2] Subject 2')
988 patch2.name = patch2.raw_subject
989 patch2.content = 'Some other patch content'
990 comment2a = {
991 'content': 'Reviewed-by: %s\nTested-by: %s\n' %
992 (self.mary, self.leb)}
993 comment2b = {'content': 'Reviewed-by: %s' % self.fred}
994 patch2.comments = [comment2a, comment2b]
995
996 # This test works by setting up commits and patch for use by the fake
997 # Rest API function _fake_patchwork2(). It calls various functions in
998 # the status module after setting up tags in the commits, checking that
999 # things behaves as expected
1000 self.commits = [commit1, commit2]
1001 self.patches = [patch1, patch2]
1002 count = 2
1003 new_rtag_list = [None] * count
Simon Glass2112d072020-10-29 21:46:38 -06001004 review_list = [None, None]
Simon Glass3db916d2020-10-29 21:46:35 -06001005
1006 # Check that the tags are picked up on the first patch
Simon Glass2112d072020-10-29 21:46:38 -06001007 status.find_new_responses(new_rtag_list, review_list, 0, commit1,
Simon Glassf9b03cf2020-11-03 13:54:14 -07001008 patch1, None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -06001009 self.assertEqual(new_rtag_list[0], {'Reviewed-by': {self.joe}})
1010
1011 # Now the second patch
Simon Glass2112d072020-10-29 21:46:38 -06001012 status.find_new_responses(new_rtag_list, review_list, 1, commit2,
Simon Glassf9b03cf2020-11-03 13:54:14 -07001013 patch2, None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -06001014 self.assertEqual(new_rtag_list[1], {
1015 'Reviewed-by': {self.mary, self.fred},
1016 'Tested-by': {self.leb}})
1017
1018 # Now add some tags to the commit, which means they should not appear as
1019 # 'new' tags when scanning comments
1020 new_rtag_list = [None] * count
1021 commit1.rtags = {'Reviewed-by': {self.joe}}
Simon Glass2112d072020-10-29 21:46:38 -06001022 status.find_new_responses(new_rtag_list, review_list, 0, commit1,
Simon Glassf9b03cf2020-11-03 13:54:14 -07001023 patch1, None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -06001024 self.assertEqual(new_rtag_list[0], {})
1025
1026 # For the second commit, add Ed and Fred, so only Mary should be left
1027 commit2.rtags = {
1028 'Tested-by': {self.leb},
1029 'Reviewed-by': {self.fred}}
Simon Glass2112d072020-10-29 21:46:38 -06001030 status.find_new_responses(new_rtag_list, review_list, 1, commit2,
Simon Glassf9b03cf2020-11-03 13:54:14 -07001031 patch2, None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -06001032 self.assertEqual(new_rtag_list[1], {'Reviewed-by': {self.mary}})
1033
1034 # Check that the output patches expectations:
1035 # 1 Subject 1
1036 # Reviewed-by: Joe Bloggs <joe@napierwallies.co.nz>
1037 # 2 Subject 2
1038 # Tested-by: Lord Edmund Blackaddër <weasel@blackadder.org>
1039 # Reviewed-by: Fred Bloggs <f.bloggs@napier.net>
1040 # + Reviewed-by: Mary Bloggs <mary@napierwallies.co.nz>
1041 # 1 new response available in patchwork
1042
1043 series = Series()
1044 series.commits = [commit1, commit2]
Simon Glass02811582022-01-29 14:14:18 -07001045 terminal.set_print_test_mode()
Simon Glass2112d072020-10-29 21:46:38 -06001046 status.check_patchwork_status(series, '1234', None, None, False, False,
Simon Glassf9b03cf2020-11-03 13:54:14 -07001047 None, self._fake_patchwork2)
Simon Glass02811582022-01-29 14:14:18 -07001048 lines = iter(terminal.get_print_test_lines())
Simon Glass3db916d2020-10-29 21:46:35 -06001049 col = terminal.Color()
1050 self.assertEqual(terminal.PrintLine(' 1 Subject 1', col.BLUE),
1051 next(lines))
1052 self.assertEqual(
1053 terminal.PrintLine(' Reviewed-by: ', col.GREEN, newline=False,
1054 bright=False),
1055 next(lines))
1056 self.assertEqual(terminal.PrintLine(self.joe, col.WHITE, bright=False),
1057 next(lines))
1058
1059 self.assertEqual(terminal.PrintLine(' 2 Subject 2', col.BLUE),
1060 next(lines))
1061 self.assertEqual(
Simon Glass2112d072020-10-29 21:46:38 -06001062 terminal.PrintLine(' Reviewed-by: ', col.GREEN, newline=False,
Simon Glass3db916d2020-10-29 21:46:35 -06001063 bright=False),
1064 next(lines))
Simon Glass2112d072020-10-29 21:46:38 -06001065 self.assertEqual(terminal.PrintLine(self.fred, col.WHITE, bright=False),
Simon Glass3db916d2020-10-29 21:46:35 -06001066 next(lines))
1067 self.assertEqual(
Simon Glass2112d072020-10-29 21:46:38 -06001068 terminal.PrintLine(' Tested-by: ', col.GREEN, newline=False,
Simon Glass3db916d2020-10-29 21:46:35 -06001069 bright=False),
1070 next(lines))
Simon Glass2112d072020-10-29 21:46:38 -06001071 self.assertEqual(terminal.PrintLine(self.leb, col.WHITE, bright=False),
Simon Glass3db916d2020-10-29 21:46:35 -06001072 next(lines))
1073 self.assertEqual(
1074 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
1075 next(lines))
1076 self.assertEqual(terminal.PrintLine(self.mary, col.WHITE),
1077 next(lines))
1078 self.assertEqual(terminal.PrintLine(
Simon Glassd0a0a582020-10-29 21:46:36 -06001079 '1 new response available in patchwork (use -d to write them to a new branch)',
1080 None), next(lines))
1081
Simon Glassf9b03cf2020-11-03 13:54:14 -07001082 def _fake_patchwork3(self, url, subpath):
Simon Glassd0a0a582020-10-29 21:46:36 -06001083 """Fake Patchwork server for the function below
1084
1085 This handles accessing series, patches and comments, providing the data
1086 in self.patches to the caller
Simon Glassf9b03cf2020-11-03 13:54:14 -07001087
1088 Args:
1089 url (str): URL of patchwork server
1090 subpath (str): URL subpath to use
Simon Glassd0a0a582020-10-29 21:46:36 -06001091 """
1092 re_series = re.match(r'series/(\d*)/$', subpath)
1093 re_patch = re.match(r'patches/(\d*)/$', subpath)
1094 re_comments = re.match(r'patches/(\d*)/comments/$', subpath)
1095 if re_series:
1096 series_num = re_series.group(1)
1097 if series_num == '1234':
1098 return {'patches': self.patches}
1099 elif re_patch:
1100 patch_num = int(re_patch.group(1))
1101 patch = self.patches[patch_num - 1]
1102 return patch
1103 elif re_comments:
1104 patch_num = int(re_comments.group(1))
1105 patch = self.patches[patch_num - 1]
1106 return patch.comments
1107 raise ValueError('Fake Patchwork does not understand: %s' % subpath)
1108
Simon Glassd85bb8f2022-01-29 14:14:09 -07001109 def test_create_branch(self):
Simon Glassd0a0a582020-10-29 21:46:36 -06001110 """Test operation of create_branch()"""
1111 repo = self.make_git_tree()
1112 branch = 'first'
1113 dest_branch = 'first2'
1114 count = 2
1115 gitdir = os.path.join(self.gitdir, '.git')
1116
1117 # Set up the test git tree. We use branch 'first' which has two commits
1118 # in it
1119 series = patchstream.get_metadata_for_list(branch, gitdir, count)
1120 self.assertEqual(2, len(series.commits))
1121
1122 patch1 = status.Patch('1')
1123 patch1.parse_subject('[1/2] %s' % series.commits[0].subject)
1124 patch1.name = patch1.raw_subject
1125 patch1.content = 'This is my patch content'
1126 comment1a = {'content': 'Reviewed-by: %s\n' % self.joe}
1127
1128 patch1.comments = [comment1a]
1129
1130 patch2 = status.Patch('2')
1131 patch2.parse_subject('[2/2] %s' % series.commits[1].subject)
1132 patch2.name = patch2.raw_subject
1133 patch2.content = 'Some other patch content'
1134 comment2a = {
1135 'content': 'Reviewed-by: %s\nTested-by: %s\n' %
1136 (self.mary, self.leb)}
1137 comment2b = {
1138 'content': 'Reviewed-by: %s' % self.fred}
1139 patch2.comments = [comment2a, comment2b]
1140
1141 # This test works by setting up patches for use by the fake Rest API
1142 # function _fake_patchwork3(). The fake patch comments above should
1143 # result in new review tags that are collected and added to the commits
1144 # created in the destination branch.
1145 self.patches = [patch1, patch2]
1146 count = 2
1147
1148 # Expected output:
1149 # 1 i2c: I2C things
1150 # + Reviewed-by: Joe Bloggs <joe@napierwallies.co.nz>
1151 # 2 spi: SPI fixes
1152 # + Reviewed-by: Fred Bloggs <f.bloggs@napier.net>
1153 # + Reviewed-by: Mary Bloggs <mary@napierwallies.co.nz>
1154 # + Tested-by: Lord Edmund Blackaddër <weasel@blackadder.org>
1155 # 4 new responses available in patchwork
1156 # 4 responses added from patchwork into new branch 'first2'
1157 # <unittest.result.TestResult run=8 errors=0 failures=0>
1158
Simon Glass02811582022-01-29 14:14:18 -07001159 terminal.set_print_test_mode()
Simon Glassd0a0a582020-10-29 21:46:36 -06001160 status.check_patchwork_status(series, '1234', branch, dest_branch,
Simon Glassf9b03cf2020-11-03 13:54:14 -07001161 False, False, None, self._fake_patchwork3,
1162 repo)
Simon Glass02811582022-01-29 14:14:18 -07001163 lines = terminal.get_print_test_lines()
Simon Glassd0a0a582020-10-29 21:46:36 -06001164 self.assertEqual(12, len(lines))
1165 self.assertEqual(
1166 "4 responses added from patchwork into new branch 'first2'",
1167 lines[11].text)
1168
1169 # Check that the destination branch has the new tags
1170 new_series = patchstream.get_metadata_for_list(dest_branch, gitdir,
1171 count)
1172 self.assertEqual(
1173 {'Reviewed-by': {self.joe}},
1174 new_series.commits[0].rtags)
1175 self.assertEqual(
1176 {'Tested-by': {self.leb},
1177 'Reviewed-by': {self.fred, self.mary}},
1178 new_series.commits[1].rtags)
1179
1180 # Now check the actual test of the first commit message. We expect to
1181 # see the new tags immediately below the old ones.
1182 stdout = patchstream.get_list(dest_branch, count=count, git_dir=gitdir)
1183 lines = iter([line.strip() for line in stdout.splitlines()
1184 if '-by:' in line])
1185
1186 # First patch should have the review tag
1187 self.assertEqual('Reviewed-by: %s' % self.joe, next(lines))
1188
1189 # Second patch should have the sign-off then the tested-by and two
1190 # reviewed-by tags
1191 self.assertEqual('Signed-off-by: %s' % self.leb, next(lines))
1192 self.assertEqual('Reviewed-by: %s' % self.fred, next(lines))
1193 self.assertEqual('Reviewed-by: %s' % self.mary, next(lines))
1194 self.assertEqual('Tested-by: %s' % self.leb, next(lines))
Simon Glassda8a2922020-10-29 21:46:37 -06001195
Simon Glassd85bb8f2022-01-29 14:14:09 -07001196 def test_parse_snippets(self):
Simon Glassda8a2922020-10-29 21:46:37 -06001197 """Test parsing of review snippets"""
1198 text = '''Hi Fred,
1199
1200This is a comment from someone.
1201
1202Something else
1203
1204On some recent date, Fred wrote:
1205> This is why I wrote the patch
1206> so here it is
1207
1208Now a comment about the commit message
1209A little more to say
1210
1211Even more
1212
1213> diff --git a/file.c b/file.c
1214> Some more code
1215> Code line 2
1216> Code line 3
1217> Code line 4
1218> Code line 5
1219> Code line 6
1220> Code line 7
1221> Code line 8
1222> Code line 9
1223
1224And another comment
1225
Simon Glassd85bb8f2022-01-29 14:14:09 -07001226> @@ -153,8 +143,13 @@ def check_patch(fname, show_types=False):
Simon Glassda8a2922020-10-29 21:46:37 -06001227> further down on the file
1228> and more code
1229> +Addition here
1230> +Another addition here
1231> codey
1232> more codey
1233
1234and another thing in same file
1235
1236> @@ -253,8 +243,13 @@
1237> with no function context
1238
1239one more thing
1240
1241> diff --git a/tools/patman/main.py b/tools/patman/main.py
1242> +line of code
1243now a very long comment in a different file
1244line2
1245line3
1246line4
1247line5
1248line6
1249line7
1250line8
1251'''
1252 pstrm = PatchStream.process_text(text, True)
1253 self.assertEqual([], pstrm.commit.warn)
1254
1255 # We expect to the filename and up to 5 lines of code context before
1256 # each comment. The 'On xxx wrote:' bit should be removed.
1257 self.assertEqual(
1258 [['Hi Fred,',
1259 'This is a comment from someone.',
1260 'Something else'],
1261 ['> This is why I wrote the patch',
1262 '> so here it is',
1263 'Now a comment about the commit message',
1264 'A little more to say', 'Even more'],
1265 ['> File: file.c', '> Code line 5', '> Code line 6',
1266 '> Code line 7', '> Code line 8', '> Code line 9',
1267 'And another comment'],
1268 ['> File: file.c',
Simon Glassd85bb8f2022-01-29 14:14:09 -07001269 '> Line: 153 / 143: def check_patch(fname, show_types=False):',
Simon Glassda8a2922020-10-29 21:46:37 -06001270 '> and more code', '> +Addition here', '> +Another addition here',
1271 '> codey', '> more codey', 'and another thing in same file'],
1272 ['> File: file.c', '> Line: 253 / 243',
1273 '> with no function context', 'one more thing'],
1274 ['> File: tools/patman/main.py', '> +line of code',
1275 'now a very long comment in a different file',
1276 'line2', 'line3', 'line4', 'line5', 'line6', 'line7', 'line8']],
1277 pstrm.snippets)
Simon Glass2112d072020-10-29 21:46:38 -06001278
Simon Glassd85bb8f2022-01-29 14:14:09 -07001279 def test_review_snippets(self):
Simon Glass2112d072020-10-29 21:46:38 -06001280 """Test showing of review snippets"""
1281 def _to_submitter(who):
1282 m_who = re.match('(.*) <(.*)>', who)
1283 return {
1284 'name': m_who.group(1),
1285 'email': m_who.group(2)
1286 }
1287
1288 commit1 = Commit('abcd')
1289 commit1.subject = 'Subject 1'
1290 commit2 = Commit('ef12')
1291 commit2.subject = 'Subject 2'
1292
1293 patch1 = status.Patch('1')
1294 patch1.parse_subject('[1/2] Subject 1')
1295 patch1.name = patch1.raw_subject
1296 patch1.content = 'This is my patch content'
1297 comment1a = {'submitter': _to_submitter(self.joe),
1298 'content': '''Hi Fred,
1299
1300On some date Fred wrote:
1301
1302> diff --git a/file.c b/file.c
1303> Some code
1304> and more code
1305
1306Here is my comment above the above...
1307
1308
1309Reviewed-by: %s
1310''' % self.joe}
1311
1312 patch1.comments = [comment1a]
1313
1314 patch2 = status.Patch('2')
1315 patch2.parse_subject('[2/2] Subject 2')
1316 patch2.name = patch2.raw_subject
1317 patch2.content = 'Some other patch content'
1318 comment2a = {
1319 'content': 'Reviewed-by: %s\nTested-by: %s\n' %
1320 (self.mary, self.leb)}
1321 comment2b = {'submitter': _to_submitter(self.fred),
1322 'content': '''Hi Fred,
1323
1324On some date Fred wrote:
1325
1326> diff --git a/tools/patman/commit.py b/tools/patman/commit.py
1327> @@ -41,6 +41,9 @@ class Commit:
1328> self.rtags = collections.defaultdict(set)
1329> self.warn = []
1330>
1331> + def __str__(self):
1332> + return self.subject
1333> +
Simon Glassd85bb8f2022-01-29 14:14:09 -07001334> def add_change(self, version, info):
Simon Glass2112d072020-10-29 21:46:38 -06001335> """Add a new change line to the change list for a version.
1336>
1337A comment
1338
1339Reviewed-by: %s
1340''' % self.fred}
1341 patch2.comments = [comment2a, comment2b]
1342
1343 # This test works by setting up commits and patch for use by the fake
1344 # Rest API function _fake_patchwork2(). It calls various functions in
1345 # the status module after setting up tags in the commits, checking that
1346 # things behaves as expected
1347 self.commits = [commit1, commit2]
1348 self.patches = [patch1, patch2]
1349
1350 # Check that the output patches expectations:
1351 # 1 Subject 1
1352 # Reviewed-by: Joe Bloggs <joe@napierwallies.co.nz>
1353 # 2 Subject 2
1354 # Tested-by: Lord Edmund Blackaddër <weasel@blackadder.org>
1355 # Reviewed-by: Fred Bloggs <f.bloggs@napier.net>
1356 # + Reviewed-by: Mary Bloggs <mary@napierwallies.co.nz>
1357 # 1 new response available in patchwork
1358
1359 series = Series()
1360 series.commits = [commit1, commit2]
Simon Glass02811582022-01-29 14:14:18 -07001361 terminal.set_print_test_mode()
Simon Glass2112d072020-10-29 21:46:38 -06001362 status.check_patchwork_status(series, '1234', None, None, False, True,
Simon Glassf9b03cf2020-11-03 13:54:14 -07001363 None, self._fake_patchwork2)
Simon Glass02811582022-01-29 14:14:18 -07001364 lines = iter(terminal.get_print_test_lines())
Simon Glass2112d072020-10-29 21:46:38 -06001365 col = terminal.Color()
1366 self.assertEqual(terminal.PrintLine(' 1 Subject 1', col.BLUE),
1367 next(lines))
1368 self.assertEqual(
1369 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
1370 next(lines))
1371 self.assertEqual(terminal.PrintLine(self.joe, col.WHITE), next(lines))
1372
1373 self.assertEqual(terminal.PrintLine('Review: %s' % self.joe, col.RED),
1374 next(lines))
1375 self.assertEqual(terminal.PrintLine(' Hi Fred,', None), next(lines))
1376 self.assertEqual(terminal.PrintLine('', None), next(lines))
1377 self.assertEqual(terminal.PrintLine(' > File: file.c', col.MAGENTA),
1378 next(lines))
1379 self.assertEqual(terminal.PrintLine(' > Some code', col.MAGENTA),
1380 next(lines))
1381 self.assertEqual(terminal.PrintLine(' > and more code', col.MAGENTA),
1382 next(lines))
1383 self.assertEqual(terminal.PrintLine(
1384 ' Here is my comment above the above...', None), next(lines))
1385 self.assertEqual(terminal.PrintLine('', None), next(lines))
1386
1387 self.assertEqual(terminal.PrintLine(' 2 Subject 2', col.BLUE),
1388 next(lines))
1389 self.assertEqual(
1390 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
1391 next(lines))
1392 self.assertEqual(terminal.PrintLine(self.fred, col.WHITE),
1393 next(lines))
1394 self.assertEqual(
1395 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
1396 next(lines))
1397 self.assertEqual(terminal.PrintLine(self.mary, col.WHITE),
1398 next(lines))
1399 self.assertEqual(
1400 terminal.PrintLine(' + Tested-by: ', col.GREEN, newline=False),
1401 next(lines))
1402 self.assertEqual(terminal.PrintLine(self.leb, col.WHITE),
1403 next(lines))
1404
1405 self.assertEqual(terminal.PrintLine('Review: %s' % self.fred, col.RED),
1406 next(lines))
1407 self.assertEqual(terminal.PrintLine(' Hi Fred,', None), next(lines))
1408 self.assertEqual(terminal.PrintLine('', None), next(lines))
1409 self.assertEqual(terminal.PrintLine(
1410 ' > File: tools/patman/commit.py', col.MAGENTA), next(lines))
1411 self.assertEqual(terminal.PrintLine(
1412 ' > Line: 41 / 41: class Commit:', col.MAGENTA), next(lines))
1413 self.assertEqual(terminal.PrintLine(
1414 ' > + return self.subject', col.MAGENTA), next(lines))
1415 self.assertEqual(terminal.PrintLine(
1416 ' > +', col.MAGENTA), next(lines))
1417 self.assertEqual(
Simon Glassd85bb8f2022-01-29 14:14:09 -07001418 terminal.PrintLine(' > def add_change(self, version, info):',
Simon Glass2112d072020-10-29 21:46:38 -06001419 col.MAGENTA),
1420 next(lines))
1421 self.assertEqual(terminal.PrintLine(
1422 ' > """Add a new change line to the change list for a version.',
1423 col.MAGENTA), next(lines))
1424 self.assertEqual(terminal.PrintLine(
1425 ' >', col.MAGENTA), next(lines))
1426 self.assertEqual(terminal.PrintLine(
1427 ' A comment', None), next(lines))
1428 self.assertEqual(terminal.PrintLine('', None), next(lines))
1429
1430 self.assertEqual(terminal.PrintLine(
1431 '4 new responses available in patchwork (use -d to write them to a new branch)',
1432 None), next(lines))
Simon Glass6a222e62021-08-01 16:02:39 -06001433
Simon Glassd85bb8f2022-01-29 14:14:09 -07001434 def test_insert_tags(self):
Simon Glass6a222e62021-08-01 16:02:39 -06001435 """Test inserting of review tags"""
1436 msg = '''first line
1437second line.'''
1438 tags = [
1439 'Reviewed-by: Bin Meng <bmeng.cn@gmail.com>',
1440 'Tested-by: Bin Meng <bmeng.cn@gmail.com>'
1441 ]
1442 signoff = 'Signed-off-by: Simon Glass <sjg@chromium.com>'
1443 tag_str = '\n'.join(tags)
1444
1445 new_msg = patchstream.insert_tags(msg, tags)
1446 self.assertEqual(msg + '\n\n' + tag_str, new_msg)
1447
1448 new_msg = patchstream.insert_tags(msg + '\n', tags)
1449 self.assertEqual(msg + '\n\n' + tag_str, new_msg)
1450
1451 msg += '\n\n' + signoff
1452 new_msg = patchstream.insert_tags(msg, tags)
1453 self.assertEqual(msg + '\n' + tag_str, new_msg)