blob: 1ce6448d00b0e36dc75649d71f35d78cfaee2b92 [file] [log] [blame]
Simon Glassdf1bc5c2017-05-29 15:31:31 -06001# -*- coding: utf-8 -*-
Tom Rini10e47792018-05-06 17:58:06 -04002# SPDX-License-Identifier: GPL-2.0+
Simon Glassdf1bc5c2017-05-29 15:31:31 -06003#
4# Copyright 2017 Google, Inc
5#
Simon Glassdf1bc5c2017-05-29 15:31:31 -06006
Simon Glasseb209e52020-10-29 21:46:15 -06007"""Functional tests for checking that patman behaves correctly"""
8
Simon Glassdf1bc5c2017-05-29 15:31:31 -06009import os
10import re
11import shutil
12import sys
13import tempfile
14import unittest
15
Simon Glass3db916d2020-10-29 21:46:35 -060016
17from patman.commit import Commit
Simon Glass54f1c5b2020-07-05 21:41:50 -060018from patman import control
Simon Glassa997ea52020-04-17 18:09:04 -060019from patman import gitutil
20from patman import patchstream
Simon Glassa7fadab2020-10-29 21:46:26 -060021from patman.patchstream import PatchStream
Simon Glass3db916d2020-10-29 21:46:35 -060022from patman.series import Series
Simon Glassa997ea52020-04-17 18:09:04 -060023from patman import settings
Simon Glass54f1c5b2020-07-05 21:41:50 -060024from patman import terminal
Simon Glassa997ea52020-04-17 18:09:04 -060025from patman import tools
Simon Glass54f1c5b2020-07-05 21:41:50 -060026from patman.test_util import capture_sys_output
Simon Glassdf1bc5c2017-05-29 15:31:31 -060027
Tom Rini488ea972021-02-26 07:52:31 -050028import pygit2
29from patman import status
Simon Glassdf1bc5c2017-05-29 15:31:31 -060030
31class TestFunctional(unittest.TestCase):
Simon Glasseb209e52020-10-29 21:46:15 -060032 """Functional tests for checking that patman behaves correctly"""
Simon Glass06202d62020-10-29 21:46:27 -060033 leb = (b'Lord Edmund Blackadd\xc3\xabr <weasel@blackadder.org>'.
34 decode('utf-8'))
Simon Glass3b762cc2020-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 Glass3db916d2020-10-29 21:46:35 -060038 commits = None
39 patches = None
Simon Glass06202d62020-10-29 21:46:27 -060040
Simon Glassdf1bc5c2017-05-29 15:31:31 -060041 def setUp(self):
42 self.tmpdir = tempfile.mkdtemp(prefix='patman.')
Simon Glass54f1c5b2020-07-05 21:41:50 -060043 self.gitdir = os.path.join(self.tmpdir, 'git')
44 self.repo = None
Simon Glassdf1bc5c2017-05-29 15:31:31 -060045
46 def tearDown(self):
47 shutil.rmtree(self.tmpdir)
Simon Glass3db916d2020-10-29 21:46:35 -060048 terminal.SetPrintTestMode(False)
Simon Glassdf1bc5c2017-05-29 15:31:31 -060049
50 @staticmethod
Simon Glasseb209e52020-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 Glassdf1bc5c2017-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 Glasseb209e52020-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 Glassdf1bc5c2017-05-29 15:31:31 -060074
75 @classmethod
Simon Glasseb209e52020-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 Glassdf1bc5c2017-05-29 15:31:31 -060085 fname = re.sub('[ :]', '-', subject)
86 return fname.replace('--', '-')
87
Simon Glasseb209e52020-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 Glassdf1bc5c2017-05-29 15:31:31 -0600101 cover_fname = None
102 fname_list = []
103 for i, commit in enumerate(series.commits):
Simon Glasseb209e52020-10-29 21:46:15 -0600104 clean_subject = self._get_patch_name(commit.subject)
Simon Glassdf1bc5c2017-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 Glasseb209e52020-10-29 21:46:15 -0600107 shutil.copy(self._get_path(src_fname), fname)
Simon Glassdf1bc5c2017-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 Glasseb209e52020-10-29 21:46:15 -0600113 shutil.copy(self._get_path(src_fname), fname)
Simon Glassdf1bc5c2017-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
125 Series-cc: Stefan Brüns <stefan.bruens@rwth-aachen.de>
126 Cover-letter-cc: Lord Mëlchett <clergy@palace.gov>
Sean Andersoncf13b862020-05-04 16:28:36 -0400127 Series-version: 3
128 Patch-cc: fred
129 Series-process-log: sort, uniq
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600130 Series-changes: 4
131 - Some changes
Sean Andersoncf13b862020-05-04 16:28:36 -0400132 - Multi
133 line
134 change
135
136 Commit-changes: 2
137 - Changes only for this commit
138
139 Cover-changes: 4
140 - Some notes for the cover letter
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600141
142 Cover-letter:
143 test: A test patch series
144 This is a test of how the cover
Sean Andersoncf13b862020-05-04 16:28:36 -0400145 letter
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600146 works
147 END
148
149 and this in the first commit:
150
Sean Andersoncf13b862020-05-04 16:28:36 -0400151 Commit-changes: 2
152 - second revision change
153
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600154 Series-notes:
155 some notes
156 about some things
157 from the first commit
158 END
159
160 Commit-notes:
161 Some notes about
162 the first commit
163 END
164
165 with the following commands:
166
167 git log -n2 --reverse >/path/to/tools/patman/test/test01.txt
168 git format-patch --subject-prefix RFC --cover-letter HEAD~2
169 mv 00* /path/to/tools/patman/test
170
171 It checks these aspects:
172 - git log can be processed by patchstream
173 - emailing patches uses the correct command
174 - CC file has information on each commit
175 - cover letter has the expected text and subject
176 - each patch has the correct subject
177 - dry-run information prints out correctly
178 - unicode is handled correctly
179 - Series-to, Series-cc, Series-prefix, Cover-letter
180 - Cover-letter-cc, Series-version, Series-changes, Series-notes
181 - Commit-notes
182 """
183 process_tags = True
Simon Glass1f975b92021-01-23 08:56:15 -0700184 ignore_bad_tags = False
Simon Glass4f817892019-05-14 15:53:53 -0600185 stefan = b'Stefan Br\xc3\xbcns <stefan.bruens@rwth-aachen.de>'.decode('utf-8')
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600186 rick = 'Richard III <richard@palace.gov>'
Simon Glass4f817892019-05-14 15:53:53 -0600187 mel = b'Lord M\xc3\xablchett <clergy@palace.gov>'.decode('utf-8')
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600188 add_maintainers = [stefan, rick]
189 dry_run = True
190 in_reply_to = mel
191 count = 2
192 settings.alias = {
Simon Glass95745aa2020-10-29 21:46:13 -0600193 'fdt': ['simon'],
194 'u-boot': ['u-boot@lists.denx.de'],
Simon Glass06202d62020-10-29 21:46:27 -0600195 'simon': [self.leb],
Simon Glass3b762cc2020-10-29 21:46:28 -0600196 'fred': [self.fred],
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600197 }
198
Simon Glasseb209e52020-10-29 21:46:15 -0600199 text = self._get_text('test01.txt')
Simon Glass93f61c02020-10-29 21:46:19 -0600200 series = patchstream.get_metadata_for_test(text)
Simon Glasseb209e52020-10-29 21:46:15 -0600201 cover_fname, args = self._create_patches_for_test(series)
Simon Glass59a70bb2020-10-29 21:46:14 -0600202 with capture_sys_output() as out:
Simon Glass93f61c02020-10-29 21:46:19 -0600203 patchstream.fix_patches(series, args)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600204 if cover_fname and series.get('cover'):
Simon Glass93f61c02020-10-29 21:46:19 -0600205 patchstream.insert_cover_letter(cover_fname, series, count)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600206 series.DoChecks()
207 cc_file = series.MakeCcFile(process_tags, cover_fname,
Chris Packhamb84fb482018-06-07 20:45:06 +1200208 not ignore_bad_tags, add_maintainers,
209 None)
Simon Glass95745aa2020-10-29 21:46:13 -0600210 cmd = gitutil.EmailPatches(
211 series, cover_fname, args, dry_run, not ignore_bad_tags,
212 cc_file, in_reply_to=in_reply_to, thread=None)
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600213 series.ShowActions(args, cmd, process_tags)
Simon Glassf544a2d2019-10-31 07:42:51 -0600214 cc_lines = open(cc_file, encoding='utf-8').read().splitlines()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600215 os.remove(cc_file)
216
Simon Glass42e3d392020-10-29 21:46:29 -0600217 lines = iter(out[0].getvalue().splitlines())
218 self.assertEqual('Cleaned %s patches' % len(series.commits),
219 next(lines))
220 self.assertEqual('Change log missing for v2', next(lines))
221 self.assertEqual('Change log missing for v3', next(lines))
222 self.assertEqual('Change log for unknown version v4', next(lines))
223 self.assertEqual("Alias 'pci' not found", next(lines))
224 self.assertIn('Dry run', next(lines))
225 self.assertEqual('', next(lines))
226 self.assertIn('Send a total of %d patches' % count, next(lines))
227 prev = next(lines)
228 for i, commit in enumerate(series.commits):
229 self.assertEqual(' %s' % args[i], prev)
230 while True:
231 prev = next(lines)
232 if 'Cc:' not in prev:
233 break
234 self.assertEqual('To: u-boot@lists.denx.de', prev)
Simon Glass9dfb3112020-11-08 20:36:18 -0700235 self.assertEqual('Cc: %s' % stefan, next(lines))
Simon Glass42e3d392020-10-29 21:46:29 -0600236 self.assertEqual('Version: 3', next(lines))
237 self.assertEqual('Prefix:\t RFC', next(lines))
238 self.assertEqual('Cover: 4 lines', next(lines))
239 self.assertEqual(' Cc: %s' % self.fred, next(lines))
Simon Glass9dfb3112020-11-08 20:36:18 -0700240 self.assertEqual(' Cc: %s' % self.leb,
Simon Glass42e3d392020-10-29 21:46:29 -0600241 next(lines))
Simon Glass9dfb3112020-11-08 20:36:18 -0700242 self.assertEqual(' Cc: %s' % mel, next(lines))
Simon Glass42e3d392020-10-29 21:46:29 -0600243 self.assertEqual(' Cc: %s' % rick, next(lines))
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600244 expected = ('Git command: git send-email --annotate '
245 '--in-reply-to="%s" --to "u-boot@lists.denx.de" '
Simon Glass1ee91c12020-11-03 13:54:10 -0700246 '--cc "%s" --cc-cmd "%s send --cc-cmd %s" %s %s'
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600247 % (in_reply_to, stefan, sys.argv[0], cc_file, cover_fname,
Simon Glass4f817892019-05-14 15:53:53 -0600248 ' '.join(args)))
Simon Glass9dfb3112020-11-08 20:36:18 -0700249 self.assertEqual(expected, next(lines))
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600250
Simon Glass9dfb3112020-11-08 20:36:18 -0700251 self.assertEqual(('%s %s\0%s' % (args[0], rick, stefan)), cc_lines[0])
Simon Glass95745aa2020-10-29 21:46:13 -0600252 self.assertEqual(
Simon Glass3b762cc2020-10-29 21:46:28 -0600253 '%s %s\0%s\0%s\0%s' % (args[1], self.fred, self.leb, rick, stefan),
Simon Glass9dfb3112020-11-08 20:36:18 -0700254 cc_lines[1])
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600255
256 expected = '''
257This is a test of how the cover
Sean Andersoncf13b862020-05-04 16:28:36 -0400258letter
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600259works
260
261some notes
262about some things
263from the first commit
264
265Changes in v4:
Sean Andersoncf13b862020-05-04 16:28:36 -0400266- Multi
267 line
268 change
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600269- Some changes
Sean Andersoncf13b862020-05-04 16:28:36 -0400270- Some notes for the cover letter
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600271
272Simon Glass (2):
273 pci: Correct cast for sandbox
Siva Durga Prasad Paladugub3d55ea2018-07-16 15:56:11 +0530274 fdt: Correct cast for sandbox in fdtdec_setup_mem_size_base()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600275
276 cmd/pci.c | 3 ++-
277 fs/fat/fat.c | 1 +
278 lib/efi_loader/efi_memory.c | 1 +
279 lib/fdtdec.c | 3 ++-
280 4 files changed, 6 insertions(+), 2 deletions(-)
281
282--\x20
2832.7.4
284
285'''
Simon Glassf544a2d2019-10-31 07:42:51 -0600286 lines = open(cover_fname, encoding='utf-8').read().splitlines()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600287 self.assertEqual(
Simon Glass95745aa2020-10-29 21:46:13 -0600288 'Subject: [RFC PATCH v3 0/2] test: A test patch series',
289 lines[3])
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600290 self.assertEqual(expected.splitlines(), lines[7:])
291
292 for i, fname in enumerate(args):
Simon Glassf544a2d2019-10-31 07:42:51 -0600293 lines = open(fname, encoding='utf-8').read().splitlines()
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600294 subject = [line for line in lines if line.startswith('Subject')]
295 self.assertEqual('Subject: [RFC %d/%d]' % (i + 1, count),
296 subject[0][:18])
Sean Andersoncf13b862020-05-04 16:28:36 -0400297
298 # Check that we got our commit notes
299 start = 0
300 expected = ''
301
Simon Glassdf1bc5c2017-05-29 15:31:31 -0600302 if i == 0:
Sean Andersoncf13b862020-05-04 16:28:36 -0400303 start = 17
304 expected = '''---
305Some notes about
306the first commit
307
308(no changes since v2)
309
310Changes in v2:
311- second revision change'''
312 elif i == 1:
313 start = 17
314 expected = '''---
315
316Changes in v4:
317- Multi
318 line
319 change
320- Some changes
321
322Changes in v2:
323- Changes only for this commit'''
324
325 if expected:
326 expected = expected.splitlines()
327 self.assertEqual(expected, lines[start:(start+len(expected))])
Simon Glass54f1c5b2020-07-05 21:41:50 -0600328
329 def make_commit_with_file(self, subject, body, fname, text):
330 """Create a file and add it to the git repo with a new commit
331
332 Args:
333 subject (str): Subject for the commit
334 body (str): Body text of the commit
335 fname (str): Filename of file to create
336 text (str): Text to put into the file
337 """
338 path = os.path.join(self.gitdir, fname)
339 tools.WriteFile(path, text, binary=False)
340 index = self.repo.index
341 index.add(fname)
Simon Glass95745aa2020-10-29 21:46:13 -0600342 author = pygit2.Signature('Test user', 'test@email.com')
Simon Glass54f1c5b2020-07-05 21:41:50 -0600343 committer = author
344 tree = index.write_tree()
345 message = subject + '\n' + body
346 self.repo.create_commit('HEAD', author, committer, message, tree,
347 [self.repo.head.target])
348
349 def make_git_tree(self):
350 """Make a simple git tree suitable for testing
351
352 It has three branches:
353 'base' has two commits: PCI, main
354 'first' has base as upstream and two more commits: I2C, SPI
355 'second' has base as upstream and three more: video, serial, bootm
356
357 Returns:
Simon Glasseb209e52020-10-29 21:46:15 -0600358 pygit2.Repository: repository
Simon Glass54f1c5b2020-07-05 21:41:50 -0600359 """
360 repo = pygit2.init_repository(self.gitdir)
361 self.repo = repo
362 new_tree = repo.TreeBuilder().write()
363
364 author = pygit2.Signature('Test user', 'test@email.com')
365 committer = author
Simon Glasseb209e52020-10-29 21:46:15 -0600366 _ = repo.create_commit('HEAD', author, committer, 'Created master',
367 new_tree, [])
Simon Glass54f1c5b2020-07-05 21:41:50 -0600368
369 self.make_commit_with_file('Initial commit', '''
370Add a README
371
372''', 'README', '''This is the README file
373describing this project
374in very little detail''')
375
376 self.make_commit_with_file('pci: PCI implementation', '''
377Here is a basic PCI implementation
378
379''', 'pci.c', '''This is a file
380it has some contents
381and some more things''')
382 self.make_commit_with_file('main: Main program', '''
383Hello here is the second commit.
384''', 'main.c', '''This is the main file
385there is very little here
386but we can always add more later
387if we want to
388
389Series-to: u-boot
390Series-cc: Barry Crump <bcrump@whataroa.nz>
391''')
392 base_target = repo.revparse_single('HEAD')
393 self.make_commit_with_file('i2c: I2C things', '''
394This has some stuff to do with I2C
395''', 'i2c.c', '''And this is the file contents
396with some I2C-related things in it''')
397 self.make_commit_with_file('spi: SPI fixes', '''
398SPI needs some fixes
399and here they are
Simon Glassd0a0a582020-10-29 21:46:36 -0600400
401Signed-off-by: %s
402
403Series-to: u-boot
404Commit-notes:
405title of the series
406This is the cover letter for the series
407with various details
408END
409''' % self.leb, 'spi.c', '''Some fixes for SPI in this
Simon Glass54f1c5b2020-07-05 21:41:50 -0600410file to make SPI work
411better than before''')
412 first_target = repo.revparse_single('HEAD')
413
414 target = repo.revparse_single('HEAD~2')
415 repo.reset(target.oid, pygit2.GIT_CHECKOUT_FORCE)
416 self.make_commit_with_file('video: Some video improvements', '''
417Fix up the video so that
418it looks more purple. Purple is
419a very nice colour.
420''', 'video.c', '''More purple here
421Purple and purple
422Even more purple
423Could not be any more purple''')
424 self.make_commit_with_file('serial: Add a serial driver', '''
425Here is the serial driver
426for my chip.
427
428Cover-letter:
429Series for my board
430This series implements support
431for my glorious board.
432END
Simon Glassa80986c2020-10-29 21:46:16 -0600433Series-links: 183237
Simon Glass54f1c5b2020-07-05 21:41:50 -0600434''', 'serial.c', '''The code for the
435serial driver is here''')
436 self.make_commit_with_file('bootm: Make it boot', '''
437This makes my board boot
438with a fix to the bootm
439command
440''', 'bootm.c', '''Fix up the bootm
441command to make the code as
442complicated as possible''')
443 second_target = repo.revparse_single('HEAD')
444
445 repo.branches.local.create('first', first_target)
446 repo.config.set_multivar('branch.first.remote', '', '.')
447 repo.config.set_multivar('branch.first.merge', '', 'refs/heads/base')
448
449 repo.branches.local.create('second', second_target)
450 repo.config.set_multivar('branch.second.remote', '', '.')
451 repo.config.set_multivar('branch.second.merge', '', 'refs/heads/base')
452
453 repo.branches.local.create('base', base_target)
454 return repo
455
Simon Glass54f1c5b2020-07-05 21:41:50 -0600456 def testBranch(self):
457 """Test creating patches from a branch"""
458 repo = self.make_git_tree()
459 target = repo.lookup_reference('refs/heads/first')
460 self.repo.checkout(target, strategy=pygit2.GIT_CHECKOUT_FORCE)
461 control.setup()
462 try:
463 orig_dir = os.getcwd()
464 os.chdir(self.gitdir)
465
466 # Check that it can detect the current branch
Simon Glass2eb4da72020-07-05 21:41:51 -0600467 self.assertEqual(2, gitutil.CountCommitsToBranch(None))
Simon Glass54f1c5b2020-07-05 21:41:50 -0600468 col = terminal.Color()
469 with capture_sys_output() as _:
470 _, cover_fname, patch_files = control.prepare_patches(
Simon Glassb3bf4e12020-07-05 21:41:52 -0600471 col, branch=None, count=-1, start=0, end=0,
Philipp Tomsich858531a2020-11-24 18:14:52 +0100472 ignore_binary=False, signoff=True)
Simon Glass54f1c5b2020-07-05 21:41:50 -0600473 self.assertIsNone(cover_fname)
474 self.assertEqual(2, len(patch_files))
Simon Glass2eb4da72020-07-05 21:41:51 -0600475
476 # Check that it can detect a different branch
477 self.assertEqual(3, gitutil.CountCommitsToBranch('second'))
478 with capture_sys_output() as _:
479 _, cover_fname, patch_files = control.prepare_patches(
Simon Glassb3bf4e12020-07-05 21:41:52 -0600480 col, branch='second', count=-1, start=0, end=0,
Philipp Tomsich858531a2020-11-24 18:14:52 +0100481 ignore_binary=False, signoff=True)
Simon Glass2eb4da72020-07-05 21:41:51 -0600482 self.assertIsNotNone(cover_fname)
483 self.assertEqual(3, len(patch_files))
Simon Glassb3bf4e12020-07-05 21:41:52 -0600484
485 # Check that it can skip patches at the end
486 with capture_sys_output() as _:
487 _, cover_fname, patch_files = control.prepare_patches(
488 col, branch='second', count=-1, start=0, end=1,
Philipp Tomsich858531a2020-11-24 18:14:52 +0100489 ignore_binary=False, signoff=True)
Simon Glassb3bf4e12020-07-05 21:41:52 -0600490 self.assertIsNotNone(cover_fname)
491 self.assertEqual(2, len(patch_files))
Simon Glass54f1c5b2020-07-05 21:41:50 -0600492 finally:
493 os.chdir(orig_dir)
Simon Glass06202d62020-10-29 21:46:27 -0600494
495 def testTags(self):
496 """Test collection of tags in a patchstream"""
497 text = '''This is a patch
498
499Signed-off-by: Terminator
Simon Glass3b762cc2020-10-29 21:46:28 -0600500Reviewed-by: %s
501Reviewed-by: %s
Simon Glass06202d62020-10-29 21:46:27 -0600502Tested-by: %s
Simon Glass3b762cc2020-10-29 21:46:28 -0600503''' % (self.joe, self.mary, self.leb)
Simon Glass06202d62020-10-29 21:46:27 -0600504 pstrm = PatchStream.process_text(text)
505 self.assertEqual(pstrm.commit.rtags, {
Simon Glass3b762cc2020-10-29 21:46:28 -0600506 'Reviewed-by': {self.joe, self.mary},
Simon Glass06202d62020-10-29 21:46:27 -0600507 'Tested-by': {self.leb}})
Simon Glass3b762cc2020-10-29 21:46:28 -0600508
509 def testMissingEnd(self):
510 """Test a missing END tag"""
511 text = '''This is a patch
512
513Cover-letter:
514This is the title
515missing END after this line
516Signed-off-by: Fred
517'''
518 pstrm = PatchStream.process_text(text)
519 self.assertEqual(["Missing 'END' in section 'cover'"],
520 pstrm.commit.warn)
521
522 def testMissingBlankLine(self):
523 """Test a missing blank line after a tag"""
524 text = '''This is a patch
525
526Series-changes: 2
527- First line of changes
528- Missing blank line after this line
529Signed-off-by: Fred
530'''
531 pstrm = PatchStream.process_text(text)
532 self.assertEqual(["Missing 'blank line' in section 'Series-changes'"],
533 pstrm.commit.warn)
534
535 def testInvalidCommitTag(self):
536 """Test an invalid Commit-xxx tag"""
537 text = '''This is a patch
538
539Commit-fred: testing
540'''
541 pstrm = PatchStream.process_text(text)
542 self.assertEqual(["Line 3: Ignoring Commit-fred"], pstrm.commit.warn)
543
544 def testSelfTest(self):
545 """Test a tested by tag by this user"""
546 test_line = 'Tested-by: %s@napier.com' % os.getenv('USER')
547 text = '''This is a patch
548
549%s
550''' % test_line
551 pstrm = PatchStream.process_text(text)
552 self.assertEqual(["Ignoring '%s'" % test_line], pstrm.commit.warn)
553
554 def testSpaceBeforeTab(self):
555 """Test a space before a tab"""
556 text = '''This is a patch
557
558+ \tSomething
559'''
560 pstrm = PatchStream.process_text(text)
561 self.assertEqual(["Line 3/0 has space before tab"], pstrm.commit.warn)
562
563 def testLinesAfterTest(self):
564 """Test detecting lines after TEST= line"""
565 text = '''This is a patch
566
567TEST=sometest
568more lines
569here
570'''
571 pstrm = PatchStream.process_text(text)
572 self.assertEqual(["Found 2 lines after TEST="], pstrm.commit.warn)
573
574 def testBlankLineAtEnd(self):
575 """Test detecting a blank line at the end of a file"""
576 text = '''This is a patch
577
578diff --git a/lib/fdtdec.c b/lib/fdtdec.c
579index c072e54..942244f 100644
580--- a/lib/fdtdec.c
581+++ b/lib/fdtdec.c
582@@ -1200,7 +1200,8 @@ int fdtdec_setup_mem_size_base(void)
583 }
584
585 gd->ram_size = (phys_size_t)(res.end - res.start + 1);
586- debug("%s: Initial DRAM size %llx\n", __func__, (u64)gd->ram_size);
587+ debug("%s: Initial DRAM size %llx\n", __func__,
588+ (unsigned long long)gd->ram_size);
589+
590diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
591
592--
5932.7.4
594
595 '''
596 pstrm = PatchStream.process_text(text)
597 self.assertEqual(
598 ["Found possible blank line(s) at end of file 'lib/fdtdec.c'"],
599 pstrm.commit.warn)
Simon Glass1c1f2072020-10-29 21:46:34 -0600600
Simon Glass1c1f2072020-10-29 21:46:34 -0600601 def testNoUpstream(self):
602 """Test CountCommitsToBranch when there is no upstream"""
603 repo = self.make_git_tree()
604 target = repo.lookup_reference('refs/heads/base')
605 self.repo.checkout(target, strategy=pygit2.GIT_CHECKOUT_FORCE)
606
607 # Check that it can detect the current branch
608 try:
609 orig_dir = os.getcwd()
610 os.chdir(self.gitdir)
611 with self.assertRaises(ValueError) as exc:
612 gitutil.CountCommitsToBranch(None)
613 self.assertIn(
614 "Failed to determine upstream: fatal: no upstream configured for branch 'base'",
615 str(exc.exception))
616 finally:
617 os.chdir(orig_dir)
Simon Glass3db916d2020-10-29 21:46:35 -0600618
619 @staticmethod
Simon Glassf9b03cf2020-11-03 13:54:14 -0700620 def _fake_patchwork(url, subpath):
Simon Glass3db916d2020-10-29 21:46:35 -0600621 """Fake Patchwork server for the function below
622
623 This handles accessing a series, providing a list consisting of a
624 single patch
Simon Glassf9b03cf2020-11-03 13:54:14 -0700625
626 Args:
627 url (str): URL of patchwork server
628 subpath (str): URL subpath to use
Simon Glass3db916d2020-10-29 21:46:35 -0600629 """
630 re_series = re.match(r'series/(\d*)/$', subpath)
631 if re_series:
632 series_num = re_series.group(1)
633 if series_num == '1234':
634 return {'patches': [
635 {'id': '1', 'name': 'Some patch'}]}
636 raise ValueError('Fake Patchwork does not understand: %s' % subpath)
637
Simon Glass3db916d2020-10-29 21:46:35 -0600638 def testStatusMismatch(self):
639 """Test Patchwork patches not matching the series"""
640 series = Series()
641
642 with capture_sys_output() as (_, err):
Simon Glassf9b03cf2020-11-03 13:54:14 -0700643 status.collect_patches(series, 1234, None, self._fake_patchwork)
Simon Glass3db916d2020-10-29 21:46:35 -0600644 self.assertIn('Warning: Patchwork reports 1 patches, series has 0',
645 err.getvalue())
646
Simon Glass3db916d2020-10-29 21:46:35 -0600647 def testStatusReadPatch(self):
648 """Test handling a single patch in Patchwork"""
649 series = Series()
650 series.commits = [Commit('abcd')]
651
Simon Glassf9b03cf2020-11-03 13:54:14 -0700652 patches = status.collect_patches(series, 1234, None,
653 self._fake_patchwork)
Simon Glass3db916d2020-10-29 21:46:35 -0600654 self.assertEqual(1, len(patches))
655 patch = patches[0]
656 self.assertEqual('1', patch.id)
657 self.assertEqual('Some patch', patch.raw_subject)
658
Simon Glass3db916d2020-10-29 21:46:35 -0600659 def testParseSubject(self):
660 """Test parsing of the patch subject"""
661 patch = status.Patch('1')
662
663 # Simple patch not in a series
664 patch.parse_subject('Testing')
665 self.assertEqual('Testing', patch.raw_subject)
666 self.assertEqual('Testing', patch.subject)
667 self.assertEqual(1, patch.seq)
668 self.assertEqual(1, patch.count)
669 self.assertEqual(None, patch.prefix)
670 self.assertEqual(None, patch.version)
671
672 # First patch in a series
673 patch.parse_subject('[1/2] Testing')
674 self.assertEqual('[1/2] Testing', patch.raw_subject)
675 self.assertEqual('Testing', patch.subject)
676 self.assertEqual(1, patch.seq)
677 self.assertEqual(2, patch.count)
678 self.assertEqual(None, patch.prefix)
679 self.assertEqual(None, patch.version)
680
681 # Second patch in a series
682 patch.parse_subject('[2/2] Testing')
683 self.assertEqual('Testing', patch.subject)
684 self.assertEqual(2, patch.seq)
685 self.assertEqual(2, patch.count)
686 self.assertEqual(None, patch.prefix)
687 self.assertEqual(None, patch.version)
688
689 # RFC patch
690 patch.parse_subject('[RFC,3/7] Testing')
691 self.assertEqual('Testing', patch.subject)
692 self.assertEqual(3, patch.seq)
693 self.assertEqual(7, patch.count)
694 self.assertEqual('RFC', patch.prefix)
695 self.assertEqual(None, patch.version)
696
697 # Version patch
698 patch.parse_subject('[v2,3/7] Testing')
699 self.assertEqual('Testing', patch.subject)
700 self.assertEqual(3, patch.seq)
701 self.assertEqual(7, patch.count)
702 self.assertEqual(None, patch.prefix)
703 self.assertEqual('v2', patch.version)
704
705 # All fields
706 patch.parse_subject('[RESEND,v2,3/7] Testing')
707 self.assertEqual('Testing', patch.subject)
708 self.assertEqual(3, patch.seq)
709 self.assertEqual(7, patch.count)
710 self.assertEqual('RESEND', patch.prefix)
711 self.assertEqual('v2', patch.version)
712
713 # RFC only
714 patch.parse_subject('[RESEND] Testing')
715 self.assertEqual('Testing', patch.subject)
716 self.assertEqual(1, patch.seq)
717 self.assertEqual(1, patch.count)
718 self.assertEqual('RESEND', patch.prefix)
719 self.assertEqual(None, patch.version)
720
Simon Glass3db916d2020-10-29 21:46:35 -0600721 def testCompareSeries(self):
722 """Test operation of compare_with_series()"""
723 commit1 = Commit('abcd')
724 commit1.subject = 'Subject 1'
725 commit2 = Commit('ef12')
726 commit2.subject = 'Subject 2'
727 commit3 = Commit('3456')
728 commit3.subject = 'Subject 2'
729
730 patch1 = status.Patch('1')
731 patch1.subject = 'Subject 1'
732 patch2 = status.Patch('2')
733 patch2.subject = 'Subject 2'
734 patch3 = status.Patch('3')
735 patch3.subject = 'Subject 2'
736
737 series = Series()
738 series.commits = [commit1]
739 patches = [patch1]
740 patch_for_commit, commit_for_patch, warnings = (
741 status.compare_with_series(series, patches))
742 self.assertEqual(1, len(patch_for_commit))
743 self.assertEqual(patch1, patch_for_commit[0])
744 self.assertEqual(1, len(commit_for_patch))
745 self.assertEqual(commit1, commit_for_patch[0])
746
747 series.commits = [commit1]
748 patches = [patch1, patch2]
749 patch_for_commit, commit_for_patch, warnings = (
750 status.compare_with_series(series, patches))
751 self.assertEqual(1, len(patch_for_commit))
752 self.assertEqual(patch1, patch_for_commit[0])
753 self.assertEqual(1, len(commit_for_patch))
754 self.assertEqual(commit1, commit_for_patch[0])
755 self.assertEqual(["Cannot find commit for patch 2 ('Subject 2')"],
756 warnings)
757
758 series.commits = [commit1, commit2]
759 patches = [patch1]
760 patch_for_commit, commit_for_patch, warnings = (
761 status.compare_with_series(series, patches))
762 self.assertEqual(1, len(patch_for_commit))
763 self.assertEqual(patch1, patch_for_commit[0])
764 self.assertEqual(1, len(commit_for_patch))
765 self.assertEqual(commit1, commit_for_patch[0])
766 self.assertEqual(["Cannot find patch for commit 2 ('Subject 2')"],
767 warnings)
768
769 series.commits = [commit1, commit2, commit3]
770 patches = [patch1, patch2]
771 patch_for_commit, commit_for_patch, warnings = (
772 status.compare_with_series(series, patches))
773 self.assertEqual(2, len(patch_for_commit))
774 self.assertEqual(patch1, patch_for_commit[0])
775 self.assertEqual(patch2, patch_for_commit[1])
776 self.assertEqual(1, len(commit_for_patch))
777 self.assertEqual(commit1, commit_for_patch[0])
778 self.assertEqual(["Cannot find patch for commit 3 ('Subject 2')",
779 "Multiple commits match patch 2 ('Subject 2'):\n"
780 ' Subject 2\n Subject 2'],
781 warnings)
782
783 series.commits = [commit1, commit2]
784 patches = [patch1, patch2, patch3]
785 patch_for_commit, commit_for_patch, warnings = (
786 status.compare_with_series(series, patches))
787 self.assertEqual(1, len(patch_for_commit))
788 self.assertEqual(patch1, patch_for_commit[0])
789 self.assertEqual(2, len(commit_for_patch))
790 self.assertEqual(commit1, commit_for_patch[0])
791 self.assertEqual(["Multiple patches match commit 2 ('Subject 2'):\n"
792 ' Subject 2\n Subject 2',
793 "Cannot find commit for patch 3 ('Subject 2')"],
794 warnings)
795
Simon Glassf9b03cf2020-11-03 13:54:14 -0700796 def _fake_patchwork2(self, url, subpath):
Simon Glass3db916d2020-10-29 21:46:35 -0600797 """Fake Patchwork server for the function below
798
799 This handles accessing series, patches and comments, providing the data
800 in self.patches to the caller
Simon Glassf9b03cf2020-11-03 13:54:14 -0700801
802 Args:
803 url (str): URL of patchwork server
804 subpath (str): URL subpath to use
Simon Glass3db916d2020-10-29 21:46:35 -0600805 """
806 re_series = re.match(r'series/(\d*)/$', subpath)
807 re_patch = re.match(r'patches/(\d*)/$', subpath)
808 re_comments = re.match(r'patches/(\d*)/comments/$', subpath)
809 if re_series:
810 series_num = re_series.group(1)
811 if series_num == '1234':
812 return {'patches': self.patches}
813 elif re_patch:
814 patch_num = int(re_patch.group(1))
815 patch = self.patches[patch_num - 1]
816 return patch
817 elif re_comments:
818 patch_num = int(re_comments.group(1))
819 patch = self.patches[patch_num - 1]
820 return patch.comments
821 raise ValueError('Fake Patchwork does not understand: %s' % subpath)
822
Simon Glass3db916d2020-10-29 21:46:35 -0600823 def testFindNewResponses(self):
824 """Test operation of find_new_responses()"""
825 commit1 = Commit('abcd')
826 commit1.subject = 'Subject 1'
827 commit2 = Commit('ef12')
828 commit2.subject = 'Subject 2'
829
830 patch1 = status.Patch('1')
831 patch1.parse_subject('[1/2] Subject 1')
832 patch1.name = patch1.raw_subject
833 patch1.content = 'This is my patch content'
834 comment1a = {'content': 'Reviewed-by: %s\n' % self.joe}
835
836 patch1.comments = [comment1a]
837
838 patch2 = status.Patch('2')
839 patch2.parse_subject('[2/2] Subject 2')
840 patch2.name = patch2.raw_subject
841 patch2.content = 'Some other patch content'
842 comment2a = {
843 'content': 'Reviewed-by: %s\nTested-by: %s\n' %
844 (self.mary, self.leb)}
845 comment2b = {'content': 'Reviewed-by: %s' % self.fred}
846 patch2.comments = [comment2a, comment2b]
847
848 # This test works by setting up commits and patch for use by the fake
849 # Rest API function _fake_patchwork2(). It calls various functions in
850 # the status module after setting up tags in the commits, checking that
851 # things behaves as expected
852 self.commits = [commit1, commit2]
853 self.patches = [patch1, patch2]
854 count = 2
855 new_rtag_list = [None] * count
Simon Glass2112d072020-10-29 21:46:38 -0600856 review_list = [None, None]
Simon Glass3db916d2020-10-29 21:46:35 -0600857
858 # Check that the tags are picked up on the first patch
Simon Glass2112d072020-10-29 21:46:38 -0600859 status.find_new_responses(new_rtag_list, review_list, 0, commit1,
Simon Glassf9b03cf2020-11-03 13:54:14 -0700860 patch1, None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -0600861 self.assertEqual(new_rtag_list[0], {'Reviewed-by': {self.joe}})
862
863 # Now the second patch
Simon Glass2112d072020-10-29 21:46:38 -0600864 status.find_new_responses(new_rtag_list, review_list, 1, commit2,
Simon Glassf9b03cf2020-11-03 13:54:14 -0700865 patch2, None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -0600866 self.assertEqual(new_rtag_list[1], {
867 'Reviewed-by': {self.mary, self.fred},
868 'Tested-by': {self.leb}})
869
870 # Now add some tags to the commit, which means they should not appear as
871 # 'new' tags when scanning comments
872 new_rtag_list = [None] * count
873 commit1.rtags = {'Reviewed-by': {self.joe}}
Simon Glass2112d072020-10-29 21:46:38 -0600874 status.find_new_responses(new_rtag_list, review_list, 0, commit1,
Simon Glassf9b03cf2020-11-03 13:54:14 -0700875 patch1, None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -0600876 self.assertEqual(new_rtag_list[0], {})
877
878 # For the second commit, add Ed and Fred, so only Mary should be left
879 commit2.rtags = {
880 'Tested-by': {self.leb},
881 'Reviewed-by': {self.fred}}
Simon Glass2112d072020-10-29 21:46:38 -0600882 status.find_new_responses(new_rtag_list, review_list, 1, commit2,
Simon Glassf9b03cf2020-11-03 13:54:14 -0700883 patch2, None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -0600884 self.assertEqual(new_rtag_list[1], {'Reviewed-by': {self.mary}})
885
886 # Check that the output patches expectations:
887 # 1 Subject 1
888 # Reviewed-by: Joe Bloggs <joe@napierwallies.co.nz>
889 # 2 Subject 2
890 # Tested-by: Lord Edmund Blackaddër <weasel@blackadder.org>
891 # Reviewed-by: Fred Bloggs <f.bloggs@napier.net>
892 # + Reviewed-by: Mary Bloggs <mary@napierwallies.co.nz>
893 # 1 new response available in patchwork
894
895 series = Series()
896 series.commits = [commit1, commit2]
897 terminal.SetPrintTestMode()
Simon Glass2112d072020-10-29 21:46:38 -0600898 status.check_patchwork_status(series, '1234', None, None, False, False,
Simon Glassf9b03cf2020-11-03 13:54:14 -0700899 None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -0600900 lines = iter(terminal.GetPrintTestLines())
901 col = terminal.Color()
902 self.assertEqual(terminal.PrintLine(' 1 Subject 1', col.BLUE),
903 next(lines))
904 self.assertEqual(
905 terminal.PrintLine(' Reviewed-by: ', col.GREEN, newline=False,
906 bright=False),
907 next(lines))
908 self.assertEqual(terminal.PrintLine(self.joe, col.WHITE, bright=False),
909 next(lines))
910
911 self.assertEqual(terminal.PrintLine(' 2 Subject 2', col.BLUE),
912 next(lines))
913 self.assertEqual(
Simon Glass2112d072020-10-29 21:46:38 -0600914 terminal.PrintLine(' Reviewed-by: ', col.GREEN, newline=False,
Simon Glass3db916d2020-10-29 21:46:35 -0600915 bright=False),
916 next(lines))
Simon Glass2112d072020-10-29 21:46:38 -0600917 self.assertEqual(terminal.PrintLine(self.fred, col.WHITE, bright=False),
Simon Glass3db916d2020-10-29 21:46:35 -0600918 next(lines))
919 self.assertEqual(
Simon Glass2112d072020-10-29 21:46:38 -0600920 terminal.PrintLine(' Tested-by: ', col.GREEN, newline=False,
Simon Glass3db916d2020-10-29 21:46:35 -0600921 bright=False),
922 next(lines))
Simon Glass2112d072020-10-29 21:46:38 -0600923 self.assertEqual(terminal.PrintLine(self.leb, col.WHITE, bright=False),
Simon Glass3db916d2020-10-29 21:46:35 -0600924 next(lines))
925 self.assertEqual(
926 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
927 next(lines))
928 self.assertEqual(terminal.PrintLine(self.mary, col.WHITE),
929 next(lines))
930 self.assertEqual(terminal.PrintLine(
Simon Glassd0a0a582020-10-29 21:46:36 -0600931 '1 new response available in patchwork (use -d to write them to a new branch)',
932 None), next(lines))
933
Simon Glassf9b03cf2020-11-03 13:54:14 -0700934 def _fake_patchwork3(self, url, subpath):
Simon Glassd0a0a582020-10-29 21:46:36 -0600935 """Fake Patchwork server for the function below
936
937 This handles accessing series, patches and comments, providing the data
938 in self.patches to the caller
Simon Glassf9b03cf2020-11-03 13:54:14 -0700939
940 Args:
941 url (str): URL of patchwork server
942 subpath (str): URL subpath to use
Simon Glassd0a0a582020-10-29 21:46:36 -0600943 """
944 re_series = re.match(r'series/(\d*)/$', subpath)
945 re_patch = re.match(r'patches/(\d*)/$', subpath)
946 re_comments = re.match(r'patches/(\d*)/comments/$', subpath)
947 if re_series:
948 series_num = re_series.group(1)
949 if series_num == '1234':
950 return {'patches': self.patches}
951 elif re_patch:
952 patch_num = int(re_patch.group(1))
953 patch = self.patches[patch_num - 1]
954 return patch
955 elif re_comments:
956 patch_num = int(re_comments.group(1))
957 patch = self.patches[patch_num - 1]
958 return patch.comments
959 raise ValueError('Fake Patchwork does not understand: %s' % subpath)
960
Simon Glassd0a0a582020-10-29 21:46:36 -0600961 def testCreateBranch(self):
962 """Test operation of create_branch()"""
963 repo = self.make_git_tree()
964 branch = 'first'
965 dest_branch = 'first2'
966 count = 2
967 gitdir = os.path.join(self.gitdir, '.git')
968
969 # Set up the test git tree. We use branch 'first' which has two commits
970 # in it
971 series = patchstream.get_metadata_for_list(branch, gitdir, count)
972 self.assertEqual(2, len(series.commits))
973
974 patch1 = status.Patch('1')
975 patch1.parse_subject('[1/2] %s' % series.commits[0].subject)
976 patch1.name = patch1.raw_subject
977 patch1.content = 'This is my patch content'
978 comment1a = {'content': 'Reviewed-by: %s\n' % self.joe}
979
980 patch1.comments = [comment1a]
981
982 patch2 = status.Patch('2')
983 patch2.parse_subject('[2/2] %s' % series.commits[1].subject)
984 patch2.name = patch2.raw_subject
985 patch2.content = 'Some other patch content'
986 comment2a = {
987 'content': 'Reviewed-by: %s\nTested-by: %s\n' %
988 (self.mary, self.leb)}
989 comment2b = {
990 'content': 'Reviewed-by: %s' % self.fred}
991 patch2.comments = [comment2a, comment2b]
992
993 # This test works by setting up patches for use by the fake Rest API
994 # function _fake_patchwork3(). The fake patch comments above should
995 # result in new review tags that are collected and added to the commits
996 # created in the destination branch.
997 self.patches = [patch1, patch2]
998 count = 2
999
1000 # Expected output:
1001 # 1 i2c: I2C things
1002 # + Reviewed-by: Joe Bloggs <joe@napierwallies.co.nz>
1003 # 2 spi: SPI fixes
1004 # + Reviewed-by: Fred Bloggs <f.bloggs@napier.net>
1005 # + Reviewed-by: Mary Bloggs <mary@napierwallies.co.nz>
1006 # + Tested-by: Lord Edmund Blackaddër <weasel@blackadder.org>
1007 # 4 new responses available in patchwork
1008 # 4 responses added from patchwork into new branch 'first2'
1009 # <unittest.result.TestResult run=8 errors=0 failures=0>
1010
1011 terminal.SetPrintTestMode()
1012 status.check_patchwork_status(series, '1234', branch, dest_branch,
Simon Glassf9b03cf2020-11-03 13:54:14 -07001013 False, False, None, self._fake_patchwork3,
1014 repo)
Simon Glassd0a0a582020-10-29 21:46:36 -06001015 lines = terminal.GetPrintTestLines()
1016 self.assertEqual(12, len(lines))
1017 self.assertEqual(
1018 "4 responses added from patchwork into new branch 'first2'",
1019 lines[11].text)
1020
1021 # Check that the destination branch has the new tags
1022 new_series = patchstream.get_metadata_for_list(dest_branch, gitdir,
1023 count)
1024 self.assertEqual(
1025 {'Reviewed-by': {self.joe}},
1026 new_series.commits[0].rtags)
1027 self.assertEqual(
1028 {'Tested-by': {self.leb},
1029 'Reviewed-by': {self.fred, self.mary}},
1030 new_series.commits[1].rtags)
1031
1032 # Now check the actual test of the first commit message. We expect to
1033 # see the new tags immediately below the old ones.
1034 stdout = patchstream.get_list(dest_branch, count=count, git_dir=gitdir)
1035 lines = iter([line.strip() for line in stdout.splitlines()
1036 if '-by:' in line])
1037
1038 # First patch should have the review tag
1039 self.assertEqual('Reviewed-by: %s' % self.joe, next(lines))
1040
1041 # Second patch should have the sign-off then the tested-by and two
1042 # reviewed-by tags
1043 self.assertEqual('Signed-off-by: %s' % self.leb, next(lines))
1044 self.assertEqual('Reviewed-by: %s' % self.fred, next(lines))
1045 self.assertEqual('Reviewed-by: %s' % self.mary, next(lines))
1046 self.assertEqual('Tested-by: %s' % self.leb, next(lines))
Simon Glassda8a2922020-10-29 21:46:37 -06001047
1048 def testParseSnippets(self):
1049 """Test parsing of review snippets"""
1050 text = '''Hi Fred,
1051
1052This is a comment from someone.
1053
1054Something else
1055
1056On some recent date, Fred wrote:
1057> This is why I wrote the patch
1058> so here it is
1059
1060Now a comment about the commit message
1061A little more to say
1062
1063Even more
1064
1065> diff --git a/file.c b/file.c
1066> Some more code
1067> Code line 2
1068> Code line 3
1069> Code line 4
1070> Code line 5
1071> Code line 6
1072> Code line 7
1073> Code line 8
1074> Code line 9
1075
1076And another comment
1077
1078> @@ -153,8 +143,13 @@ def CheckPatch(fname, show_types=False):
1079> further down on the file
1080> and more code
1081> +Addition here
1082> +Another addition here
1083> codey
1084> more codey
1085
1086and another thing in same file
1087
1088> @@ -253,8 +243,13 @@
1089> with no function context
1090
1091one more thing
1092
1093> diff --git a/tools/patman/main.py b/tools/patman/main.py
1094> +line of code
1095now a very long comment in a different file
1096line2
1097line3
1098line4
1099line5
1100line6
1101line7
1102line8
1103'''
1104 pstrm = PatchStream.process_text(text, True)
1105 self.assertEqual([], pstrm.commit.warn)
1106
1107 # We expect to the filename and up to 5 lines of code context before
1108 # each comment. The 'On xxx wrote:' bit should be removed.
1109 self.assertEqual(
1110 [['Hi Fred,',
1111 'This is a comment from someone.',
1112 'Something else'],
1113 ['> This is why I wrote the patch',
1114 '> so here it is',
1115 'Now a comment about the commit message',
1116 'A little more to say', 'Even more'],
1117 ['> File: file.c', '> Code line 5', '> Code line 6',
1118 '> Code line 7', '> Code line 8', '> Code line 9',
1119 'And another comment'],
1120 ['> File: file.c',
1121 '> Line: 153 / 143: def CheckPatch(fname, show_types=False):',
1122 '> and more code', '> +Addition here', '> +Another addition here',
1123 '> codey', '> more codey', 'and another thing in same file'],
1124 ['> File: file.c', '> Line: 253 / 243',
1125 '> with no function context', 'one more thing'],
1126 ['> File: tools/patman/main.py', '> +line of code',
1127 'now a very long comment in a different file',
1128 'line2', 'line3', 'line4', 'line5', 'line6', 'line7', 'line8']],
1129 pstrm.snippets)
Simon Glass2112d072020-10-29 21:46:38 -06001130
Simon Glass2112d072020-10-29 21:46:38 -06001131 def testReviewSnippets(self):
1132 """Test showing of review snippets"""
1133 def _to_submitter(who):
1134 m_who = re.match('(.*) <(.*)>', who)
1135 return {
1136 'name': m_who.group(1),
1137 'email': m_who.group(2)
1138 }
1139
1140 commit1 = Commit('abcd')
1141 commit1.subject = 'Subject 1'
1142 commit2 = Commit('ef12')
1143 commit2.subject = 'Subject 2'
1144
1145 patch1 = status.Patch('1')
1146 patch1.parse_subject('[1/2] Subject 1')
1147 patch1.name = patch1.raw_subject
1148 patch1.content = 'This is my patch content'
1149 comment1a = {'submitter': _to_submitter(self.joe),
1150 'content': '''Hi Fred,
1151
1152On some date Fred wrote:
1153
1154> diff --git a/file.c b/file.c
1155> Some code
1156> and more code
1157
1158Here is my comment above the above...
1159
1160
1161Reviewed-by: %s
1162''' % self.joe}
1163
1164 patch1.comments = [comment1a]
1165
1166 patch2 = status.Patch('2')
1167 patch2.parse_subject('[2/2] Subject 2')
1168 patch2.name = patch2.raw_subject
1169 patch2.content = 'Some other patch content'
1170 comment2a = {
1171 'content': 'Reviewed-by: %s\nTested-by: %s\n' %
1172 (self.mary, self.leb)}
1173 comment2b = {'submitter': _to_submitter(self.fred),
1174 'content': '''Hi Fred,
1175
1176On some date Fred wrote:
1177
1178> diff --git a/tools/patman/commit.py b/tools/patman/commit.py
1179> @@ -41,6 +41,9 @@ class Commit:
1180> self.rtags = collections.defaultdict(set)
1181> self.warn = []
1182>
1183> + def __str__(self):
1184> + return self.subject
1185> +
1186> def AddChange(self, version, info):
1187> """Add a new change line to the change list for a version.
1188>
1189A comment
1190
1191Reviewed-by: %s
1192''' % self.fred}
1193 patch2.comments = [comment2a, comment2b]
1194
1195 # This test works by setting up commits and patch for use by the fake
1196 # Rest API function _fake_patchwork2(). It calls various functions in
1197 # the status module after setting up tags in the commits, checking that
1198 # things behaves as expected
1199 self.commits = [commit1, commit2]
1200 self.patches = [patch1, patch2]
1201
1202 # Check that the output patches expectations:
1203 # 1 Subject 1
1204 # Reviewed-by: Joe Bloggs <joe@napierwallies.co.nz>
1205 # 2 Subject 2
1206 # Tested-by: Lord Edmund Blackaddër <weasel@blackadder.org>
1207 # Reviewed-by: Fred Bloggs <f.bloggs@napier.net>
1208 # + Reviewed-by: Mary Bloggs <mary@napierwallies.co.nz>
1209 # 1 new response available in patchwork
1210
1211 series = Series()
1212 series.commits = [commit1, commit2]
1213 terminal.SetPrintTestMode()
1214 status.check_patchwork_status(series, '1234', None, None, False, True,
Simon Glassf9b03cf2020-11-03 13:54:14 -07001215 None, self._fake_patchwork2)
Simon Glass2112d072020-10-29 21:46:38 -06001216 lines = iter(terminal.GetPrintTestLines())
1217 col = terminal.Color()
1218 self.assertEqual(terminal.PrintLine(' 1 Subject 1', col.BLUE),
1219 next(lines))
1220 self.assertEqual(
1221 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
1222 next(lines))
1223 self.assertEqual(terminal.PrintLine(self.joe, col.WHITE), next(lines))
1224
1225 self.assertEqual(terminal.PrintLine('Review: %s' % self.joe, col.RED),
1226 next(lines))
1227 self.assertEqual(terminal.PrintLine(' Hi Fred,', None), next(lines))
1228 self.assertEqual(terminal.PrintLine('', None), next(lines))
1229 self.assertEqual(terminal.PrintLine(' > File: file.c', col.MAGENTA),
1230 next(lines))
1231 self.assertEqual(terminal.PrintLine(' > Some code', col.MAGENTA),
1232 next(lines))
1233 self.assertEqual(terminal.PrintLine(' > and more code', col.MAGENTA),
1234 next(lines))
1235 self.assertEqual(terminal.PrintLine(
1236 ' Here is my comment above the above...', None), next(lines))
1237 self.assertEqual(terminal.PrintLine('', None), next(lines))
1238
1239 self.assertEqual(terminal.PrintLine(' 2 Subject 2', col.BLUE),
1240 next(lines))
1241 self.assertEqual(
1242 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
1243 next(lines))
1244 self.assertEqual(terminal.PrintLine(self.fred, col.WHITE),
1245 next(lines))
1246 self.assertEqual(
1247 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
1248 next(lines))
1249 self.assertEqual(terminal.PrintLine(self.mary, col.WHITE),
1250 next(lines))
1251 self.assertEqual(
1252 terminal.PrintLine(' + Tested-by: ', col.GREEN, newline=False),
1253 next(lines))
1254 self.assertEqual(terminal.PrintLine(self.leb, col.WHITE),
1255 next(lines))
1256
1257 self.assertEqual(terminal.PrintLine('Review: %s' % self.fred, col.RED),
1258 next(lines))
1259 self.assertEqual(terminal.PrintLine(' Hi Fred,', None), next(lines))
1260 self.assertEqual(terminal.PrintLine('', None), next(lines))
1261 self.assertEqual(terminal.PrintLine(
1262 ' > File: tools/patman/commit.py', col.MAGENTA), next(lines))
1263 self.assertEqual(terminal.PrintLine(
1264 ' > Line: 41 / 41: class Commit:', col.MAGENTA), next(lines))
1265 self.assertEqual(terminal.PrintLine(
1266 ' > + return self.subject', col.MAGENTA), next(lines))
1267 self.assertEqual(terminal.PrintLine(
1268 ' > +', col.MAGENTA), next(lines))
1269 self.assertEqual(
1270 terminal.PrintLine(' > def AddChange(self, version, info):',
1271 col.MAGENTA),
1272 next(lines))
1273 self.assertEqual(terminal.PrintLine(
1274 ' > """Add a new change line to the change list for a version.',
1275 col.MAGENTA), next(lines))
1276 self.assertEqual(terminal.PrintLine(
1277 ' >', col.MAGENTA), next(lines))
1278 self.assertEqual(terminal.PrintLine(
1279 ' A comment', None), next(lines))
1280 self.assertEqual(terminal.PrintLine('', None), next(lines))
1281
1282 self.assertEqual(terminal.PrintLine(
1283 '4 new responses available in patchwork (use -d to write them to a new branch)',
1284 None), next(lines))