From efce0d1b7657c440c90f0f4bce614b96672b9e0b Mon Sep 17 00:00:00 2001 From: Edward Lemur Date: Sat, 7 Sep 2019 03:36:37 +0000 Subject: [PATCH] gclient_utils: Fix bug in CheckCallAndFilter in Python 3. Header was printed using sys.stdout, but the rest of the output was printed using sys.stdout.buffer, causing the output to be written before the header. Bug: 984182 Change-Id: If6aaa05a579c3b0c73ce8ffe48f3a4e777fa16fa Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/1790254 Auto-Submit: Edward Lesmes Commit-Queue: Andrii Shyshkalov Reviewed-by: Andrii Shyshkalov --- gclient_utils.py | 3 ++- tests/gclient_utils_test.py | 41 ++++++++++++++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/gclient_utils.py b/gclient_utils.py index 7b4ae5664b..38341337a2 100644 --- a/gclient_utils.py +++ b/gclient_utils.py @@ -527,7 +527,8 @@ def CheckCallAndFilter(args, print_stdout=False, filter_fn=None, header += '\n' if print_stdout: - sys.stdout.write(header) + stdout_write = getattr(sys.stdout, 'buffer', sys.stdout).write + stdout_write(header.encode()) if filter_fn: filter_fn(header) diff --git a/tests/gclient_utils_test.py b/tests/gclient_utils_test.py index adb0e633dd..670775a68e 100755 --- a/tests/gclient_utils_test.py +++ b/tests/gclient_utils_test.py @@ -4,6 +4,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +from __future__ import print_function from __future__ import unicode_literals import io @@ -33,7 +34,15 @@ class CheckCallAndFilterTestCase(unittest.TestCase): def setUp(self): super(CheckCallAndFilterTestCase, self).setUp() - mock.patch('sys.stdout', io.StringIO()).start() + self.printfn = io.StringIO() + self.stdout = io.BytesIO() + if sys.version_info.major == 2: + mock.patch('sys.stdout', self.stdout).start() + mock.patch('__builtin__.print', self.printfn.write).start() + else: + mock.patch('sys.stdout', mock.Mock()).start() + mock.patch('sys.stdout.buffer', self.stdout).start() + mock.patch('builtins.print', self.printfn.write).start() mock.patch('sys.stdout.flush', lambda: None).start() self.addCleanup(mock.patch.stopall) @@ -58,6 +67,7 @@ class CheckCallAndFilterTestCase(unittest.TestCase): 'allo', 'addb', 'āœ”']) + self.assertEqual(self.stdout.getvalue(), b'') mockPopen.assert_called_with( args, cwd=cwd, stdout=subprocess2.PIPE, stderr=subprocess2.STDOUT, @@ -110,10 +120,35 @@ class CheckCallAndFilterTestCase(unittest.TestCase): stderr=subprocess2.STDOUT, bufsize=0), ]) + self.assertEqual(self.stdout.getvalue(), b'') self.assertEqual( - sys.stdout.getvalue(), + self.printfn.getvalue(), 'WARNING: subprocess \'"boo" "foo" "bar"\' in bleh failed; will retry ' - 'after a short nap...\n') + 'after a short nap...') + + @mock.patch('subprocess2.Popen') + def testCHeckCallAndFilter_PrintStdout(self, mockPopen): + cwd = 'bleh' + args = ['boo', 'foo', 'bar'] + test_string = 'ahah\naccb\nallo\naddb\nāœ”' + + mockPopen.return_value = self.ProcessIdMock(test_string) + + result = gclient_utils.CheckCallAndFilter( + args, cwd=cwd, show_header=True, always_show_header=True, + print_stdout=True) + + self.assertEqual(result, test_string.encode('utf-8')) + self.assertEqual( + self.stdout.getvalue().splitlines(), + [ + b'________ running \'boo foo bar\' in \'bleh\'', + b'ahah', + b'accb', + b'allo', + b'addb', + b'\xe2\x9c\x94', + ]) class SplitUrlRevisionTestCase(unittest.TestCase):