blob: 2493e527f525cabd118b0696692698035ddb6c28 [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
Simon Glass6a222e62021-08-01 16:02:39 -0600139' Cover-changes: 4
Sean Andersoncf13b862020-05-04 16:28:36 -0400140 - 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
Patrick Delaunay6bbdd0c2021-07-22 16:51:42 +0200509 def testInvalidTag(self):
510 """Test invalid tag in a patchstream"""
511 text = '''This is a patch
512
513Serie-version: 2
514'''
515 with self.assertRaises(ValueError) as exc:
516 pstrm = PatchStream.process_text(text)
517 self.assertEqual("Line 3: Invalid tag = 'Serie-version: 2'",
518 str(exc.exception))
519
Simon Glass3b762cc2020-10-29 21:46:28 -0600520 def testMissingEnd(self):
521 """Test a missing END tag"""
522 text = '''This is a patch
523
524Cover-letter:
525This is the title
526missing END after this line
527Signed-off-by: Fred
528'''
529 pstrm = PatchStream.process_text(text)
530 self.assertEqual(["Missing 'END' in section 'cover'"],
531 pstrm.commit.warn)
532
533 def testMissingBlankLine(self):
534 """Test a missing blank line after a tag"""
535 text = '''This is a patch
536
537Series-changes: 2
538- First line of changes
539- Missing blank line after this line
540Signed-off-by: Fred
541'''
542 pstrm = PatchStream.process_text(text)
543 self.assertEqual(["Missing 'blank line' in section 'Series-changes'"],
544 pstrm.commit.warn)
545
546 def testInvalidCommitTag(self):
547 """Test an invalid Commit-xxx tag"""
548 text = '''This is a patch
549
550Commit-fred: testing
551'''
552 pstrm = PatchStream.process_text(text)
553 self.assertEqual(["Line 3: Ignoring Commit-fred"], pstrm.commit.warn)
554
555 def testSelfTest(self):
556 """Test a tested by tag by this user"""
557 test_line = 'Tested-by: %s@napier.com' % os.getenv('USER')
558 text = '''This is a patch
559
560%s
561''' % test_line
562 pstrm = PatchStream.process_text(text)
563 self.assertEqual(["Ignoring '%s'" % test_line], pstrm.commit.warn)
564
565 def testSpaceBeforeTab(self):
566 """Test a space before a tab"""
567 text = '''This is a patch
568
569+ \tSomething
570'''
571 pstrm = PatchStream.process_text(text)
572 self.assertEqual(["Line 3/0 has space before tab"], pstrm.commit.warn)
573
574 def testLinesAfterTest(self):
575 """Test detecting lines after TEST= line"""
576 text = '''This is a patch
577
578TEST=sometest
579more lines
580here
581'''
582 pstrm = PatchStream.process_text(text)
583 self.assertEqual(["Found 2 lines after TEST="], pstrm.commit.warn)
584
585 def testBlankLineAtEnd(self):
586 """Test detecting a blank line at the end of a file"""
587 text = '''This is a patch
588
589diff --git a/lib/fdtdec.c b/lib/fdtdec.c
590index c072e54..942244f 100644
591--- a/lib/fdtdec.c
592+++ b/lib/fdtdec.c
593@@ -1200,7 +1200,8 @@ int fdtdec_setup_mem_size_base(void)
594 }
595
596 gd->ram_size = (phys_size_t)(res.end - res.start + 1);
597- debug("%s: Initial DRAM size %llx\n", __func__, (u64)gd->ram_size);
598+ debug("%s: Initial DRAM size %llx\n", __func__,
599+ (unsigned long long)gd->ram_size);
600+
601diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
602
603--
6042.7.4
605
606 '''
607 pstrm = PatchStream.process_text(text)
608 self.assertEqual(
609 ["Found possible blank line(s) at end of file 'lib/fdtdec.c'"],
610 pstrm.commit.warn)
Simon Glass1c1f2072020-10-29 21:46:34 -0600611
Simon Glass1c1f2072020-10-29 21:46:34 -0600612 def testNoUpstream(self):
613 """Test CountCommitsToBranch when there is no upstream"""
614 repo = self.make_git_tree()
615 target = repo.lookup_reference('refs/heads/base')
616 self.repo.checkout(target, strategy=pygit2.GIT_CHECKOUT_FORCE)
617
618 # Check that it can detect the current branch
619 try:
620 orig_dir = os.getcwd()
621 os.chdir(self.gitdir)
622 with self.assertRaises(ValueError) as exc:
623 gitutil.CountCommitsToBranch(None)
624 self.assertIn(
625 "Failed to determine upstream: fatal: no upstream configured for branch 'base'",
626 str(exc.exception))
627 finally:
628 os.chdir(orig_dir)
Simon Glass3db916d2020-10-29 21:46:35 -0600629
630 @staticmethod
Simon Glassf9b03cf2020-11-03 13:54:14 -0700631 def _fake_patchwork(url, subpath):
Simon Glass3db916d2020-10-29 21:46:35 -0600632 """Fake Patchwork server for the function below
633
634 This handles accessing a series, providing a list consisting of a
635 single patch
Simon Glassf9b03cf2020-11-03 13:54:14 -0700636
637 Args:
638 url (str): URL of patchwork server
639 subpath (str): URL subpath to use
Simon Glass3db916d2020-10-29 21:46:35 -0600640 """
641 re_series = re.match(r'series/(\d*)/$', subpath)
642 if re_series:
643 series_num = re_series.group(1)
644 if series_num == '1234':
645 return {'patches': [
646 {'id': '1', 'name': 'Some patch'}]}
647 raise ValueError('Fake Patchwork does not understand: %s' % subpath)
648
Simon Glass3db916d2020-10-29 21:46:35 -0600649 def testStatusMismatch(self):
650 """Test Patchwork patches not matching the series"""
651 series = Series()
652
653 with capture_sys_output() as (_, err):
Simon Glassf9b03cf2020-11-03 13:54:14 -0700654 status.collect_patches(series, 1234, None, self._fake_patchwork)
Simon Glass3db916d2020-10-29 21:46:35 -0600655 self.assertIn('Warning: Patchwork reports 1 patches, series has 0',
656 err.getvalue())
657
Simon Glass3db916d2020-10-29 21:46:35 -0600658 def testStatusReadPatch(self):
659 """Test handling a single patch in Patchwork"""
660 series = Series()
661 series.commits = [Commit('abcd')]
662
Simon Glassf9b03cf2020-11-03 13:54:14 -0700663 patches = status.collect_patches(series, 1234, None,
664 self._fake_patchwork)
Simon Glass3db916d2020-10-29 21:46:35 -0600665 self.assertEqual(1, len(patches))
666 patch = patches[0]
667 self.assertEqual('1', patch.id)
668 self.assertEqual('Some patch', patch.raw_subject)
669
Simon Glass3db916d2020-10-29 21:46:35 -0600670 def testParseSubject(self):
671 """Test parsing of the patch subject"""
672 patch = status.Patch('1')
673
674 # Simple patch not in a series
675 patch.parse_subject('Testing')
676 self.assertEqual('Testing', patch.raw_subject)
677 self.assertEqual('Testing', patch.subject)
678 self.assertEqual(1, patch.seq)
679 self.assertEqual(1, patch.count)
680 self.assertEqual(None, patch.prefix)
681 self.assertEqual(None, patch.version)
682
683 # First patch in a series
684 patch.parse_subject('[1/2] Testing')
685 self.assertEqual('[1/2] Testing', patch.raw_subject)
686 self.assertEqual('Testing', patch.subject)
687 self.assertEqual(1, patch.seq)
688 self.assertEqual(2, patch.count)
689 self.assertEqual(None, patch.prefix)
690 self.assertEqual(None, patch.version)
691
692 # Second patch in a series
693 patch.parse_subject('[2/2] Testing')
694 self.assertEqual('Testing', patch.subject)
695 self.assertEqual(2, patch.seq)
696 self.assertEqual(2, patch.count)
697 self.assertEqual(None, patch.prefix)
698 self.assertEqual(None, patch.version)
699
700 # RFC patch
701 patch.parse_subject('[RFC,3/7] Testing')
702 self.assertEqual('Testing', patch.subject)
703 self.assertEqual(3, patch.seq)
704 self.assertEqual(7, patch.count)
705 self.assertEqual('RFC', patch.prefix)
706 self.assertEqual(None, patch.version)
707
708 # Version patch
709 patch.parse_subject('[v2,3/7] Testing')
710 self.assertEqual('Testing', patch.subject)
711 self.assertEqual(3, patch.seq)
712 self.assertEqual(7, patch.count)
713 self.assertEqual(None, patch.prefix)
714 self.assertEqual('v2', patch.version)
715
716 # All fields
717 patch.parse_subject('[RESEND,v2,3/7] Testing')
718 self.assertEqual('Testing', patch.subject)
719 self.assertEqual(3, patch.seq)
720 self.assertEqual(7, patch.count)
721 self.assertEqual('RESEND', patch.prefix)
722 self.assertEqual('v2', patch.version)
723
724 # RFC only
725 patch.parse_subject('[RESEND] Testing')
726 self.assertEqual('Testing', patch.subject)
727 self.assertEqual(1, patch.seq)
728 self.assertEqual(1, patch.count)
729 self.assertEqual('RESEND', patch.prefix)
730 self.assertEqual(None, patch.version)
731
Simon Glass3db916d2020-10-29 21:46:35 -0600732 def testCompareSeries(self):
733 """Test operation of compare_with_series()"""
734 commit1 = Commit('abcd')
735 commit1.subject = 'Subject 1'
736 commit2 = Commit('ef12')
737 commit2.subject = 'Subject 2'
738 commit3 = Commit('3456')
739 commit3.subject = 'Subject 2'
740
741 patch1 = status.Patch('1')
742 patch1.subject = 'Subject 1'
743 patch2 = status.Patch('2')
744 patch2.subject = 'Subject 2'
745 patch3 = status.Patch('3')
746 patch3.subject = 'Subject 2'
747
748 series = Series()
749 series.commits = [commit1]
750 patches = [patch1]
751 patch_for_commit, commit_for_patch, warnings = (
752 status.compare_with_series(series, patches))
753 self.assertEqual(1, len(patch_for_commit))
754 self.assertEqual(patch1, patch_for_commit[0])
755 self.assertEqual(1, len(commit_for_patch))
756 self.assertEqual(commit1, commit_for_patch[0])
757
758 series.commits = [commit1]
759 patches = [patch1, patch2]
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 commit for patch 2 ('Subject 2')"],
767 warnings)
768
769 series.commits = [commit1, commit2]
770 patches = [patch1]
771 patch_for_commit, commit_for_patch, warnings = (
772 status.compare_with_series(series, patches))
773 self.assertEqual(1, len(patch_for_commit))
774 self.assertEqual(patch1, patch_for_commit[0])
775 self.assertEqual(1, len(commit_for_patch))
776 self.assertEqual(commit1, commit_for_patch[0])
777 self.assertEqual(["Cannot find patch for commit 2 ('Subject 2')"],
778 warnings)
779
780 series.commits = [commit1, commit2, commit3]
781 patches = [patch1, patch2]
782 patch_for_commit, commit_for_patch, warnings = (
783 status.compare_with_series(series, patches))
784 self.assertEqual(2, len(patch_for_commit))
785 self.assertEqual(patch1, patch_for_commit[0])
786 self.assertEqual(patch2, patch_for_commit[1])
787 self.assertEqual(1, len(commit_for_patch))
788 self.assertEqual(commit1, commit_for_patch[0])
789 self.assertEqual(["Cannot find patch for commit 3 ('Subject 2')",
790 "Multiple commits match patch 2 ('Subject 2'):\n"
791 ' Subject 2\n Subject 2'],
792 warnings)
793
794 series.commits = [commit1, commit2]
795 patches = [patch1, patch2, patch3]
796 patch_for_commit, commit_for_patch, warnings = (
797 status.compare_with_series(series, patches))
798 self.assertEqual(1, len(patch_for_commit))
799 self.assertEqual(patch1, patch_for_commit[0])
800 self.assertEqual(2, len(commit_for_patch))
801 self.assertEqual(commit1, commit_for_patch[0])
802 self.assertEqual(["Multiple patches match commit 2 ('Subject 2'):\n"
803 ' Subject 2\n Subject 2',
804 "Cannot find commit for patch 3 ('Subject 2')"],
805 warnings)
806
Simon Glassf9b03cf2020-11-03 13:54:14 -0700807 def _fake_patchwork2(self, url, subpath):
Simon Glass3db916d2020-10-29 21:46:35 -0600808 """Fake Patchwork server for the function below
809
810 This handles accessing series, patches and comments, providing the data
811 in self.patches to the caller
Simon Glassf9b03cf2020-11-03 13:54:14 -0700812
813 Args:
814 url (str): URL of patchwork server
815 subpath (str): URL subpath to use
Simon Glass3db916d2020-10-29 21:46:35 -0600816 """
817 re_series = re.match(r'series/(\d*)/$', subpath)
818 re_patch = re.match(r'patches/(\d*)/$', subpath)
819 re_comments = re.match(r'patches/(\d*)/comments/$', subpath)
820 if re_series:
821 series_num = re_series.group(1)
822 if series_num == '1234':
823 return {'patches': self.patches}
824 elif re_patch:
825 patch_num = int(re_patch.group(1))
826 patch = self.patches[patch_num - 1]
827 return patch
828 elif re_comments:
829 patch_num = int(re_comments.group(1))
830 patch = self.patches[patch_num - 1]
831 return patch.comments
832 raise ValueError('Fake Patchwork does not understand: %s' % subpath)
833
Simon Glass3db916d2020-10-29 21:46:35 -0600834 def testFindNewResponses(self):
835 """Test operation of find_new_responses()"""
836 commit1 = Commit('abcd')
837 commit1.subject = 'Subject 1'
838 commit2 = Commit('ef12')
839 commit2.subject = 'Subject 2'
840
841 patch1 = status.Patch('1')
842 patch1.parse_subject('[1/2] Subject 1')
843 patch1.name = patch1.raw_subject
844 patch1.content = 'This is my patch content'
845 comment1a = {'content': 'Reviewed-by: %s\n' % self.joe}
846
847 patch1.comments = [comment1a]
848
849 patch2 = status.Patch('2')
850 patch2.parse_subject('[2/2] Subject 2')
851 patch2.name = patch2.raw_subject
852 patch2.content = 'Some other patch content'
853 comment2a = {
854 'content': 'Reviewed-by: %s\nTested-by: %s\n' %
855 (self.mary, self.leb)}
856 comment2b = {'content': 'Reviewed-by: %s' % self.fred}
857 patch2.comments = [comment2a, comment2b]
858
859 # This test works by setting up commits and patch for use by the fake
860 # Rest API function _fake_patchwork2(). It calls various functions in
861 # the status module after setting up tags in the commits, checking that
862 # things behaves as expected
863 self.commits = [commit1, commit2]
864 self.patches = [patch1, patch2]
865 count = 2
866 new_rtag_list = [None] * count
Simon Glass2112d072020-10-29 21:46:38 -0600867 review_list = [None, None]
Simon Glass3db916d2020-10-29 21:46:35 -0600868
869 # Check that the tags are picked up on the first patch
Simon Glass2112d072020-10-29 21:46:38 -0600870 status.find_new_responses(new_rtag_list, review_list, 0, commit1,
Simon Glassf9b03cf2020-11-03 13:54:14 -0700871 patch1, None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -0600872 self.assertEqual(new_rtag_list[0], {'Reviewed-by': {self.joe}})
873
874 # Now the second patch
Simon Glass2112d072020-10-29 21:46:38 -0600875 status.find_new_responses(new_rtag_list, review_list, 1, commit2,
Simon Glassf9b03cf2020-11-03 13:54:14 -0700876 patch2, None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -0600877 self.assertEqual(new_rtag_list[1], {
878 'Reviewed-by': {self.mary, self.fred},
879 'Tested-by': {self.leb}})
880
881 # Now add some tags to the commit, which means they should not appear as
882 # 'new' tags when scanning comments
883 new_rtag_list = [None] * count
884 commit1.rtags = {'Reviewed-by': {self.joe}}
Simon Glass2112d072020-10-29 21:46:38 -0600885 status.find_new_responses(new_rtag_list, review_list, 0, commit1,
Simon Glassf9b03cf2020-11-03 13:54:14 -0700886 patch1, None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -0600887 self.assertEqual(new_rtag_list[0], {})
888
889 # For the second commit, add Ed and Fred, so only Mary should be left
890 commit2.rtags = {
891 'Tested-by': {self.leb},
892 'Reviewed-by': {self.fred}}
Simon Glass2112d072020-10-29 21:46:38 -0600893 status.find_new_responses(new_rtag_list, review_list, 1, commit2,
Simon Glassf9b03cf2020-11-03 13:54:14 -0700894 patch2, None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -0600895 self.assertEqual(new_rtag_list[1], {'Reviewed-by': {self.mary}})
896
897 # Check that the output patches expectations:
898 # 1 Subject 1
899 # Reviewed-by: Joe Bloggs <joe@napierwallies.co.nz>
900 # 2 Subject 2
901 # Tested-by: Lord Edmund Blackaddër <weasel@blackadder.org>
902 # Reviewed-by: Fred Bloggs <f.bloggs@napier.net>
903 # + Reviewed-by: Mary Bloggs <mary@napierwallies.co.nz>
904 # 1 new response available in patchwork
905
906 series = Series()
907 series.commits = [commit1, commit2]
908 terminal.SetPrintTestMode()
Simon Glass2112d072020-10-29 21:46:38 -0600909 status.check_patchwork_status(series, '1234', None, None, False, False,
Simon Glassf9b03cf2020-11-03 13:54:14 -0700910 None, self._fake_patchwork2)
Simon Glass3db916d2020-10-29 21:46:35 -0600911 lines = iter(terminal.GetPrintTestLines())
912 col = terminal.Color()
913 self.assertEqual(terminal.PrintLine(' 1 Subject 1', col.BLUE),
914 next(lines))
915 self.assertEqual(
916 terminal.PrintLine(' Reviewed-by: ', col.GREEN, newline=False,
917 bright=False),
918 next(lines))
919 self.assertEqual(terminal.PrintLine(self.joe, col.WHITE, bright=False),
920 next(lines))
921
922 self.assertEqual(terminal.PrintLine(' 2 Subject 2', col.BLUE),
923 next(lines))
924 self.assertEqual(
Simon Glass2112d072020-10-29 21:46:38 -0600925 terminal.PrintLine(' Reviewed-by: ', col.GREEN, newline=False,
Simon Glass3db916d2020-10-29 21:46:35 -0600926 bright=False),
927 next(lines))
Simon Glass2112d072020-10-29 21:46:38 -0600928 self.assertEqual(terminal.PrintLine(self.fred, col.WHITE, bright=False),
Simon Glass3db916d2020-10-29 21:46:35 -0600929 next(lines))
930 self.assertEqual(
Simon Glass2112d072020-10-29 21:46:38 -0600931 terminal.PrintLine(' Tested-by: ', col.GREEN, newline=False,
Simon Glass3db916d2020-10-29 21:46:35 -0600932 bright=False),
933 next(lines))
Simon Glass2112d072020-10-29 21:46:38 -0600934 self.assertEqual(terminal.PrintLine(self.leb, col.WHITE, bright=False),
Simon Glass3db916d2020-10-29 21:46:35 -0600935 next(lines))
936 self.assertEqual(
937 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
938 next(lines))
939 self.assertEqual(terminal.PrintLine(self.mary, col.WHITE),
940 next(lines))
941 self.assertEqual(terminal.PrintLine(
Simon Glassd0a0a582020-10-29 21:46:36 -0600942 '1 new response available in patchwork (use -d to write them to a new branch)',
943 None), next(lines))
944
Simon Glassf9b03cf2020-11-03 13:54:14 -0700945 def _fake_patchwork3(self, url, subpath):
Simon Glassd0a0a582020-10-29 21:46:36 -0600946 """Fake Patchwork server for the function below
947
948 This handles accessing series, patches and comments, providing the data
949 in self.patches to the caller
Simon Glassf9b03cf2020-11-03 13:54:14 -0700950
951 Args:
952 url (str): URL of patchwork server
953 subpath (str): URL subpath to use
Simon Glassd0a0a582020-10-29 21:46:36 -0600954 """
955 re_series = re.match(r'series/(\d*)/$', subpath)
956 re_patch = re.match(r'patches/(\d*)/$', subpath)
957 re_comments = re.match(r'patches/(\d*)/comments/$', subpath)
958 if re_series:
959 series_num = re_series.group(1)
960 if series_num == '1234':
961 return {'patches': self.patches}
962 elif re_patch:
963 patch_num = int(re_patch.group(1))
964 patch = self.patches[patch_num - 1]
965 return patch
966 elif re_comments:
967 patch_num = int(re_comments.group(1))
968 patch = self.patches[patch_num - 1]
969 return patch.comments
970 raise ValueError('Fake Patchwork does not understand: %s' % subpath)
971
Simon Glassd0a0a582020-10-29 21:46:36 -0600972 def testCreateBranch(self):
973 """Test operation of create_branch()"""
974 repo = self.make_git_tree()
975 branch = 'first'
976 dest_branch = 'first2'
977 count = 2
978 gitdir = os.path.join(self.gitdir, '.git')
979
980 # Set up the test git tree. We use branch 'first' which has two commits
981 # in it
982 series = patchstream.get_metadata_for_list(branch, gitdir, count)
983 self.assertEqual(2, len(series.commits))
984
985 patch1 = status.Patch('1')
986 patch1.parse_subject('[1/2] %s' % series.commits[0].subject)
987 patch1.name = patch1.raw_subject
988 patch1.content = 'This is my patch content'
989 comment1a = {'content': 'Reviewed-by: %s\n' % self.joe}
990
991 patch1.comments = [comment1a]
992
993 patch2 = status.Patch('2')
994 patch2.parse_subject('[2/2] %s' % series.commits[1].subject)
995 patch2.name = patch2.raw_subject
996 patch2.content = 'Some other patch content'
997 comment2a = {
998 'content': 'Reviewed-by: %s\nTested-by: %s\n' %
999 (self.mary, self.leb)}
1000 comment2b = {
1001 'content': 'Reviewed-by: %s' % self.fred}
1002 patch2.comments = [comment2a, comment2b]
1003
1004 # This test works by setting up patches for use by the fake Rest API
1005 # function _fake_patchwork3(). The fake patch comments above should
1006 # result in new review tags that are collected and added to the commits
1007 # created in the destination branch.
1008 self.patches = [patch1, patch2]
1009 count = 2
1010
1011 # Expected output:
1012 # 1 i2c: I2C things
1013 # + Reviewed-by: Joe Bloggs <joe@napierwallies.co.nz>
1014 # 2 spi: SPI fixes
1015 # + Reviewed-by: Fred Bloggs <f.bloggs@napier.net>
1016 # + Reviewed-by: Mary Bloggs <mary@napierwallies.co.nz>
1017 # + Tested-by: Lord Edmund Blackaddër <weasel@blackadder.org>
1018 # 4 new responses available in patchwork
1019 # 4 responses added from patchwork into new branch 'first2'
1020 # <unittest.result.TestResult run=8 errors=0 failures=0>
1021
1022 terminal.SetPrintTestMode()
1023 status.check_patchwork_status(series, '1234', branch, dest_branch,
Simon Glassf9b03cf2020-11-03 13:54:14 -07001024 False, False, None, self._fake_patchwork3,
1025 repo)
Simon Glassd0a0a582020-10-29 21:46:36 -06001026 lines = terminal.GetPrintTestLines()
1027 self.assertEqual(12, len(lines))
1028 self.assertEqual(
1029 "4 responses added from patchwork into new branch 'first2'",
1030 lines[11].text)
1031
1032 # Check that the destination branch has the new tags
1033 new_series = patchstream.get_metadata_for_list(dest_branch, gitdir,
1034 count)
1035 self.assertEqual(
1036 {'Reviewed-by': {self.joe}},
1037 new_series.commits[0].rtags)
1038 self.assertEqual(
1039 {'Tested-by': {self.leb},
1040 'Reviewed-by': {self.fred, self.mary}},
1041 new_series.commits[1].rtags)
1042
1043 # Now check the actual test of the first commit message. We expect to
1044 # see the new tags immediately below the old ones.
1045 stdout = patchstream.get_list(dest_branch, count=count, git_dir=gitdir)
1046 lines = iter([line.strip() for line in stdout.splitlines()
1047 if '-by:' in line])
1048
1049 # First patch should have the review tag
1050 self.assertEqual('Reviewed-by: %s' % self.joe, next(lines))
1051
1052 # Second patch should have the sign-off then the tested-by and two
1053 # reviewed-by tags
1054 self.assertEqual('Signed-off-by: %s' % self.leb, next(lines))
1055 self.assertEqual('Reviewed-by: %s' % self.fred, next(lines))
1056 self.assertEqual('Reviewed-by: %s' % self.mary, next(lines))
1057 self.assertEqual('Tested-by: %s' % self.leb, next(lines))
Simon Glassda8a2922020-10-29 21:46:37 -06001058
1059 def testParseSnippets(self):
1060 """Test parsing of review snippets"""
1061 text = '''Hi Fred,
1062
1063This is a comment from someone.
1064
1065Something else
1066
1067On some recent date, Fred wrote:
1068> This is why I wrote the patch
1069> so here it is
1070
1071Now a comment about the commit message
1072A little more to say
1073
1074Even more
1075
1076> diff --git a/file.c b/file.c
1077> Some more code
1078> Code line 2
1079> Code line 3
1080> Code line 4
1081> Code line 5
1082> Code line 6
1083> Code line 7
1084> Code line 8
1085> Code line 9
1086
1087And another comment
1088
1089> @@ -153,8 +143,13 @@ def CheckPatch(fname, show_types=False):
1090> further down on the file
1091> and more code
1092> +Addition here
1093> +Another addition here
1094> codey
1095> more codey
1096
1097and another thing in same file
1098
1099> @@ -253,8 +243,13 @@
1100> with no function context
1101
1102one more thing
1103
1104> diff --git a/tools/patman/main.py b/tools/patman/main.py
1105> +line of code
1106now a very long comment in a different file
1107line2
1108line3
1109line4
1110line5
1111line6
1112line7
1113line8
1114'''
1115 pstrm = PatchStream.process_text(text, True)
1116 self.assertEqual([], pstrm.commit.warn)
1117
1118 # We expect to the filename and up to 5 lines of code context before
1119 # each comment. The 'On xxx wrote:' bit should be removed.
1120 self.assertEqual(
1121 [['Hi Fred,',
1122 'This is a comment from someone.',
1123 'Something else'],
1124 ['> This is why I wrote the patch',
1125 '> so here it is',
1126 'Now a comment about the commit message',
1127 'A little more to say', 'Even more'],
1128 ['> File: file.c', '> Code line 5', '> Code line 6',
1129 '> Code line 7', '> Code line 8', '> Code line 9',
1130 'And another comment'],
1131 ['> File: file.c',
1132 '> Line: 153 / 143: def CheckPatch(fname, show_types=False):',
1133 '> and more code', '> +Addition here', '> +Another addition here',
1134 '> codey', '> more codey', 'and another thing in same file'],
1135 ['> File: file.c', '> Line: 253 / 243',
1136 '> with no function context', 'one more thing'],
1137 ['> File: tools/patman/main.py', '> +line of code',
1138 'now a very long comment in a different file',
1139 'line2', 'line3', 'line4', 'line5', 'line6', 'line7', 'line8']],
1140 pstrm.snippets)
Simon Glass2112d072020-10-29 21:46:38 -06001141
Simon Glass2112d072020-10-29 21:46:38 -06001142 def testReviewSnippets(self):
1143 """Test showing of review snippets"""
1144 def _to_submitter(who):
1145 m_who = re.match('(.*) <(.*)>', who)
1146 return {
1147 'name': m_who.group(1),
1148 'email': m_who.group(2)
1149 }
1150
1151 commit1 = Commit('abcd')
1152 commit1.subject = 'Subject 1'
1153 commit2 = Commit('ef12')
1154 commit2.subject = 'Subject 2'
1155
1156 patch1 = status.Patch('1')
1157 patch1.parse_subject('[1/2] Subject 1')
1158 patch1.name = patch1.raw_subject
1159 patch1.content = 'This is my patch content'
1160 comment1a = {'submitter': _to_submitter(self.joe),
1161 'content': '''Hi Fred,
1162
1163On some date Fred wrote:
1164
1165> diff --git a/file.c b/file.c
1166> Some code
1167> and more code
1168
1169Here is my comment above the above...
1170
1171
1172Reviewed-by: %s
1173''' % self.joe}
1174
1175 patch1.comments = [comment1a]
1176
1177 patch2 = status.Patch('2')
1178 patch2.parse_subject('[2/2] Subject 2')
1179 patch2.name = patch2.raw_subject
1180 patch2.content = 'Some other patch content'
1181 comment2a = {
1182 'content': 'Reviewed-by: %s\nTested-by: %s\n' %
1183 (self.mary, self.leb)}
1184 comment2b = {'submitter': _to_submitter(self.fred),
1185 'content': '''Hi Fred,
1186
1187On some date Fred wrote:
1188
1189> diff --git a/tools/patman/commit.py b/tools/patman/commit.py
1190> @@ -41,6 +41,9 @@ class Commit:
1191> self.rtags = collections.defaultdict(set)
1192> self.warn = []
1193>
1194> + def __str__(self):
1195> + return self.subject
1196> +
1197> def AddChange(self, version, info):
1198> """Add a new change line to the change list for a version.
1199>
1200A comment
1201
1202Reviewed-by: %s
1203''' % self.fred}
1204 patch2.comments = [comment2a, comment2b]
1205
1206 # This test works by setting up commits and patch for use by the fake
1207 # Rest API function _fake_patchwork2(). It calls various functions in
1208 # the status module after setting up tags in the commits, checking that
1209 # things behaves as expected
1210 self.commits = [commit1, commit2]
1211 self.patches = [patch1, patch2]
1212
1213 # Check that the output patches expectations:
1214 # 1 Subject 1
1215 # Reviewed-by: Joe Bloggs <joe@napierwallies.co.nz>
1216 # 2 Subject 2
1217 # Tested-by: Lord Edmund Blackaddër <weasel@blackadder.org>
1218 # Reviewed-by: Fred Bloggs <f.bloggs@napier.net>
1219 # + Reviewed-by: Mary Bloggs <mary@napierwallies.co.nz>
1220 # 1 new response available in patchwork
1221
1222 series = Series()
1223 series.commits = [commit1, commit2]
1224 terminal.SetPrintTestMode()
1225 status.check_patchwork_status(series, '1234', None, None, False, True,
Simon Glassf9b03cf2020-11-03 13:54:14 -07001226 None, self._fake_patchwork2)
Simon Glass2112d072020-10-29 21:46:38 -06001227 lines = iter(terminal.GetPrintTestLines())
1228 col = terminal.Color()
1229 self.assertEqual(terminal.PrintLine(' 1 Subject 1', col.BLUE),
1230 next(lines))
1231 self.assertEqual(
1232 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
1233 next(lines))
1234 self.assertEqual(terminal.PrintLine(self.joe, col.WHITE), next(lines))
1235
1236 self.assertEqual(terminal.PrintLine('Review: %s' % self.joe, col.RED),
1237 next(lines))
1238 self.assertEqual(terminal.PrintLine(' Hi Fred,', None), next(lines))
1239 self.assertEqual(terminal.PrintLine('', None), next(lines))
1240 self.assertEqual(terminal.PrintLine(' > File: file.c', col.MAGENTA),
1241 next(lines))
1242 self.assertEqual(terminal.PrintLine(' > Some code', col.MAGENTA),
1243 next(lines))
1244 self.assertEqual(terminal.PrintLine(' > and more code', col.MAGENTA),
1245 next(lines))
1246 self.assertEqual(terminal.PrintLine(
1247 ' Here is my comment above the above...', None), next(lines))
1248 self.assertEqual(terminal.PrintLine('', None), next(lines))
1249
1250 self.assertEqual(terminal.PrintLine(' 2 Subject 2', col.BLUE),
1251 next(lines))
1252 self.assertEqual(
1253 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
1254 next(lines))
1255 self.assertEqual(terminal.PrintLine(self.fred, col.WHITE),
1256 next(lines))
1257 self.assertEqual(
1258 terminal.PrintLine(' + Reviewed-by: ', col.GREEN, newline=False),
1259 next(lines))
1260 self.assertEqual(terminal.PrintLine(self.mary, col.WHITE),
1261 next(lines))
1262 self.assertEqual(
1263 terminal.PrintLine(' + Tested-by: ', col.GREEN, newline=False),
1264 next(lines))
1265 self.assertEqual(terminal.PrintLine(self.leb, col.WHITE),
1266 next(lines))
1267
1268 self.assertEqual(terminal.PrintLine('Review: %s' % self.fred, col.RED),
1269 next(lines))
1270 self.assertEqual(terminal.PrintLine(' Hi Fred,', None), next(lines))
1271 self.assertEqual(terminal.PrintLine('', None), next(lines))
1272 self.assertEqual(terminal.PrintLine(
1273 ' > File: tools/patman/commit.py', col.MAGENTA), next(lines))
1274 self.assertEqual(terminal.PrintLine(
1275 ' > Line: 41 / 41: class Commit:', col.MAGENTA), next(lines))
1276 self.assertEqual(terminal.PrintLine(
1277 ' > + return self.subject', col.MAGENTA), next(lines))
1278 self.assertEqual(terminal.PrintLine(
1279 ' > +', col.MAGENTA), next(lines))
1280 self.assertEqual(
1281 terminal.PrintLine(' > def AddChange(self, version, info):',
1282 col.MAGENTA),
1283 next(lines))
1284 self.assertEqual(terminal.PrintLine(
1285 ' > """Add a new change line to the change list for a version.',
1286 col.MAGENTA), next(lines))
1287 self.assertEqual(terminal.PrintLine(
1288 ' >', col.MAGENTA), next(lines))
1289 self.assertEqual(terminal.PrintLine(
1290 ' A comment', None), next(lines))
1291 self.assertEqual(terminal.PrintLine('', None), next(lines))
1292
1293 self.assertEqual(terminal.PrintLine(
1294 '4 new responses available in patchwork (use -d to write them to a new branch)',
1295 None), next(lines))
Simon Glass6a222e62021-08-01 16:02:39 -06001296
1297 def testInsertTags(self):
1298 """Test inserting of review tags"""
1299 msg = '''first line
1300second line.'''
1301 tags = [
1302 'Reviewed-by: Bin Meng <bmeng.cn@gmail.com>',
1303 'Tested-by: Bin Meng <bmeng.cn@gmail.com>'
1304 ]
1305 signoff = 'Signed-off-by: Simon Glass <sjg@chromium.com>'
1306 tag_str = '\n'.join(tags)
1307
1308 new_msg = patchstream.insert_tags(msg, tags)
1309 self.assertEqual(msg + '\n\n' + tag_str, new_msg)
1310
1311 new_msg = patchstream.insert_tags(msg + '\n', tags)
1312 self.assertEqual(msg + '\n\n' + tag_str, new_msg)
1313
1314 msg += '\n\n' + signoff
1315 new_msg = patchstream.insert_tags(msg, tags)
1316 self.assertEqual(msg + '\n' + tag_str, new_msg)