blob: 9f4e03e8822d347d23655dbffa4adaef057d6cc3 [file] [log] [blame]
Simon Glass6e87ae12017-05-29 15:31:31 -06001# -*- coding: utf-8 -*-
Tom Rini83d290c2018-05-06 17:58:06 -04002# SPDX-License-Identifier: GPL-2.0+
Simon Glass6e87ae12017-05-29 15:31:31 -06003#
4# Copyright 2017 Google, Inc
5#
Simon Glass6e87ae12017-05-29 15:31:31 -06006
Simon Glassfca99112020-10-29 21:46:15 -06007"""Functional tests for checking that patman behaves correctly"""
8
Simon Glass6e87ae12017-05-29 15:31:31 -06009import os
10import re
11import shutil
12import sys
13import tempfile
14import unittest
15
Simon Glassdc6df972020-10-29 21:46:35 -060016
17from patman.commit import Commit
Simon Glassfd709862020-07-05 21:41:50 -060018from patman import control
Simon Glassbf776672020-04-17 18:09:04 -060019from patman import gitutil
20from patman import patchstream
Simon Glass47f62952020-10-29 21:46:26 -060021from patman.patchstream import PatchStream
Simon Glassdc6df972020-10-29 21:46:35 -060022from patman.series import Series
Simon Glassbf776672020-04-17 18:09:04 -060023from patman import settings
Simon Glassfd709862020-07-05 21:41:50 -060024from patman import terminal
Simon Glassbf776672020-04-17 18:09:04 -060025from patman import tools
Simon Glassfd709862020-07-05 21:41:50 -060026from patman.test_util import capture_sys_output
27
Tom Rini2959a8e2021-02-26 07:52:31 -050028import pygit2
29from patman import status
Simon Glass6e87ae12017-05-29 15:31:31 -060030
Simon Glass6e87ae12017-05-29 15:31:31 -060031class TestFunctional(unittest.TestCase):
Simon Glassfca99112020-10-29 21:46:15 -060032 """Functional tests for checking that patman behaves correctly"""
Simon Glass74570512020-10-29 21:46:27 -060033 leb = (b'Lord Edmund Blackadd\xc3\xabr <weasel@blackadder.org>'.
34 decode('utf-8'))
Simon Glass4af99872020-10-29 21:46:28 -060035 fred = 'Fred Bloggs <f.bloggs@napier.net>'
36 joe = 'Joe Bloggs <joe@napierwallies.co.nz>'
37 mary = 'Mary Bloggs <mary@napierwallies.co.nz>'
Simon Glassdc6df972020-10-29 21:46:35 -060038 commits = None
39 patches = None
Simon Glass74570512020-10-29 21:46:27 -060040
Simon Glass6e87ae12017-05-29 15:31:31 -060041 def setUp(self):
42 self.tmpdir = tempfile.mkdtemp(prefix='patman.')
Simon Glassfd709862020-07-05 21:41:50 -060043 self.gitdir = os.path.join(self.tmpdir, 'git')
44 self.repo = None
Simon Glass6e87ae12017-05-29 15:31:31 -060045
46 def tearDown(self):
47 shutil.rmtree(self.tmpdir)
Simon Glassdc6df972020-10-29 21:46:35 -060048 terminal.SetPrintTestMode(False)
Simon Glass6e87ae12017-05-29 15:31:31 -060049
50 @staticmethod
Simon Glassfca99112020-10-29 21:46:15 -060051 def _get_path(fname):
52 """Get the path to a test file
53
54 Args:
55 fname (str): Filename to obtain
56
57 Returns:
58 str: Full path to file in the test directory
59 """
Simon Glass6e87ae12017-05-29 15:31:31 -060060 return os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
61 'test', fname)
62
63 @classmethod
Simon Glassfca99112020-10-29 21:46:15 -060064 def _get_text(cls, fname):
65 """Read a file as text
66
67 Args:
68 fname (str): Filename to read
69
70 Returns:
71 str: Contents of file
72 """
73 return open(cls._get_path(fname), encoding='utf-8').read()
Simon Glass6e87ae12017-05-29 15:31:31 -060074
75 @classmethod
Simon Glassfca99112020-10-29 21:46:15 -060076 def _get_patch_name(cls, subject):
77 """Get the filename of a patch given its subject
78
79 Args:
80 subject (str): Patch subject
81
82 Returns:
83 str: Filename for that patch
84 """
Simon Glass6e87ae12017-05-29 15:31:31 -060085 fname = re.sub('[ :]', '-', subject)
86 return fname.replace('--', '-')
87
Simon Glassfca99112020-10-29 21:46:15 -060088 def _create_patches_for_test(self, series):
89 """Create patch files for use by tests
90
91 This copies patch files from the test directory as needed by the series
92
93 Args:
94 series (Series): Series containing commits to convert
95
96 Returns:
97 tuple:
98 str: Cover-letter filename, or None if none
99 fname_list: list of str, each a patch filename
100 """
Simon Glass6e87ae12017-05-29 15:31:31 -0600101 cover_fname = None
102 fname_list = []
103 for i, commit in enumerate(series.commits):
Simon Glassfca99112020-10-29 21:46:15 -0600104 clean_subject = self._get_patch_name(commit.subject)
Simon Glass6e87ae12017-05-29 15:31:31 -0600105 src_fname = '%04d-%s.patch' % (i + 1, clean_subject[:52])
106 fname = os.path.join(self.tmpdir, src_fname)
Simon Glassfca99112020-10-29 21:46:15 -0600107 shutil.copy(self._get_path(src_fname), fname)
Simon Glass6e87ae12017-05-29 15:31:31 -0600108 fname_list.append(fname)
109 if series.get('cover'):
110 src_fname = '0000-cover-letter.patch'
111 cover_fname = os.path.join(self.tmpdir, src_fname)
112 fname = os.path.join(self.tmpdir, src_fname)
Simon Glassfca99112020-10-29 21:46:15 -0600113 shutil.copy(self._get_path(src_fname), fname)
Simon Glass6e87ae12017-05-29 15:31:31 -0600114
115 return cover_fname, fname_list
116
117 def testBasic(self):
118 """Tests the basic flow of patman
119
120 This creates a series from some hard-coded patches build from a simple
121 tree with the following metadata in the top commit:
122
123 Series-to: u-boot
124 Series-prefix: RFC
Sean Anderson082c1192021-10-22 19:07:04 -0400125 Series-postfix: some-branch
Simon Glass6e87ae12017-05-29 15:31:31 -0600126 Series-cc: Stefan Brüns <stefan.bruens@rwth-aachen.de>
127 Cover-letter-cc: Lord Mëlchett <clergy@palace.gov>
Sean Andersondc03ba42020-05-04 16:28:36 -0400128 Series-version: 3
129 Patch-cc: fred
130 Series-process-log: sort, uniq
Simon Glass6e87ae12017-05-29 15:31:31 -0600131 Series-changes: 4
132 - Some changes
Sean Andersondc03ba42020-05-04 16:28:36 -0400133 - Multi
134 line
135 change
136
137 Commit-changes: 2
138 - Changes only for this commit
139
Simon Glass59747182021-08-01 16:02:39 -0600140' Cover-changes: 4
Sean Andersondc03ba42020-05-04 16:28:36 -0400141 - Some notes for the cover letter
Simon Glass6e87ae12017-05-29 15:31:31 -0600142
143 Cover-letter:
144 test: A test patch series
145 This is a test of how the cover
Sean Andersondc03ba42020-05-04 16:28:36 -0400146 letter
Simon Glass6e87ae12017-05-29 15:31:31 -0600147 works
148 END
149
150 and this in the first commit:
151
Sean Andersondc03ba42020-05-04 16:28:36 -0400152 Commit-changes: 2
153 - second revision change
154
Simon Glass6e87ae12017-05-29 15:31:31 -0600155 Series-notes:
156 some notes
157 about some things
158 from the first commit
159 END
160
161 Commit-notes:
162 Some notes about
163 the first commit
164 END
165
166 with the following commands:
167
168 git log -n2 --reverse >/path/to/tools/patman/test/test01.txt
169 git format-patch --subject-prefix RFC --cover-letter HEAD~2
170 mv 00* /path/to/tools/patman/test
171
172 It checks these aspects:
173 - git log can be processed by patchstream
174 - emailing patches uses the correct command
175 - CC file has information on each commit
176 - cover letter has the expected text and subject
177 - each patch has the correct subject
178 - dry-run information prints out correctly
179 - unicode is handled correctly
Sean Anderson082c1192021-10-22 19:07:04 -0400180 - Series-to, Series-cc, Series-prefix, Series-postfix, Cover-letter
Simon Glass6e87ae12017-05-29 15:31:31 -0600181 - Cover-letter-cc, Series-version, Series-changes, Series-notes
182 - Commit-notes
183 """
184 process_tags = True
Simon Glass0fb560d2021-01-23 08:56:15 -0700185 ignore_bad_tags = False
Simon Glasse6dca5e2019-05-14 15:53:53 -0600186 stefan = b'Stefan Br\xc3\xbcns <stefan.bruens@rwth-aachen.de>'.decode('utf-8')
Simon Glass6e87ae12017-05-29 15:31:31 -0600187 rick = 'Richard III <richard@palace.gov>'
Simon Glasse6dca5e2019-05-14 15:53:53 -0600188 mel = b'Lord M\xc3\xablchett <clergy@palace.gov>'.decode('utf-8')
Simon Glass6e87ae12017-05-29 15:31:31 -0600189 add_maintainers = [stefan, rick]
190 dry_run = True
191 in_reply_to = mel
192 count = 2
193 settings.alias = {
Simon Glass427b0282020-10-29 21:46:13 -0600194 'fdt': ['simon'],
195 'u-boot': ['u-boot@lists.denx.de'],
Simon Glass74570512020-10-29 21:46:27 -0600196 'simon': [self.leb],
Simon Glass4af99872020-10-29 21:46:28 -0600197 'fred': [self.fred],
Simon Glass6e87ae12017-05-29 15:31:31 -0600198 }
199
Simon Glassfca99112020-10-29 21:46:15 -0600200 text = self._get_text('test01.txt')
Simon Glassd93720e2020-10-29 21:46:19 -0600201 series = patchstream.get_metadata_for_test(text)
Simon Glassfca99112020-10-29 21:46:15 -0600202 cover_fname, args = self._create_patches_for_test(series)
Simon Glass366954f2020-10-29 21:46:14 -0600203 with capture_sys_output() as out:
Simon Glassd93720e2020-10-29 21:46:19 -0600204 patchstream.fix_patches(series, args)
Simon Glass6e87ae12017-05-29 15:31:31 -0600205 if cover_fname and series.get('cover'):
Simon Glassd93720e2020-10-29 21:46:19 -0600206 patchstream.insert_cover_letter(cover_fname, series, count)
Simon Glass6e87ae12017-05-29 15:31:31 -0600207 series.DoChecks()
208 cc_file = series.MakeCcFile(process_tags, cover_fname,
Chris Packham4fb35022018-06-07 20:45:06 +1200209 not ignore_bad_tags, add_maintainers,
210 None)
Simon Glass427b0282020-10-29 21:46:13 -0600211 cmd = gitutil.EmailPatches(
212 series, cover_fname, args, dry_run, not ignore_bad_tags,
213 cc_file, in_reply_to=in_reply_to, thread=None)
Simon Glass6e87ae12017-05-29 15:31:31 -0600214 series.ShowActions(args, cmd, process_tags)
Simon Glass272cd852019-10-31 07:42:51 -0600215 cc_lines = open(cc_file, encoding='utf-8').read().splitlines()
Simon Glass6e87ae12017-05-29 15:31:31 -0600216 os.remove(cc_file)
217
Simon Glass8c17f8c2020-10-29 21:46:29 -0600218 lines = iter(out[0].getvalue().splitlines())
219 self.assertEqual('Cleaned %s patches' % len(series.commits),
220 next(lines))
221 self.assertEqual('Change log missing for v2', next(lines))
222 self.assertEqual('Change log missing for v3', next(lines))
223 self.assertEqual('Change log for unknown version v4', next(lines))
224 self.assertEqual("Alias 'pci' not found", next(lines))
225 self.assertIn('Dry run', next(lines))
226 self.assertEqual('', next(lines))
227 self.assertIn('Send a total of %d patches' % count, next(lines))
228 prev = next(lines)
229 for i, commit in enumerate(series.commits):
230 self.assertEqual(' %s' % args[i], prev)
231 while True:
232 prev = next(lines)
233 if 'Cc:' not in prev:
234 break
235 self.assertEqual('To: u-boot@lists.denx.de', prev)
Simon Glassfc0056e2020-11-08 20:36:18 -0700236 self.assertEqual('Cc: %s' % stefan, next(lines))
Simon Glass8c17f8c2020-10-29 21:46:29 -0600237 self.assertEqual('Version: 3', next(lines))
238 self.assertEqual('Prefix:\t RFC', next(lines))
Sean Anderson082c1192021-10-22 19:07:04 -0400239 self.assertEqual('Postfix:\t some-branch', next(lines))
Simon Glass8c17f8c2020-10-29 21:46:29 -0600240 self.assertEqual('Cover: 4 lines', next(lines))
241 self.assertEqual(' Cc: %s' % self.fred, next(lines))
Simon Glassfc0056e2020-11-08 20:36:18 -0700242 self.assertEqual(' Cc: %s' % self.leb,
Simon Glass8c17f8c2020-10-29 21:46:29 -0600243 next(lines))
Simon Glassfc0056e2020-11-08 20:36:18 -0700244 self.assertEqual(' Cc: %s' % mel, next(lines))
Simon Glass8c17f8c2020-10-29 21:46:29 -0600245 self.assertEqual(' Cc: %s' % rick, next(lines))
Simon Glass6e87ae12017-05-29 15:31:31 -0600246 expected = ('Git command: git send-email --annotate '
247 '--in-reply-to="%s" --to "u-boot@lists.denx.de" '
Simon Glass46007672020-11-03 13:54:10 -0700248 '--cc "%s" --cc-cmd "%s send --cc-cmd %s" %s %s'
Simon Glass6e87ae12017-05-29 15:31:31 -0600249 % (in_reply_to, stefan, sys.argv[0], cc_file, cover_fname,
Simon Glasse6dca5e2019-05-14 15:53:53 -0600250 ' '.join(args)))
Simon Glassfc0056e2020-11-08 20:36:18 -0700251 self.assertEqual(expected, next(lines))
Simon Glass6e87ae12017-05-29 15:31:31 -0600252
Simon Glassfc0056e2020-11-08 20:36:18 -0700253 self.assertEqual(('%s %s\0%s' % (args[0], rick, stefan)), cc_lines[0])
Simon Glass427b0282020-10-29 21:46:13 -0600254 self.assertEqual(
Simon Glass4af99872020-10-29 21:46:28 -0600255 '%s %s\0%s\0%s\0%s' % (args[1], self.fred, self.leb, rick, stefan),
Simon Glassfc0056e2020-11-08 20:36:18 -0700256 cc_lines[1])
Simon Glass6e87ae12017-05-29 15:31:31 -0600257
258 expected = '''
259This is a test of how the cover
Sean Andersondc03ba42020-05-04 16:28:36 -0400260letter
Simon Glass6e87ae12017-05-29 15:31:31 -0600261works
262
263some notes
264about some things
265from the first commit
266
267Changes in v4:
Sean Andersondc03ba42020-05-04 16:28:36 -0400268- Multi
269 line
270 change
Simon Glass6e87ae12017-05-29 15:31:31 -0600271- Some changes
Sean Andersondc03ba42020-05-04 16:28:36 -0400272- Some notes for the cover letter
Simon Glass6e87ae12017-05-29 15:31:31 -0600273
274Simon Glass (2):
275 pci: Correct cast for sandbox
Siva Durga Prasad Paladugu12308b12018-07-16 15:56:11 +0530276 fdt: Correct cast for sandbox in fdtdec_setup_mem_size_base()
Simon Glass6e87ae12017-05-29 15:31:31 -0600277
278 cmd/pci.c | 3 ++-
279 fs/fat/fat.c | 1 +
280 lib/efi_loader/efi_memory.c | 1 +
281 lib/fdtdec.c | 3 ++-
282 4 files changed, 6 insertions(+), 2 deletions(-)
283
284--\x20
2852.7.4
286
287'''
Simon Glass272cd852019-10-31 07:42:51 -0600288 lines = open(cover_fname, encoding='utf-8').read().splitlines()
Simon Glass6e87ae12017-05-29 15:31:31 -0600289 self.assertEqual(
Sean Anderson082c1192021-10-22 19:07:04 -0400290 'Subject: [RFC PATCH some-branch v3 0/2] test: A test patch series',
Simon Glass427b0282020-10-29 21:46:13 -0600291 lines[3])
Simon Glass6e87ae12017-05-29 15:31:31 -0600292 self.assertEqual(expected.splitlines(), lines[7:])
293
294 for i, fname in enumerate(args):
Simon Glass272cd852019-10-31 07:42:51 -0600295 lines = open(fname, encoding='utf-8').read().splitlines()
Simon Glass6e87ae12017-05-29 15:31:31 -0600296 subject = [line for line in lines if line.startswith('Subject')]
297 self.assertEqual('Subject: [RFC %d/%d]' % (i + 1, count),
298 subject[0][:18])
Sean Andersondc03ba42020-05-04 16:28:36 -0400299
300 # Check that we got our commit notes
301 start = 0
302 expected = ''
303
Simon Glass6e87ae12017-05-29 15:31:31 -0600304 if i == 0:
Sean Andersondc03ba42020-05-04 16:28:36 -0400305 start = 17
306 expected = '''---
307Some notes about
308the first commit
309
310(no changes since v2)
311
312Changes in v2:
313- second revision change'''
314 elif i == 1:
315 start = 17
316 expected = '''---
317
318Changes in v4:
319- Multi
320 line
321 change
322- Some changes
323
324Changes in v2:
325- Changes only for this commit'''
326
327 if expected:
328 expected = expected.splitlines()
329 self.assertEqual(expected, lines[start:(start+len(expected))])
Simon Glassfd709862020-07-05 21:41:50 -0600330
331 def make_commit_with_file(self, subject, body, fname, text):
332 """Create a file and add it to the git repo with a new commit
333
334 Args:
335 subject (str): Subject for the commit
336 body (str): Body text of the commit
337 fname (str): Filename of file to create
338 text (str): Text to put into the file
339 """
340 path = os.path.join(self.gitdir, fname)
341 tools.WriteFile(path, text, binary=False)
342 index = self.repo.index
343 index.add(fname)
Simon Glass427b0282020-10-29 21:46:13 -0600344 author = pygit2.Signature('Test user', 'test@email.com')
Simon Glassfd709862020-07-05 21:41:50 -0600345 committer = author
346 tree = index.write_tree()
347 message = subject + '\n' + body
348 self.repo.create_commit('HEAD', author, committer, message, tree,
349 [self.repo.head.target])
350
351 def make_git_tree(self):
352 """Make a simple git tree suitable for testing
353
354 It has three branches:
355 'base' has two commits: PCI, main
356 'first' has base as upstream and two more commits: I2C, SPI
357 'second' has base as upstream and three more: video, serial, bootm
358
359 Returns:
Simon Glassfca99112020-10-29 21:46:15 -0600360 pygit2.Repository: repository
Simon Glassfd709862020-07-05 21:41:50 -0600361 """
362 repo = pygit2.init_repository(self.gitdir)
363 self.repo = repo
364 new_tree = repo.TreeBuilder().write()
365
366 author = pygit2.Signature('Test user', 'test@email.com')
367 committer = author
Simon Glassfca99112020-10-29 21:46:15 -0600368 _ = repo.create_commit('HEAD', author, committer, 'Created master',
369 new_tree, [])
Simon Glassfd709862020-07-05 21:41:50 -0600370
371 self.make_commit_with_file('Initial commit', '''
372Add a README
373
374''', 'README', '''This is the README file
375describing this project
376in very little detail''')
377
378 self.make_commit_with_file('pci: PCI implementation', '''
379Here is a basic PCI implementation
380
381''', 'pci.c', '''This is a file
382it has some contents
383and some more things''')
384 self.make_commit_with_file('main: Main program', '''
385Hello here is the second commit.
386''', 'main.c', '''This is the main file
387there is very little here
388but we can always add more later
389if we want to
390
391Series-to: u-boot
392Series-cc: Barry Crump <bcrump@whataroa.nz>
393''')
394 base_target = repo.revparse_single('HEAD')
395 self.make_commit_with_file('i2c: I2C things', '''
396This has some stuff to do with I2C
397''', 'i2c.c', '''And this is the file contents
398with some I2C-related things in it''')
399 self.make_commit_with_file('spi: SPI fixes', '''
400SPI needs some fixes
401and here they are
Simon Glass8f9ba3a2020-10-29 21:46:36 -0600402
403Signed-off-by: %s
404
405Series-to: u-boot
406Commit-notes:
407title of the series
408This is the cover letter for the series
409with various details
410END
411''' % self.leb, 'spi.c', '''Some fixes for SPI in this
Simon Glassfd709862020-07-05 21:41:50 -0600412file to make SPI work
413better than before''')
414 first_target = repo.revparse_single('HEAD')
415
416 target = repo.revparse_single('HEAD~2')
417 repo.reset(target.oid, pygit2.GIT_CHECKOUT_FORCE)
418 self.make_commit_with_file('video: Some video improvements', '''
419Fix up the video so that
420it looks more purple. Purple is
421a very nice colour.
422''', 'video.c', '''More purple here
423Purple and purple
424Even more purple
425Could not be any more purple''')
426 self.make_commit_with_file('serial: Add a serial driver', '''
427Here is the serial driver
428for my chip.
429
430Cover-letter:
431Series for my board
432This series implements support
433for my glorious board.
434END
Simon Glassf9e42842020-10-29 21:46:16 -0600435Series-links: 183237
Simon Glassfd709862020-07-05 21:41:50 -0600436''', 'serial.c', '''The code for the
437serial driver is here''')
438 self.make_commit_with_file('bootm: Make it boot', '''
439This makes my board boot
440with a fix to the bootm
441command
442''', 'bootm.c', '''Fix up the bootm
443command to make the code as
444complicated as possible''')
445 second_target = repo.revparse_single('HEAD')
446
447 repo.branches.local.create('first', first_target)
448 repo.config.set_multivar('branch.first.remote', '', '.')
449 repo.config.set_multivar('branch.first.merge', '', 'refs/heads/base')
450
451 repo.branches.local.create('second', second_target)
452 repo.config.set_multivar('branch.second.remote', '', '.')
453 repo.config.set_multivar('branch.second.merge', '', 'refs/heads/base')
454
455 repo.branches.local.create('base', base_target)
456 return repo
457
Simon Glassfd709862020-07-05 21:41:50 -0600458 def testBranch(self):
459 """Test creating patches from a branch"""
460 repo = self.make_git_tree()
461 target = repo.lookup_reference('refs/heads/first')
462 self.repo.checkout(target, strategy=pygit2.GIT_CHECKOUT_FORCE)
463 control.setup()
464 try:
465 orig_dir = os.getcwd()
466 os.chdir(self.gitdir)
467
468 # Check that it can detect the current branch
Simon Glass262130f2020-07-05 21:41:51 -0600469 self.assertEqual(2, gitutil.CountCommitsToBranch(None))
Simon Glassfd709862020-07-05 21:41:50 -0600470 col = terminal.Color()
471 with capture_sys_output() as _:
472 _, cover_fname, patch_files = control.prepare_patches(
Simon Glass137947e2020-07-05 21:41:52 -0600473 col, branch=None, count=-1, start=0, end=0,
Philipp Tomsichb3aff152020-11-24 18:14:52 +0100474 ignore_binary=False, signoff=True)
Simon Glassfd709862020-07-05 21:41:50 -0600475 self.assertIsNone(cover_fname)
476 self.assertEqual(2, len(patch_files))
Simon Glass262130f2020-07-05 21:41:51 -0600477
478 # Check that it can detect a different branch
479 self.assertEqual(3, gitutil.CountCommitsToBranch('second'))
480 with capture_sys_output() as _:
481 _, cover_fname, patch_files = control.prepare_patches(
Simon Glass137947e2020-07-05 21:41:52 -0600482 col, branch='second', count=-1, start=0, end=0,
Philipp Tomsichb3aff152020-11-24 18:14:52 +0100483 ignore_binary=False, signoff=True)
Simon Glass262130f2020-07-05 21:41:51 -0600484 self.assertIsNotNone(cover_fname)
485 self.assertEqual(3, len(patch_files))
Simon Glass137947e2020-07-05 21:41:52 -0600486
487 # Check that it can skip patches at the end
488 with capture_sys_output() as _:
489 _, cover_fname, patch_files = control.prepare_patches(
490 col, branch='second', count=-1, start=0, end=1,
Philipp Tomsichb3aff152020-11-24 18:14:52 +0100491 ignore_binary=False, signoff=True)
Simon Glass137947e2020-07-05 21:41:52 -0600492 self.assertIsNotNone(cover_fname)
493 self.assertEqual(2, len(patch_files))
Simon Glassfd709862020-07-05 21:41:50 -0600494 finally:
495 os.chdir(orig_dir)
Simon Glass74570512020-10-29 21:46:27 -0600496
497 def testTags(self):
498 """Test collection of tags in a patchstream"""
499 text = '''This is a patch
500
501Signed-off-by: Terminator
Simon Glass4af99872020-10-29 21:46:28 -0600502Reviewed-by: %s
503Reviewed-by: %s
Simon Glass74570512020-10-29 21:46:27 -0600504Tested-by: %s
Simon Glass4af99872020-10-29 21:46:28 -0600505''' % (self.joe, self.mary, self.leb)
Simon Glass74570512020-10-29 21:46:27 -0600506 pstrm = PatchStream.process_text(text)
507 self.assertEqual(pstrm.commit.rtags, {
Simon Glass4af99872020-10-29 21:46:28 -0600508 'Reviewed-by': {self.joe, self.mary},
Simon Glass74570512020-10-29 21:46:27 -0600509 'Tested-by': {self.leb}})
Simon Glass4af99872020-10-29 21:46:28 -0600510
Patrick Delaunaya6123332021-07-22 16:51:42 +0200511 def testInvalidTag(self):
512 """Test invalid tag in a patchstream"""
513 text = '''This is a patch
514
515Serie-version: 2
516'''
517 with self.assertRaises(ValueError) as exc:
518 pstrm = PatchStream.process_text(text)
519 self.assertEqual("Line 3: Invalid tag = 'Serie-version: 2'",
520 str(exc.exception))
521
Simon Glass4af99872020-10-29 21:46:28 -0600522 def testMissingEnd(self):
523 """Test a missing END tag"""
524 text = '''This is a patch
525
526Cover-letter:
527This is the title
528missing END after this line
529Signed-off-by: Fred
530'''
531 pstrm = PatchStream.process_text(text)
532 self.assertEqual(["Missing 'END' in section 'cover'"],
533 pstrm.commit.warn)
534
535 def testMissingBlankLine(self):
536 """Test a missing blank line after a tag"""
537 text = '''This is a patch
538
539Series-changes: 2
540- First line of changes
541- Missing blank line after this line
542Signed-off-by: Fred
543'''
544 pstrm = PatchStream.process_text(text)
545 self.assertEqual(["Missing 'blank line' in section 'Series-changes'"],
546 pstrm.commit.warn)
547
548 def testInvalidCommitTag(self):
549 """Test an invalid Commit-xxx tag"""
550 text = '''This is a patch
551
552Commit-fred: testing
553'''
554 pstrm = PatchStream.process_text(text)
555 self.assertEqual(["Line 3: Ignoring Commit-fred"], pstrm.commit.warn)
556
557 def testSelfTest(self):
558 """Test a tested by tag by this user"""
559 test_line = 'Tested-by: %s@napier.com' % os.getenv('USER')
560 text = '''This is a patch
561
562%s
563''' % test_line
564 pstrm = PatchStream.process_text(text)
565 self.assertEqual(["Ignoring '%s'" % test_line], pstrm.commit.warn)
566
567 def testSpaceBeforeTab(self):
568 """Test a space before a tab"""
569 text = '''This is a patch
570
571+ \tSomething
572'''
573 pstrm = PatchStream.process_text(text)
574 self.assertEqual(["Line 3/0 has space before tab"], pstrm.commit.warn)
575
576 def testLinesAfterTest(self):
577 """Test detecting lines after TEST= line"""
578 text = '''This is a patch
579
580TEST=sometest
581more lines
582here
583'''
584 pstrm = PatchStream.process_text(text)
585 self.assertEqual(["Found 2 lines after TEST="], pstrm.commit.warn)
586
587 def testBlankLineAtEnd(self):
588 """Test detecting a blank line at the end of a file"""
589 text = '''This is a patch
590
591diff --git a/lib/fdtdec.c b/lib/fdtdec.c
592index c072e54..942244f 100644
593--- a/lib/fdtdec.c
594+++ b/lib/fdtdec.c
595@@ -1200,7 +1200,8 @@ int fdtdec_setup_mem_size_base(void)
596 }
597
598 gd->ram_size = (phys_size_t)(res.end - res.start + 1);
599- debug("%s: Initial DRAM size %llx\n", __func__, (u64)gd->ram_size);
600+ debug("%s: Initial DRAM size %llx\n", __func__,
601+ (unsigned long long)gd->ram_size);
602+
603diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
604
605--
6062.7.4
607
608 '''
609 pstrm = PatchStream.process_text(text)
610 self.assertEqual(
611 ["Found possible blank line(s) at end of file 'lib/fdtdec.c'"],
612 pstrm.commit.warn)
Simon Glassbe051c02020-10-29 21:46:34 -0600613
Simon Glassbe051c02020-10-29 21:46:34 -0600614 def testNoUpstream(self):
615 """Test CountCommitsToBranch when there is no upstream"""
616 repo = self.make_git_tree()
617 target = repo.lookup_reference('refs/heads/base')
618 self.repo.checkout(target, strategy=pygit2.GIT_CHECKOUT_FORCE)
619
620 # Check that it can detect the current branch
621 try:
622 orig_dir = os.getcwd()
623 os.chdir(self.gitdir)
624 with self.assertRaises(ValueError) as exc:
625 gitutil.CountCommitsToBranch(None)
626 self.assertIn(
627 "Failed to determine upstream: fatal: no upstream configured for branch 'base'",
628 str(exc.exception))
629 finally:
630 os.chdir(orig_dir)
Simon Glassdc6df972020-10-29 21:46:35 -0600631
632 @staticmethod
Simon Glass7cbf02e2020-11-03 13:54:14 -0700633 def _fake_patchwork(url, subpath):
Simon Glassdc6df972020-10-29 21:46:35 -0600634 """Fake Patchwork server for the function below
635
636 This handles accessing a series, providing a list consisting of a
637 single patch
Simon Glass7cbf02e2020-11-03 13:54:14 -0700638
639 Args:
640 url (str): URL of patchwork server
641 subpath (str): URL subpath to use
Simon Glassdc6df972020-10-29 21:46:35 -0600642 """
643 re_series = re.match(r'series/(\d*)/$', subpath)
644 if re_series:
645 series_num = re_series.group(1)
646 if series_num == '1234':
647 return {'patches': [
648 {'id': '1', 'name': 'Some patch'}]}
649 raise ValueError('Fake Patchwork does not understand: %s' % subpath)
650
Simon Glassdc6df972020-10-29 21:46:35 -0600651 def testStatusMismatch(self):
652 """Test Patchwork patches not matching the series"""
653 series = Series()
654
655 with capture_sys_output() as (_, err):
Simon Glass7cbf02e2020-11-03 13:54:14 -0700656 status.collect_patches(series, 1234, None, self._fake_patchwork)
Simon Glassdc6df972020-10-29 21:46:35 -0600657 self.assertIn('Warning: Patchwork reports 1 patches, series has 0',
658 err.getvalue())
659
Simon Glassdc6df972020-10-29 21:46:35 -0600660 def testStatusReadPatch(self):
661 """Test handling a single patch in Patchwork"""
662 series = Series()
663 series.commits = [Commit('abcd')]
664
Simon Glass7cbf02e2020-11-03 13:54:14 -0700665 patches = status.collect_patches(series, 1234, None,
666 self._fake_patchwork)
Simon Glassdc6df972020-10-29 21:46:35 -0600667 self.assertEqual(1, len(patches))
668 patch = patches[0]
669 self.assertEqual('1', patch.id)
670 self.assertEqual('Some patch', patch.raw_subject)
671
Simon Glassdc6df972020-10-29 21:46:35 -0600672 def testParseSubject(self):
673 """Test parsing of the patch subject"""
674 patch = status.Patch('1')
675
676 # Simple patch not in a series
677 patch.parse_subject('Testing')
678 self.assertEqual('Testing', patch.raw_subject)
679 self.assertEqual('Testing', patch.subject)
680 self.assertEqual(1, patch.seq)
681 self.assertEqual(1, patch.count)
682 self.assertEqual(None, patch.prefix)
683 self.assertEqual(None, patch.version)
684
685 # First patch in a series
686 patch.parse_subject('[1/2] Testing')
687 self.assertEqual('[1/2] Testing', patch.raw_subject)
688 self.assertEqual('Testing', patch.subject)
689 self.assertEqual(1, patch.seq)
690 self.assertEqual(2, patch.count)
691 self.assertEqual(None, patch.prefix)
692 self.assertEqual(None, patch.version)
693
694 # Second patch in a series
695 patch.parse_subject('[2/2] Testing')
696 self.assertEqual('Testing', patch.subject)
697 self.assertEqual(2, patch.seq)
698 self.assertEqual(2, patch.count)
699 self.assertEqual(None, patch.prefix)
700 self.assertEqual(None, patch.version)
701
702 # RFC patch
703 patch.parse_subject('[RFC,3/7] Testing')
704 self.assertEqual('Testing', patch.subject)
705 self.assertEqual(3, patch.seq)
706 self.assertEqual(7, patch.count)
707 self.assertEqual('RFC', patch.prefix)
708 self.assertEqual(None, patch.version)
709
710 # Version patch
711 patch.parse_subject('[v2,3/7] Testing')
712 self.assertEqual('Testing', patch.subject)
713 self.assertEqual(3, patch.seq)
714 self.assertEqual(7, patch.count)
715 self.assertEqual(None, patch.prefix)
716 self.assertEqual('v2', patch.version)
717
718 # All fields
719 patch.parse_subject('[RESEND,v2,3/7] Testing')
720 self.assertEqual('Testing', patch.subject)
721 self.assertEqual(3, patch.seq)
722 self.assertEqual(7, patch.count)
723 self.assertEqual('RESEND', patch.prefix)
724 self.assertEqual('v2', patch.version)
725
726 # RFC only
727 patch.parse_subject('[RESEND] Testing')
728 self.assertEqual('Testing', patch.subject)
729 self.assertEqual(1, patch.seq)
730 self.assertEqual(1, patch.count)
731 self.assertEqual('RESEND', patch.prefix)
732 self.assertEqual(None, patch.version)
733
Simon Glassdc6df972020-10-29 21:46:35 -0600734 def testCompareSeries(self):
735 """Test operation of compare_with_series()"""
736 commit1 = Commit('abcd')
737 commit1.subject = 'Subject 1'
738 commit2 = Commit('ef12')
739 commit2.subject = 'Subject 2'
740 commit3 = Commit('3456')
741 commit3.subject = 'Subject 2'
742
743 patch1 = status.Patch('1')
744 patch1.subject = 'Subject 1'
745 patch2 = status.Patch('2')
746 patch2.subject = 'Subject 2'
747 patch3 = status.Patch('3')
748 patch3.subject = 'Subject 2'
749
750 series = Series()
751 series.commits = [commit1]
752 patches = [patch1]
753 patch_for_commit, commit_for_patch, warnings = (
754 status.compare_with_series(series, patches))
755 self.assertEqual(1, len(patch_for_commit))
756 self.assertEqual(patch1, patch_for_commit[0])
757 self.assertEqual(1, len(commit_for_patch))
758 self.assertEqual(commit1, commit_for_patch[0])
759
760 series.commits = [commit1]
761 patches = [patch1, patch2]
762 patch_for_commit, commit_for_patch, warnings = (
763 status.compare_with_series(series, patches))
764 self.assertEqual(1, len(patch_for_commit))
765 self.assertEqual(patch1, patch_for_commit[0])
766 self.assertEqual(1, len(commit_for_patch))
767 self.assertEqual(commit1, commit_for_patch[0])
768 self.assertEqual(["Cannot find commit for patch 2 ('Subject 2')"],
769 warnings)
770
771 series.commits = [commit1, commit2]
772 patches = [patch1]
773 patch_for_commit, commit_for_patch, warnings = (
774 status.compare_with_series(series, patches))
775 self.assertEqual(1, len(patch_for_commit))
776 self.assertEqual(patch1, patch_for_commit[0])
777 self.assertEqual(1, len(commit_for_patch))
778 self.assertEqual(commit1, commit_for_patch[0])
779 self.assertEqual(["Cannot find patch for commit 2 ('Subject 2')"],
780 warnings)
781
782 series.commits = [commit1, commit2, commit3]
783 patches = [patch1, patch2]
784 patch_for_commit, commit_for_patch, warnings = (
785 status.compare_with_series(series, patches))
786 self.assertEqual(2, len(patch_for_commit))
787 self.assertEqual(patch1, patch_for_commit[0])
788 self.assertEqual(patch2, patch_for_commit[1])
789 self.assertEqual(1, len(commit_for_patch))
790 self.assertEqual(commit1, commit_for_patch[0])
791 self.assertEqual(["Cannot find patch for commit 3 ('Subject 2')",
792 "Multiple commits match patch 2 ('Subject 2'):\n"
793 ' Subject 2\n Subject 2'],
794 warnings)
795
796 series.commits = [commit1, commit2]
797 patches = [patch1, patch2, patch3]
798 patch_for_commit, commit_for_patch, warnings = (
799 status.compare_with_series(series, patches))
800 self.assertEqual(1, len(patch_for_commit))
801 self.assertEqual(patch1, patch_for_commit[0])
802 self.assertEqual(2, len(commit_for_patch))
803 self.assertEqual(commit1, commit_for_patch[0])
804 self.assertEqual(["Multiple patches match commit 2 ('Subject 2'):\n"
805 ' Subject 2\n Subject 2',
806 "Cannot find commit for patch 3 ('Subject 2')"],
807 warnings)
808
Simon Glass7cbf02e2020-11-03 13:54:14 -0700809 def _fake_patchwork2(self, url, subpath):
Simon Glassdc6df972020-10-29 21:46:35 -0600810 """Fake Patchwork server for the function below
811
812 This handles accessing series, patches and comments, providing the data
813 in self.patches to the caller
Simon Glass7cbf02e2020-11-03 13:54:14 -0700814
815 Args:
816 url (str): URL of patchwork server
817 subpath (str): URL subpath to use
Simon Glassdc6df972020-10-29 21:46:35 -0600818 """
819 re_series = re.match(r'series/(\d*)/$', subpath)
820 re_patch = re.match(r'patches/(\d*)/$', subpath)
821 re_comments = re.match(r'patches/(\d*)/comments/$', subpath)
822 if re_series:
823 series_num = re_series.group(1)
824 if series_num == '1234':
825 return {'patches': self.patches}
826 elif re_patch:
827 patch_num = int(re_patch.group(1))
828 patch = self.patches[patch_num - 1]
829 return patch
830 elif re_comments:
831 patch_num = int(re_comments.group(1))
832 patch = self.patches[patch_num - 1]
833 return patch.comments
834 raise ValueError('Fake Patchwork does not understand: %s' % subpath)
835
Simon Glassdc6df972020-10-29 21:46:35 -0600836 def testFindNewResponses(self):
837 """Test operation of find_new_responses()"""
838 commit1 = Commit('abcd')
839 commit1.subject = 'Subject 1'
840 commit2 = Commit('ef12')
841 commit2.subject = 'Subject 2'
842
843 patch1 = status.Patch('1')
844 patch1.parse_subject('[1/2] Subject 1')
845 patch1.name = patch1.raw_subject
846 patch1.content = 'This is my patch content'
847 comment1a = {'content': 'Reviewed-by: %s\n' % self.joe}
848
849 patch1.comments = [comment1a]
850
851 patch2 = status.Patch('2')
852 patch2.parse_subject('[2/2] Subject 2')
853 patch2.name = patch2.raw_subject
854 patch2.content = 'Some other patch content'
855 comment2a = {
856 'content': 'Reviewed-by: %s\nTested-by: %s\n' %
857 (self.mary, self.leb)}
858 comment2b = {'content': 'Reviewed-by: %s' % self.fred}
859 patch2.comments = [comment2a, comment2b]
860
861 # This test works by setting up commits and patch for use by the fake
862 # Rest API function _fake_patchwork2(). It calls various functions in
863 # the status module after setting up tags in the commits, checking that
864 # things behaves as expected
865 self.commits = [commit1, commit2]
866 self.patches = [patch1, patch2]
867 count = 2
868 new_rtag_list = [None] * count
Simon Glassdc4b2a92020-10-29 21:46:38 -0600869 review_list = [None, None]
Simon Glassdc6df972020-10-29 21:46:35 -0600870
871 # Check that the tags are picked up on the first patch
Simon Glassdc4b2a92020-10-29 21:46:38 -0600872 status.find_new_responses(new_rtag_list, review_list, 0, commit1,
Simon Glass7cbf02e2020-11-03 13:54:14 -0700873 patch1, None, self._fake_patchwork2)
Simon Glassdc6df972020-10-29 21:46:35 -0600874 self.assertEqual(new_rtag_list[0], {'Reviewed-by': {self.joe}})
875
876 # Now the second patch
Simon Glassdc4b2a92020-10-29 21:46:38 -0600877 status.find_new_responses(new_rtag_list, review_list, 1, commit2,
Simon Glass7cbf02e2020-11-03 13:54:14 -0700878 patch2, None, self._fake_patchwork2)
Simon Glassdc6df972020-10-29 21:46:35 -0600879 self.assertEqual(new_rtag_list[1], {
880 'Reviewed-by': {self.mary, self.fred},
881 'Tested-by': {self.leb}})
882
883 # Now add some tags to the commit, which means they should not appear as
884 # 'new' tags when scanning comments
885 new_rtag_list = [None] * count
886 commit1.rtags = {'Reviewed-by': {self.joe}}
Simon Glassdc4b2a92020-10-29 21:46:38 -0600887 status.find_new_responses(new_rtag_list, review_list, 0, commit1,
Simon Glass7cbf02e2020-11-03 13:54:14 -0700888 patch1, None, self._fake_patchwork2)
Simon Glassdc6df972020-10-29 21:46:35 -0600889 self.assertEqual(new_rtag_list[0], {})
890
891 # For the second commit, add Ed and Fred, so only Mary should be left
892 commit2.rtags = {
893 'Tested-by': {self.leb},
894 'Reviewed-by': {self.fred}}
Simon Glassdc4b2a92020-10-29 21:46:38 -0600895 status.find_new_responses(new_rtag_list, review_list, 1, commit2,
Simon Glass7cbf02e2020-11-03 13:54:14 -0700896 patch2, None, self._fake_patchwork2)
Simon Glassdc6df972020-10-29 21:46:35 -0600897 self.assertEqual(new_rtag_list[1], {'Reviewed-by': {self.mary}})
898
899 # Check that the output patches expectations:
900 # 1 Subject 1
901 # Reviewed-by: Joe Bloggs <joe@napierwallies.co.nz>
902 # 2 Subject 2
903 # Tested-by: Lord Edmund Blackaddër <weasel@blackadder.org>
904 # Reviewed-by: Fred Bloggs <f.bloggs@napier.net>
905 # + Reviewed-by: Mary Bloggs <mary@napierwallies.co.nz>
906 # 1 new response available in patchwork
907
908 series = Series()
909 series.commits = [commit1, commit2]
910 terminal.SetPrintTestMode()
Simon Glassdc4b2a92020-10-29 21:46:38 -0600911 status.check_patchwork_status(series, '1234', None, None, False, False,
Simon Glass7cbf02e2020-11-03 13:54:14 -0700912 None, self._fake_patchwork2)
Simon Glassdc6df972020-10-29 21:46:35 -0600913 lines = iter(terminal.GetPrintTestLines())
914 col = terminal.Color()
915 self.assertEqual(terminal.PrintLine(' 1 Subject 1', col.BLUE),
916 next(lines))
917 self.assertEqual(
918 terminal.PrintLine(' Reviewed-by: ', col.GREEN, newline=False,
919 bright=False),
920 next(lines))
921 self.assertEqual(terminal.PrintLine(self.joe, col.WHITE, bright=False),
922 next(lines))
923
924 self.assertEqual(terminal.PrintLine(' 2 Subject 2', col.BLUE),
925 next(lines))
926 self.assertEqual(
Simon Glassdc6df972020-10-29 21:46:35 -0600927 terminal.PrintLine(' Reviewed-by: ', col.GREEN, newline=False,
928 bright=False),
929 next(lines))
930 self.assertEqual(terminal.PrintLine(self.fred, col.WHITE, bright=False),
931 next(lines))
932 self.assertEqual(
Simon Glassdc4b2a92020-10-29 21:46:38 -0600933 terminal.PrintLine(' Tested-by: ', col.GREEN, newline=False,
934 bright=False),
935 next(lines))
936 self.assertEqual(terminal.PrintLine(self.leb, col.WHITE, bright=False),
937 next(lines))
938 self.assertEqual(
Simon Glassdc6df972020-10-29 21:46:35 -0600939 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
940 next(lines))
941 self.assertEqual(terminal.PrintLine(self.mary, col.WHITE),
942 next(lines))
943 self.assertEqual(terminal.PrintLine(
Simon Glass8f9ba3a2020-10-29 21:46:36 -0600944 '1 new response available in patchwork (use -d to write them to a new branch)',
945 None), next(lines))
946
Simon Glass7cbf02e2020-11-03 13:54:14 -0700947 def _fake_patchwork3(self, url, subpath):
Simon Glass8f9ba3a2020-10-29 21:46:36 -0600948 """Fake Patchwork server for the function below
949
950 This handles accessing series, patches and comments, providing the data
951 in self.patches to the caller
Simon Glass7cbf02e2020-11-03 13:54:14 -0700952
953 Args:
954 url (str): URL of patchwork server
955 subpath (str): URL subpath to use
Simon Glass8f9ba3a2020-10-29 21:46:36 -0600956 """
957 re_series = re.match(r'series/(\d*)/$', subpath)
958 re_patch = re.match(r'patches/(\d*)/$', subpath)
959 re_comments = re.match(r'patches/(\d*)/comments/$', subpath)
960 if re_series:
961 series_num = re_series.group(1)
962 if series_num == '1234':
963 return {'patches': self.patches}
964 elif re_patch:
965 patch_num = int(re_patch.group(1))
966 patch = self.patches[patch_num - 1]
967 return patch
968 elif re_comments:
969 patch_num = int(re_comments.group(1))
970 patch = self.patches[patch_num - 1]
971 return patch.comments
972 raise ValueError('Fake Patchwork does not understand: %s' % subpath)
973
Simon Glass8f9ba3a2020-10-29 21:46:36 -0600974 def testCreateBranch(self):
975 """Test operation of create_branch()"""
976 repo = self.make_git_tree()
977 branch = 'first'
978 dest_branch = 'first2'
979 count = 2
980 gitdir = os.path.join(self.gitdir, '.git')
981
982 # Set up the test git tree. We use branch 'first' which has two commits
983 # in it
984 series = patchstream.get_metadata_for_list(branch, gitdir, count)
985 self.assertEqual(2, len(series.commits))
986
987 patch1 = status.Patch('1')
988 patch1.parse_subject('[1/2] %s' % series.commits[0].subject)
989 patch1.name = patch1.raw_subject
990 patch1.content = 'This is my patch content'
991 comment1a = {'content': 'Reviewed-by: %s\n' % self.joe}
992
993 patch1.comments = [comment1a]
994
995 patch2 = status.Patch('2')
996 patch2.parse_subject('[2/2] %s' % series.commits[1].subject)
997 patch2.name = patch2.raw_subject
998 patch2.content = 'Some other patch content'
999 comment2a = {
1000 'content': 'Reviewed-by: %s\nTested-by: %s\n' %
1001 (self.mary, self.leb)}
1002 comment2b = {
1003 'content': 'Reviewed-by: %s' % self.fred}
1004 patch2.comments = [comment2a, comment2b]
1005
1006 # This test works by setting up patches for use by the fake Rest API
1007 # function _fake_patchwork3(). The fake patch comments above should
1008 # result in new review tags that are collected and added to the commits
1009 # created in the destination branch.
1010 self.patches = [patch1, patch2]
1011 count = 2
1012
1013 # Expected output:
1014 # 1 i2c: I2C things
1015 # + Reviewed-by: Joe Bloggs <joe@napierwallies.co.nz>
1016 # 2 spi: SPI fixes
1017 # + Reviewed-by: Fred Bloggs <f.bloggs@napier.net>
1018 # + Reviewed-by: Mary Bloggs <mary@napierwallies.co.nz>
1019 # + Tested-by: Lord Edmund Blackaddër <weasel@blackadder.org>
1020 # 4 new responses available in patchwork
1021 # 4 responses added from patchwork into new branch 'first2'
1022 # <unittest.result.TestResult run=8 errors=0 failures=0>
1023
1024 terminal.SetPrintTestMode()
1025 status.check_patchwork_status(series, '1234', branch, dest_branch,
Simon Glass7cbf02e2020-11-03 13:54:14 -07001026 False, False, None, self._fake_patchwork3,
1027 repo)
Simon Glass8f9ba3a2020-10-29 21:46:36 -06001028 lines = terminal.GetPrintTestLines()
1029 self.assertEqual(12, len(lines))
1030 self.assertEqual(
1031 "4 responses added from patchwork into new branch 'first2'",
1032 lines[11].text)
1033
1034 # Check that the destination branch has the new tags
1035 new_series = patchstream.get_metadata_for_list(dest_branch, gitdir,
1036 count)
1037 self.assertEqual(
1038 {'Reviewed-by': {self.joe}},
1039 new_series.commits[0].rtags)
1040 self.assertEqual(
1041 {'Tested-by': {self.leb},
1042 'Reviewed-by': {self.fred, self.mary}},
1043 new_series.commits[1].rtags)
1044
1045 # Now check the actual test of the first commit message. We expect to
1046 # see the new tags immediately below the old ones.
1047 stdout = patchstream.get_list(dest_branch, count=count, git_dir=gitdir)
1048 lines = iter([line.strip() for line in stdout.splitlines()
1049 if '-by:' in line])
1050
1051 # First patch should have the review tag
1052 self.assertEqual('Reviewed-by: %s' % self.joe, next(lines))
1053
1054 # Second patch should have the sign-off then the tested-by and two
1055 # reviewed-by tags
1056 self.assertEqual('Signed-off-by: %s' % self.leb, next(lines))
1057 self.assertEqual('Reviewed-by: %s' % self.fred, next(lines))
1058 self.assertEqual('Reviewed-by: %s' % self.mary, next(lines))
1059 self.assertEqual('Tested-by: %s' % self.leb, next(lines))
Simon Glass6b3252e2020-10-29 21:46:37 -06001060
1061 def testParseSnippets(self):
1062 """Test parsing of review snippets"""
1063 text = '''Hi Fred,
1064
1065This is a comment from someone.
1066
1067Something else
1068
1069On some recent date, Fred wrote:
1070> This is why I wrote the patch
1071> so here it is
1072
1073Now a comment about the commit message
1074A little more to say
1075
1076Even more
1077
1078> diff --git a/file.c b/file.c
1079> Some more code
1080> Code line 2
1081> Code line 3
1082> Code line 4
1083> Code line 5
1084> Code line 6
1085> Code line 7
1086> Code line 8
1087> Code line 9
1088
1089And another comment
1090
1091> @@ -153,8 +143,13 @@ def CheckPatch(fname, show_types=False):
1092> further down on the file
1093> and more code
1094> +Addition here
1095> +Another addition here
1096> codey
1097> more codey
1098
1099and another thing in same file
1100
1101> @@ -253,8 +243,13 @@
1102> with no function context
1103
1104one more thing
1105
1106> diff --git a/tools/patman/main.py b/tools/patman/main.py
1107> +line of code
1108now a very long comment in a different file
1109line2
1110line3
1111line4
1112line5
1113line6
1114line7
1115line8
1116'''
1117 pstrm = PatchStream.process_text(text, True)
1118 self.assertEqual([], pstrm.commit.warn)
1119
1120 # We expect to the filename and up to 5 lines of code context before
1121 # each comment. The 'On xxx wrote:' bit should be removed.
1122 self.assertEqual(
1123 [['Hi Fred,',
1124 'This is a comment from someone.',
1125 'Something else'],
1126 ['> This is why I wrote the patch',
1127 '> so here it is',
1128 'Now a comment about the commit message',
1129 'A little more to say', 'Even more'],
1130 ['> File: file.c', '> Code line 5', '> Code line 6',
1131 '> Code line 7', '> Code line 8', '> Code line 9',
1132 'And another comment'],
1133 ['> File: file.c',
1134 '> Line: 153 / 143: def CheckPatch(fname, show_types=False):',
1135 '> and more code', '> +Addition here', '> +Another addition here',
1136 '> codey', '> more codey', 'and another thing in same file'],
1137 ['> File: file.c', '> Line: 253 / 243',
1138 '> with no function context', 'one more thing'],
1139 ['> File: tools/patman/main.py', '> +line of code',
1140 'now a very long comment in a different file',
1141 'line2', 'line3', 'line4', 'line5', 'line6', 'line7', 'line8']],
1142 pstrm.snippets)
Simon Glassdc4b2a92020-10-29 21:46:38 -06001143
Simon Glassdc4b2a92020-10-29 21:46:38 -06001144 def testReviewSnippets(self):
1145 """Test showing of review snippets"""
1146 def _to_submitter(who):
1147 m_who = re.match('(.*) <(.*)>', who)
1148 return {
1149 'name': m_who.group(1),
1150 'email': m_who.group(2)
1151 }
1152
1153 commit1 = Commit('abcd')
1154 commit1.subject = 'Subject 1'
1155 commit2 = Commit('ef12')
1156 commit2.subject = 'Subject 2'
1157
1158 patch1 = status.Patch('1')
1159 patch1.parse_subject('[1/2] Subject 1')
1160 patch1.name = patch1.raw_subject
1161 patch1.content = 'This is my patch content'
1162 comment1a = {'submitter': _to_submitter(self.joe),
1163 'content': '''Hi Fred,
1164
1165On some date Fred wrote:
1166
1167> diff --git a/file.c b/file.c
1168> Some code
1169> and more code
1170
1171Here is my comment above the above...
1172
1173
1174Reviewed-by: %s
1175''' % self.joe}
1176
1177 patch1.comments = [comment1a]
1178
1179 patch2 = status.Patch('2')
1180 patch2.parse_subject('[2/2] Subject 2')
1181 patch2.name = patch2.raw_subject
1182 patch2.content = 'Some other patch content'
1183 comment2a = {
1184 'content': 'Reviewed-by: %s\nTested-by: %s\n' %
1185 (self.mary, self.leb)}
1186 comment2b = {'submitter': _to_submitter(self.fred),
1187 'content': '''Hi Fred,
1188
1189On some date Fred wrote:
1190
1191> diff --git a/tools/patman/commit.py b/tools/patman/commit.py
1192> @@ -41,6 +41,9 @@ class Commit:
1193> self.rtags = collections.defaultdict(set)
1194> self.warn = []
1195>
1196> + def __str__(self):
1197> + return self.subject
1198> +
1199> def AddChange(self, version, info):
1200> """Add a new change line to the change list for a version.
1201>
1202A comment
1203
1204Reviewed-by: %s
1205''' % self.fred}
1206 patch2.comments = [comment2a, comment2b]
1207
1208 # This test works by setting up commits and patch for use by the fake
1209 # Rest API function _fake_patchwork2(). It calls various functions in
1210 # the status module after setting up tags in the commits, checking that
1211 # things behaves as expected
1212 self.commits = [commit1, commit2]
1213 self.patches = [patch1, patch2]
1214
1215 # Check that the output patches expectations:
1216 # 1 Subject 1
1217 # Reviewed-by: Joe Bloggs <joe@napierwallies.co.nz>
1218 # 2 Subject 2
1219 # Tested-by: Lord Edmund Blackaddër <weasel@blackadder.org>
1220 # Reviewed-by: Fred Bloggs <f.bloggs@napier.net>
1221 # + Reviewed-by: Mary Bloggs <mary@napierwallies.co.nz>
1222 # 1 new response available in patchwork
1223
1224 series = Series()
1225 series.commits = [commit1, commit2]
1226 terminal.SetPrintTestMode()
1227 status.check_patchwork_status(series, '1234', None, None, False, True,
Simon Glass7cbf02e2020-11-03 13:54:14 -07001228 None, self._fake_patchwork2)
Simon Glassdc4b2a92020-10-29 21:46:38 -06001229 lines = iter(terminal.GetPrintTestLines())
1230 col = terminal.Color()
1231 self.assertEqual(terminal.PrintLine(' 1 Subject 1', col.BLUE),
1232 next(lines))
1233 self.assertEqual(
1234 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
1235 next(lines))
1236 self.assertEqual(terminal.PrintLine(self.joe, col.WHITE), next(lines))
1237
1238 self.assertEqual(terminal.PrintLine('Review: %s' % self.joe, col.RED),
1239 next(lines))
1240 self.assertEqual(terminal.PrintLine(' Hi Fred,', None), next(lines))
1241 self.assertEqual(terminal.PrintLine('', None), next(lines))
1242 self.assertEqual(terminal.PrintLine(' > File: file.c', col.MAGENTA),
1243 next(lines))
1244 self.assertEqual(terminal.PrintLine(' > Some code', col.MAGENTA),
1245 next(lines))
1246 self.assertEqual(terminal.PrintLine(' > and more code', col.MAGENTA),
1247 next(lines))
1248 self.assertEqual(terminal.PrintLine(
1249 ' Here is my comment above the above...', None), next(lines))
1250 self.assertEqual(terminal.PrintLine('', None), next(lines))
1251
1252 self.assertEqual(terminal.PrintLine(' 2 Subject 2', col.BLUE),
1253 next(lines))
1254 self.assertEqual(
1255 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
1256 next(lines))
1257 self.assertEqual(terminal.PrintLine(self.fred, col.WHITE),
1258 next(lines))
1259 self.assertEqual(
1260 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
1261 next(lines))
1262 self.assertEqual(terminal.PrintLine(self.mary, col.WHITE),
1263 next(lines))
1264 self.assertEqual(
1265 terminal.PrintLine(' + Tested-by: ', col.GREEN, newline=False),
1266 next(lines))
1267 self.assertEqual(terminal.PrintLine(self.leb, col.WHITE),
1268 next(lines))
1269
1270 self.assertEqual(terminal.PrintLine('Review: %s' % self.fred, col.RED),
1271 next(lines))
1272 self.assertEqual(terminal.PrintLine(' Hi Fred,', None), next(lines))
1273 self.assertEqual(terminal.PrintLine('', None), next(lines))
1274 self.assertEqual(terminal.PrintLine(
1275 ' > File: tools/patman/commit.py', col.MAGENTA), next(lines))
1276 self.assertEqual(terminal.PrintLine(
1277 ' > Line: 41 / 41: class Commit:', col.MAGENTA), next(lines))
1278 self.assertEqual(terminal.PrintLine(
1279 ' > + return self.subject', col.MAGENTA), next(lines))
1280 self.assertEqual(terminal.PrintLine(
1281 ' > +', col.MAGENTA), next(lines))
1282 self.assertEqual(
1283 terminal.PrintLine(' > def AddChange(self, version, info):',
1284 col.MAGENTA),
1285 next(lines))
1286 self.assertEqual(terminal.PrintLine(
1287 ' > """Add a new change line to the change list for a version.',
1288 col.MAGENTA), next(lines))
1289 self.assertEqual(terminal.PrintLine(
1290 ' >', col.MAGENTA), next(lines))
1291 self.assertEqual(terminal.PrintLine(
1292 ' A comment', None), next(lines))
1293 self.assertEqual(terminal.PrintLine('', None), next(lines))
1294
1295 self.assertEqual(terminal.PrintLine(
1296 '4 new responses available in patchwork (use -d to write them to a new branch)',
1297 None), next(lines))
Simon Glass59747182021-08-01 16:02:39 -06001298
1299 def testInsertTags(self):
1300 """Test inserting of review tags"""
1301 msg = '''first line
1302second line.'''
1303 tags = [
1304 'Reviewed-by: Bin Meng <bmeng.cn@gmail.com>',
1305 'Tested-by: Bin Meng <bmeng.cn@gmail.com>'
1306 ]
1307 signoff = 'Signed-off-by: Simon Glass <sjg@chromium.com>'
1308 tag_str = '\n'.join(tags)
1309
1310 new_msg = patchstream.insert_tags(msg, tags)
1311 self.assertEqual(msg + '\n\n' + tag_str, new_msg)
1312
1313 new_msg = patchstream.insert_tags(msg + '\n', tags)
1314 self.assertEqual(msg + '\n\n' + tag_str, new_msg)
1315
1316 msg += '\n\n' + signoff
1317 new_msg = patchstream.insert_tags(msg, tags)
1318 self.assertEqual(msg + '\n' + tag_str, new_msg)