depot_tools: Run git_common_test in Python 3

Bug: 1009809
Change-Id: Idfcbd26de3420798f092c7fa55a6126d7c389a8c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/1834317
Reviewed-by: Anthony Polito <apolito@google.com>
Commit-Queue: Edward Lesmes <ehmaldonado@chromium.org>
changes/17/1834317/8
Edward Lemur 6 years ago committed by Commit Bot
parent 4508b4223b
commit 12a537f932

@ -6,12 +6,13 @@
# Derived from https://gist.github.com/aljungberg/626518 # Derived from https://gist.github.com/aljungberg/626518
from __future__ import print_function from __future__ import print_function
from __future__ import unicode_literals
import multiprocessing.pool import multiprocessing.pool
from multiprocessing.pool import IMapIterator from multiprocessing.pool import IMapIterator
def wrapper(func): def wrapper(func):
def wrap(self, timeout=None): def wrap(self, timeout=None):
return func(self, timeout=timeout or 1e100) return func(self, timeout=timeout or 1 << 31)
return wrap return wrap
IMapIterator.next = wrapper(IMapIterator.next) IMapIterator.next = wrapper(IMapIterator.next)
IMapIterator.__next__ = IMapIterator.next IMapIterator.__next__ = IMapIterator.next
@ -303,11 +304,17 @@ class ProgressPrinter(object):
def once(function): def once(function):
"""@Decorates |function| so that it only performs its action once, no matter """@Decorates |function| so that it only performs its action once, no matter
how many times the decorated |function| is called.""" how many times the decorated |function| is called."""
def _inner_gen(): has_run = [False]
yield function() def _wrapper(*args, **kwargs):
while True: if not has_run[0]:
yield has_run[0] = True
return _inner_gen().next function(*args, **kwargs)
return _wrapper
def unicode_repr(s):
result = repr(s)
return result[1:] if result.startswith('u') else result
## Git functions ## Git functions
@ -597,8 +604,8 @@ def mktree(treedict):
treedict - { name: (mode, type, ref) } treedict - { name: (mode, type, ref) }
""" """
with tempfile.TemporaryFile() as f: with tempfile.TemporaryFile() as f:
for name, (mode, typ, ref) in treedict.iteritems(): for name, (mode, typ, ref) in treedict.items():
f.write('%s %s %s\t%s\0' % (mode, typ, ref, name)) f.write(('%s %s %s\t%s\0' % (mode, typ, ref, name)).encode())
f.seek(0) f.seek(0)
return run('mktree', '-z', stdin=f) return run('mktree', '-z', stdin=f)
@ -612,7 +619,7 @@ def parse_commitrefs(*commitrefs):
* 'cool_branch~2' * 'cool_branch~2'
""" """
try: try:
return map(binascii.unhexlify, hash_multi(*commitrefs)) return [binascii.unhexlify(h) for h in hash_multi(*commitrefs)]
except subprocess2.CalledProcessError: except subprocess2.CalledProcessError:
raise BadCommitRefException(commitrefs) raise BadCommitRefException(commitrefs)
@ -751,6 +758,7 @@ def run_with_stderr(*cmd, **kwargs):
kwargs.setdefault('shell', False) kwargs.setdefault('shell', False)
autostrip = kwargs.pop('autostrip', True) autostrip = kwargs.pop('autostrip', True)
indata = kwargs.pop('indata', None) indata = kwargs.pop('indata', None)
decode = kwargs.pop('decode', True)
cmd = (GIT_EXE, '-c', 'color.ui=never') + cmd cmd = (GIT_EXE, '-c', 'color.ui=never') + cmd
proc = subprocess2.Popen(cmd, **kwargs) proc = subprocess2.Popen(cmd, **kwargs)
@ -760,8 +768,12 @@ def run_with_stderr(*cmd, **kwargs):
raise subprocess2.CalledProcessError(retcode, cmd, os.getcwd(), ret, err) raise subprocess2.CalledProcessError(retcode, cmd, os.getcwd(), ret, err)
if autostrip: if autostrip:
ret = (ret or '').strip() ret = (ret or b'').strip()
err = (err or '').strip() err = (err or b'').strip()
if decode:
ret = ret.decode('utf-8', 'replace')
err = err.decode('utf-8', 'replace')
return ret, err return ret, err
@ -810,9 +822,9 @@ def status():
def tokenizer(stream): def tokenizer(stream):
acc = BytesIO() acc = BytesIO()
c = None c = None
while c != '': while c != b'':
c = stream.read(1) c = stream.read(1)
if c in (None, '', '\0'): if c in (None, b'', b'\0'):
if len(acc.getvalue()): if len(acc.getvalue()):
yield acc.getvalue() yield acc.getvalue()
acc = BytesIO() acc = BytesIO()
@ -821,12 +833,14 @@ def status():
def parser(tokens): def parser(tokens):
while True: while True:
# Raises StopIteration if it runs out of tokens. try:
status_dest = next(tokens) status_dest = next(tokens).decode('utf-8')
except StopIteration:
return
stat, dest = status_dest[:2], status_dest[3:] stat, dest = status_dest[:2], status_dest[3:]
lstat, rstat = stat lstat, rstat = stat
if lstat == 'R': if lstat == 'R':
src = next(tokens) src = next(tokens).decode('utf-8')
else: else:
src = dest src = dest
yield (dest, stat_entry(lstat, rstat, src)) yield (dest, stat_entry(lstat, rstat, src))
@ -848,7 +862,7 @@ def squash_current_branch(header=None, merge_base=None):
# nothing to commit at this point. # nothing to commit at this point.
print('Nothing to commit; squashed branch is empty') print('Nothing to commit; squashed branch is empty')
return False return False
run('commit', '--no-verify', '-a', '-F', '-', indata=log_msg) run('commit', '--no-verify', '-a', '-F', '-', indata=log_msg.encode())
return True return True
@ -858,7 +872,8 @@ def tags(*args):
def thaw(): def thaw():
took_action = False took_action = False
for sha in (s.strip() for s in run_stream('rev-list', 'HEAD').xreadlines()): for sha in run_stream('rev-list', 'HEAD').readlines():
sha = sha.strip().decode('utf-8')
msg = run('show', '--format=%f%b', '-s', 'HEAD') msg = run('show', '--format=%f%b', '-s', 'HEAD')
match = FREEZE_MATCHER.match(msg) match = FREEZE_MATCHER.match(msg)
if not match: if not match:
@ -899,7 +914,7 @@ def topo_iter(branch_tree, top_down=True):
# TODO(iannucci): There is probably a more efficient way to do these. # TODO(iannucci): There is probably a more efficient way to do these.
if top_down: if top_down:
while branch_tree: while branch_tree:
this_pass = [(b, p) for b, p in branch_tree.iteritems() this_pass = [(b, p) for b, p in branch_tree.items()
if p not in branch_tree] if p not in branch_tree]
assert this_pass, "Branch tree has cycles: %r" % branch_tree assert this_pass, "Branch tree has cycles: %r" % branch_tree
for branch, parent in sorted(this_pass): for branch, parent in sorted(this_pass):
@ -907,11 +922,11 @@ def topo_iter(branch_tree, top_down=True):
del branch_tree[branch] del branch_tree[branch]
else: else:
parent_to_branches = collections.defaultdict(set) parent_to_branches = collections.defaultdict(set)
for branch, parent in branch_tree.iteritems(): for branch, parent in branch_tree.items():
parent_to_branches[parent].add(branch) parent_to_branches[parent].add(branch)
while branch_tree: while branch_tree:
this_pass = [(b, p) for b, p in branch_tree.iteritems() this_pass = [(b, p) for b, p in branch_tree.items()
if not parent_to_branches[b]] if not parent_to_branches[b]]
assert this_pass, "Branch tree has cycles: %r" % branch_tree assert this_pass, "Branch tree has cycles: %r" % branch_tree
for branch, parent in sorted(this_pass): for branch, parent in sorted(this_pass):
@ -1014,7 +1029,9 @@ def get_branches_info(include_tracking_status):
if info.upstream not in info_map and info.upstream not in missing_upstreams: if info.upstream not in info_map and info.upstream not in missing_upstreams:
missing_upstreams[info.upstream] = None missing_upstreams[info.upstream] = None
return dict(info_map.items() + missing_upstreams.items()) result = info_map.copy()
result.update(missing_upstreams)
return result
def make_workdir_common(repository, new_workdir, files_to_symlink, def make_workdir_common(repository, new_workdir, files_to_symlink,

@ -7,6 +7,7 @@
""" """
from __future__ import print_function from __future__ import print_function
from __future__ import unicode_literals
import argparse import argparse
import collections import collections
@ -94,11 +95,6 @@ def parse_blame(blameoutput):
yield BlameLine(commit, context, lineno_then, lineno_now, False) yield BlameLine(commit, context, lineno_then, lineno_now, False)
def num_codepoints(s):
"""Gets the length of a UTF-8 byte string, in Unicode codepoints."""
return len(s.decode('utf-8', errors='replace'))
def print_table(table, colsep=' ', rowsep='\n', align=None, out=sys.stdout): def print_table(table, colsep=' ', rowsep='\n', align=None, out=sys.stdout):
"""Print a 2D rectangular array, aligning columns with spaces. """Print a 2D rectangular array, aligning columns with spaces.
@ -112,10 +108,9 @@ def print_table(table, colsep=' ', rowsep='\n', align=None, out=sys.stdout):
colwidths = None colwidths = None
for row in table: for row in table:
if colwidths is None: if colwidths is None:
colwidths = [num_codepoints(x) for x in row] colwidths = [len(x) for x in row]
else: else:
colwidths = [max(colwidths[i], num_codepoints(x)) colwidths = [max(colwidths[i], len(x)) for i, x in enumerate(row)]
for i, x in enumerate(row)]
if align is None: # pragma: no cover if align is None: # pragma: no cover
align = 'l' * len(colwidths) align = 'l' * len(colwidths)
@ -123,7 +118,7 @@ def print_table(table, colsep=' ', rowsep='\n', align=None, out=sys.stdout):
for row in table: for row in table:
cells = [] cells = []
for i, cell in enumerate(row): for i, cell in enumerate(row):
padding = ' ' * (colwidths[i] - num_codepoints(cell)) padding = ' ' * (colwidths[i] - len(cell))
if align[i] == 'r': if align[i] == 'r':
cell = padding + cell cell = padding + cell
elif i < len(row) - 1: elif i < len(row) - 1:
@ -279,7 +274,7 @@ def hyper_blame(ignored, filename, revision='HEAD', out=sys.stdout,
try: try:
parsed = cache_blame_from(filename, git_common.hash_one(revision)) parsed = cache_blame_from(filename, git_common.hash_one(revision))
except subprocess2.CalledProcessError as e: except subprocess2.CalledProcessError as e:
err.write(e.stderr) err.write(e.stderr.decode())
return e.returncode return e.returncode
new_parsed = [] new_parsed = []
@ -361,7 +356,7 @@ def main(args, stdout=sys.stdout, stderr=sys.stderr):
try: try:
repo_root = git_common.repo_root() repo_root = git_common.repo_root()
except subprocess2.CalledProcessError as e: except subprocess2.CalledProcessError as e:
stderr.write(e.stderr) stderr.write(e.stderr.decode())
return e.returncode return e.returncode
# Make filename relative to the repository root, and cd to the root dir (so # Make filename relative to the repository root, and cd to the root dir (so

@ -75,7 +75,8 @@ def get_number_tree(prefix_bytes):
ref = '%s:%s' % (REF, pathlify(prefix_bytes)) ref = '%s:%s' % (REF, pathlify(prefix_bytes))
try: try:
raw = buffer(git.run('cat-file', 'blob', ref, autostrip=False)) raw = buffer(
git.run('cat-file', 'blob', ref, autostrip=False, decode=False))
return dict(struct.unpack_from(CHUNK_FMT, raw, i * CHUNK_SIZE) return dict(struct.unpack_from(CHUNK_FMT, raw, i * CHUNK_SIZE)
for i in xrange(len(raw) / CHUNK_SIZE)) for i in xrange(len(raw) / CHUNK_SIZE))
except subprocess2.CalledProcessError: except subprocess2.CalledProcessError:

@ -320,8 +320,8 @@ def main(args=None):
else: else:
root_branch = git.root() root_branch = git.root()
if return_branch != 'HEAD': if return_branch != 'HEAD':
print("%r was merged with its parent, checking out %r instead." % print("%s was merged with its parent, checking out %s instead." %
(return_branch, root_branch)) (git.unicode_repr(return_branch), git.unicode_repr(root_branch)))
git.run('checkout', root_branch) git.run('checkout', root_branch)
# return_workdir may also not be there any more. # return_workdir may also not be there any more.

@ -15,13 +15,18 @@ import tempfile
import unittest import unittest
if sys.version_info.major == 3:
# pylint: disable=redefined-builtin
basestring = (str,)
def git_hash_data(data, typ='blob'): def git_hash_data(data, typ='blob'):
"""Calculate the git-style SHA1 for some data. """Calculate the git-style SHA1 for some data.
Only supports 'blob' type data at the moment. Only supports 'blob' type data at the moment.
""" """
assert typ == 'blob', 'Only support blobs for now' assert typ == 'blob', 'Only support blobs for now'
return hashlib.sha1('blob %s\0%s' % (len(data), data)).hexdigest() return hashlib.sha1(b'blob %d\0%s' % (len(data), data)).hexdigest()
class OrderedSet(collections.MutableSet): class OrderedSet(collections.MutableSet):
@ -121,7 +126,7 @@ class GitRepoSchema(object):
This is the repo This is the repo
A - B - C - D A - B - C - D
\ E / \\ E /
Whitespace doesn't matter. Each line is a declaration of which commits come Whitespace doesn't matter. Each line is a declaration of which commits come
before which other commits. before which other commits.
@ -166,15 +171,15 @@ class GitRepoSchema(object):
is_root = True is_root = True
par_map = copy.deepcopy(self.par_map) par_map = copy.deepcopy(self.par_map)
while par_map: while par_map:
empty_keys = set(k for k, v in par_map.iteritems() if not v) empty_keys = set(k for k, v in par_map.items() if not v)
assert empty_keys, 'Cycle detected! %s' % par_map assert empty_keys, 'Cycle detected! %s' % par_map
for k in sorted(empty_keys): for k in sorted(empty_keys):
yield self.COMMIT(k, self.par_map[k], yield self.COMMIT(k, self.par_map[k],
not any(k in v for v in self.par_map.itervalues()), not any(k in v for v in self.par_map.values()),
is_root) is_root)
del par_map[k] del par_map[k]
for v in par_map.itervalues(): for v in par_map.values():
v.difference_update(empty_keys) v.difference_update(empty_keys)
is_root = False is_root = False
@ -321,7 +326,7 @@ class GitRepo(object):
env = self.get_git_commit_env(commit_data) env = self.get_git_commit_env(commit_data)
for fname, file_data in commit_data.iteritems(): for fname, file_data in commit_data.items():
# If it isn't a string, it's one of the special keys. # If it isn't a string, it's one of the special keys.
if not isinstance(fname, basestring): if not isinstance(fname, basestring):
continue continue
@ -367,7 +372,9 @@ class GitRepo(object):
self._date += datetime.timedelta(days=1) self._date += datetime.timedelta(days=1)
else: else:
val = getattr(self, 'DEFAULT_%s' % singleton) val = getattr(self, 'DEFAULT_%s' % singleton)
env['GIT_%s' % singleton] = str(val) if not isinstance(val, str) and not isinstance(val, bytes):
val = str(val)
env['GIT_%s' % singleton] = val
return env return env
def git(self, *args, **kwargs): def git(self, *args, **kwargs):
@ -377,6 +384,7 @@ class GitRepo(object):
with open(os.devnull, 'wb') as devnull: with open(os.devnull, 'wb') as devnull:
output = subprocess.check_output( output = subprocess.check_output(
('git',) + args, cwd=self.repo_path, stderr=devnull, **kwargs) ('git',) + args, cwd=self.repo_path, stderr=devnull, **kwargs)
output = output.decode('utf-8')
return self.COMMAND_OUTPUT(0, output) return self.COMMAND_OUTPUT(0, output)
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
return self.COMMAND_OUTPUT(e.returncode, e.output) return self.COMMAND_OUTPUT(e.returncode, e.output)
@ -418,8 +426,8 @@ class GitRepo(object):
stdout = sys.stdout stdout = sys.stdout
stderr = sys.stderr stderr = sys.stderr
try: try:
# "multiple statements on a line" pylint: disable=multiple-statements with tempfile.TemporaryFile('w+') as out:
with tempfile.TemporaryFile() as out, tempfile.TemporaryFile() as err: with tempfile.TemporaryFile('w+') as err:
sys.stdout = out sys.stdout = out
sys.stderr = err sys.stderr = err
try: try:

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env vpython3
# Copyright 2013 The Chromium Authors. All rights reserved. # Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
@ -85,7 +85,7 @@ class Support(GitCommonTestBase):
add_to_list() add_to_list()
add_to_list() add_to_list()
self.assertEquals(testlist, ['dog']) self.assertEqual(testlist, ['dog'])
def slow_square(i): def slow_square(i):
@ -102,7 +102,7 @@ class ScopedPoolTest(GitCommonTestBase):
def testThreads(self): def testThreads(self):
result = [] result = []
with self.gc.ScopedPool(kind='threads') as pool: with self.gc.ScopedPool(kind='threads') as pool:
result = list(pool.imap(slow_square, xrange(10))) result = list(pool.imap(slow_square, range(10)))
self.assertEqual([0, 1, 4, 9, 16, 25, 36, 49, 64, 81], result) self.assertEqual([0, 1, 4, 9, 16, 25, 36, 49, 64, 81], result)
def testThreadsCtrlC(self): def testThreadsCtrlC(self):
@ -110,7 +110,7 @@ class ScopedPoolTest(GitCommonTestBase):
with self.assertRaises(KeyboardInterrupt): with self.assertRaises(KeyboardInterrupt):
with self.gc.ScopedPool(kind='threads') as pool: with self.gc.ScopedPool(kind='threads') as pool:
# Make sure this pool is interrupted in mid-swing # Make sure this pool is interrupted in mid-swing
for i in pool.imap(slow_square, xrange(20)): for i in pool.imap(slow_square, range(20)):
if i > 32: if i > 32:
os.kill(os.getpid(), self.CTRL_C) os.kill(os.getpid(), self.CTRL_C)
result.append(i) result.append(i)
@ -119,7 +119,7 @@ class ScopedPoolTest(GitCommonTestBase):
def testProcs(self): def testProcs(self):
result = [] result = []
with self.gc.ScopedPool() as pool: with self.gc.ScopedPool() as pool:
result = list(pool.imap(slow_square, xrange(10))) result = list(pool.imap(slow_square, range(10)))
self.assertEqual([0, 1, 4, 9, 16, 25, 36, 49, 64, 81], result) self.assertEqual([0, 1, 4, 9, 16, 25, 36, 49, 64, 81], result)
def testProcsCtrlC(self): def testProcsCtrlC(self):
@ -127,7 +127,7 @@ class ScopedPoolTest(GitCommonTestBase):
with self.assertRaises(KeyboardInterrupt): with self.assertRaises(KeyboardInterrupt):
with self.gc.ScopedPool() as pool: with self.gc.ScopedPool() as pool:
# Make sure this pool is interrupted in mid-swing # Make sure this pool is interrupted in mid-swing
for i in pool.imap(slow_square, xrange(20)): for i in pool.imap(slow_square, range(20)):
if i > 32: if i > 32:
os.kill(os.getpid(), self.CTRL_C) os.kill(os.getpid(), self.CTRL_C)
result.append(i) result.append(i)
@ -146,7 +146,6 @@ class ProgressPrinterTest(GitCommonTestBase):
def flush(self): def flush(self):
self.count += 1 self.count += 1
@unittest.expectedFailure
def testBasic(self): def testBasic(self):
"""This test is probably racy, but I don't have a better alternative.""" """This test is probably racy, but I don't have a better alternative."""
fmt = '%(count)d/10' fmt = '%(count)d/10'
@ -154,12 +153,12 @@ class ProgressPrinterTest(GitCommonTestBase):
pp = self.gc.ProgressPrinter(fmt, enabled=True, fout=stream, period=0.01) pp = self.gc.ProgressPrinter(fmt, enabled=True, fout=stream, period=0.01)
with pp as inc: with pp as inc:
for _ in xrange(10): for _ in range(10):
time.sleep(0.02) time.sleep(0.02)
inc() inc()
filtered = {x.strip() for x in stream.data} filtered = {x.strip() for x in stream.data}
rslt = {fmt % {'count': i} for i in xrange(11)} rslt = {fmt % {'count': i} for i in range(11)}
self.assertSetEqual(filtered, rslt) self.assertSetEqual(filtered, rslt)
self.assertGreaterEqual(stream.count, 10) self.assertGreaterEqual(stream.count, 10)
@ -172,24 +171,24 @@ class GitReadOnlyFunctionsTest(git_test_utils.GitRepoReadOnlyTestBase,
""" """
COMMIT_A = { COMMIT_A = {
'some/files/file1': {'data': 'file1'}, 'some/files/file1': {'data': b'file1'},
'some/files/file2': {'data': 'file2'}, 'some/files/file2': {'data': b'file2'},
'some/files/file3': {'data': 'file3'}, 'some/files/file3': {'data': b'file3'},
'some/other/file': {'data': 'otherfile'}, 'some/other/file': {'data': b'otherfile'},
} }
COMMIT_C = { COMMIT_C = {
'some/files/file2': { 'some/files/file2': {
'mode': 0o755, 'mode': 0o755,
'data': 'file2 - vanilla\n'}, 'data': b'file2 - vanilla\n'},
} }
COMMIT_E = { COMMIT_E = {
'some/files/file2': {'data': 'file2 - merged\n'}, 'some/files/file2': {'data': b'file2 - merged\n'},
} }
COMMIT_D = { COMMIT_D = {
'some/files/file2': {'data': 'file2 - vanilla\nfile2 - merged\n'}, 'some/files/file2': {'data': b'file2 - vanilla\nfile2 - merged\n'},
} }
def testHashes(self): def testHashes(self):
@ -209,7 +208,7 @@ class GitReadOnlyFunctionsTest(git_test_utils.GitRepoReadOnlyTestBase,
self.repo['E'], self.repo['E'],
self.repo['C'], self.repo['C'],
], ret) ], ret)
self.assertEquals( self.assertEqual(
self.repo.run(self.gc.hash_one, 'branch_D'), self.repo.run(self.gc.hash_one, 'branch_D'),
self.repo['D'] self.repo['D']
) )
@ -217,23 +216,23 @@ class GitReadOnlyFunctionsTest(git_test_utils.GitRepoReadOnlyTestBase,
self.repo.run(self.gc.hash_one, 'branch_D', short=True))) self.repo.run(self.gc.hash_one, 'branch_D', short=True)))
def testStream(self): def testStream(self):
items = set(self.repo.commit_map.itervalues()) items = set(self.repo.commit_map.values())
def testfn(): def testfn():
for line in self.gc.run_stream('log', '--format=%H').xreadlines(): for line in self.gc.run_stream('log', '--format=%H').readlines():
line = line.strip() line = line.strip().decode('utf-8')
self.assertIn(line, items) self.assertIn(line, items)
items.remove(line) items.remove(line)
self.repo.run(testfn) self.repo.run(testfn)
def testStreamWithRetcode(self): def testStreamWithRetcode(self):
items = set(self.repo.commit_map.itervalues()) items = set(self.repo.commit_map.values())
def testfn(): def testfn():
with self.gc.run_stream_with_retcode('log', '--format=%H') as stdout: with self.gc.run_stream_with_retcode('log', '--format=%H') as stdout:
for line in stdout.xreadlines(): for line in stdout.readlines():
line = line.strip() line = line.strip().decode('utf-8')
self.assertIn(line, items) self.assertIn(line, items)
items.remove(line) items.remove(line)
@ -326,13 +325,14 @@ class GitReadOnlyFunctionsTest(git_test_utils.GitRepoReadOnlyTestBase,
'tag_C^{}', 'tag_C^{}',
] ]
) )
self.assertEqual(ret, map(binascii.unhexlify, [ hashes = [
self.repo['D'], self.repo['D'],
self.repo['A'], self.repo['A'],
self.repo['B'], self.repo['B'],
self.repo['E'], self.repo['E'],
self.repo['C'], self.repo['C'],
])) ]
self.assertEqual(ret, [binascii.unhexlify(h) for h in hashes])
with self.assertRaisesRegexp(Exception, r"one of \('master', 'bananas'\)"): with self.assertRaisesRegexp(Exception, r"one of \('master', 'bananas'\)"):
self.repo.run(self.gc.parse_commitrefs, 'master', 'bananas') self.repo.run(self.gc.parse_commitrefs, 'master', 'bananas')
@ -356,20 +356,20 @@ class GitReadOnlyFunctionsTest(git_test_utils.GitRepoReadOnlyTestBase,
file1 = self.COMMIT_A['some/files/file1']['data'] file1 = self.COMMIT_A['some/files/file1']['data']
file2 = self.COMMIT_D['some/files/file2']['data'] file2 = self.COMMIT_D['some/files/file2']['data']
file3 = self.COMMIT_A['some/files/file3']['data'] file3 = self.COMMIT_A['some/files/file3']['data']
self.assertEquals( self.assertEqual(
tree['file1'], tree['file1'],
('100644', 'blob', git_test_utils.git_hash_data(file1))) ('100644', 'blob', git_test_utils.git_hash_data(file1)))
self.assertEquals( self.assertEqual(
tree['file2'], tree['file2'],
('100755', 'blob', git_test_utils.git_hash_data(file2))) ('100755', 'blob', git_test_utils.git_hash_data(file2)))
self.assertEquals( self.assertEqual(
tree['file3'], tree['file3'],
('100644', 'blob', git_test_utils.git_hash_data(file3))) ('100644', 'blob', git_test_utils.git_hash_data(file3)))
tree = self.repo.run(self.gc.tree, 'master:some') tree = self.repo.run(self.gc.tree, 'master:some')
self.assertEquals(len(tree), 2) self.assertEqual(len(tree), 2)
# Don't check the tree hash because we're lazy :) # Don't check the tree hash because we're lazy :)
self.assertEquals(tree['files'][:2], ('040000', 'tree')) self.assertEqual(tree['files'][:2], ('040000', 'tree'))
tree = self.repo.run(self.gc.tree, 'master:wat') tree = self.repo.run(self.gc.tree, 'master:wat')
self.assertEqual(tree, None) self.assertEqual(tree, None)
@ -380,16 +380,16 @@ class GitReadOnlyFunctionsTest(git_test_utils.GitRepoReadOnlyTestBase,
file2 = self.COMMIT_D['some/files/file2']['data'] file2 = self.COMMIT_D['some/files/file2']['data']
file3 = self.COMMIT_A['some/files/file3']['data'] file3 = self.COMMIT_A['some/files/file3']['data']
other = self.COMMIT_A['some/other/file']['data'] other = self.COMMIT_A['some/other/file']['data']
self.assertEquals( self.assertEqual(
tree['files/file1'], tree['files/file1'],
('100644', 'blob', git_test_utils.git_hash_data(file1))) ('100644', 'blob', git_test_utils.git_hash_data(file1)))
self.assertEquals( self.assertEqual(
tree['files/file2'], tree['files/file2'],
('100755', 'blob', git_test_utils.git_hash_data(file2))) ('100755', 'blob', git_test_utils.git_hash_data(file2)))
self.assertEquals( self.assertEqual(
tree['files/file3'], tree['files/file3'],
('100644', 'blob', git_test_utils.git_hash_data(file3))) ('100644', 'blob', git_test_utils.git_hash_data(file3)))
self.assertEquals( self.assertEqual(
tree['other/file'], tree['other/file'],
('100644', 'blob', git_test_utils.git_hash_data(other))) ('100644', 'blob', git_test_utils.git_hash_data(other)))
@ -399,7 +399,7 @@ class GitMutableFunctionsTest(git_test_utils.GitRepoReadWriteTestBase,
REPO_SCHEMA = '' REPO_SCHEMA = ''
def _intern_data(self, data): def _intern_data(self, data):
with tempfile.TemporaryFile() as f: with tempfile.TemporaryFile('w') as f:
f.write(data) f.write(data)
f.seek(0) f.seek(0)
return self.repo.run(self.gc.intern_f, f) return self.repo.run(self.gc.intern_f, f)
@ -407,8 +407,8 @@ class GitMutableFunctionsTest(git_test_utils.GitRepoReadWriteTestBase,
def testInternF(self): def testInternF(self):
data = 'CoolBobcatsBro' data = 'CoolBobcatsBro'
data_hash = self._intern_data(data) data_hash = self._intern_data(data)
self.assertEquals(git_test_utils.git_hash_data(data), data_hash) self.assertEqual(git_test_utils.git_hash_data(data.encode()), data_hash)
self.assertEquals(data, self.repo.git('cat-file', 'blob', data_hash).stdout) self.assertEqual(data, self.repo.git('cat-file', 'blob', data_hash).stdout)
def testMkTree(self): def testMkTree(self):
tree = {} tree = {}
@ -416,46 +416,46 @@ class GitMutableFunctionsTest(git_test_utils.GitRepoReadWriteTestBase,
name = 'file%d' % i name = 'file%d' % i
tree[name] = ('100644', 'blob', self._intern_data(name)) tree[name] = ('100644', 'blob', self._intern_data(name))
tree_hash = self.repo.run(self.gc.mktree, tree) tree_hash = self.repo.run(self.gc.mktree, tree)
self.assertEquals('37b61866d6e061c4ba478e7eb525be7b5752737d', tree_hash) self.assertEqual('37b61866d6e061c4ba478e7eb525be7b5752737d', tree_hash)
def testConfig(self): def testConfig(self):
self.repo.git('config', '--add', 'happy.derpies', 'food') self.repo.git('config', '--add', 'happy.derpies', 'food')
self.assertEquals(self.repo.run(self.gc.get_config_list, 'happy.derpies'), self.assertEqual(self.repo.run(self.gc.get_config_list, 'happy.derpies'),
['food']) ['food'])
self.assertEquals(self.repo.run(self.gc.get_config_list, 'sad.derpies'), []) self.assertEqual(self.repo.run(self.gc.get_config_list, 'sad.derpies'), [])
self.repo.git('config', '--add', 'happy.derpies', 'cat') self.repo.git('config', '--add', 'happy.derpies', 'cat')
self.assertEquals(self.repo.run(self.gc.get_config_list, 'happy.derpies'), self.assertEqual(self.repo.run(self.gc.get_config_list, 'happy.derpies'),
['food', 'cat']) ['food', 'cat'])
self.assertEquals('cat', self.repo.run(self.gc.get_config, 'dude.bob', self.assertEqual(
'cat')) 'cat', self.repo.run(self.gc.get_config, 'dude.bob', 'cat'))
self.repo.run(self.gc.set_config, 'dude.bob', 'dog') self.repo.run(self.gc.set_config, 'dude.bob', 'dog')
self.assertEquals('dog', self.repo.run(self.gc.get_config, 'dude.bob', self.assertEqual(
'cat')) 'dog', self.repo.run(self.gc.get_config, 'dude.bob', 'cat'))
self.repo.run(self.gc.del_config, 'dude.bob') self.repo.run(self.gc.del_config, 'dude.bob')
# This should work without raising an exception # This should work without raising an exception
self.repo.run(self.gc.del_config, 'dude.bob') self.repo.run(self.gc.del_config, 'dude.bob')
self.assertEquals('cat', self.repo.run(self.gc.get_config, 'dude.bob', self.assertEqual(
'cat')) 'cat', self.repo.run(self.gc.get_config, 'dude.bob', 'cat'))
self.assertEquals('origin/master', self.repo.run(self.gc.root)) self.assertEqual('origin/master', self.repo.run(self.gc.root))
self.repo.git('config', 'depot-tools.upstream', 'catfood') self.repo.git('config', 'depot-tools.upstream', 'catfood')
self.assertEquals('catfood', self.repo.run(self.gc.root)) self.assertEqual('catfood', self.repo.run(self.gc.root))
def testUpstream(self): def testUpstream(self):
self.repo.git('commit', '--allow-empty', '-am', 'foooooo') self.repo.git('commit', '--allow-empty', '-am', 'foooooo')
self.assertEquals(self.repo.run(self.gc.upstream, 'bobly'), None) self.assertEqual(self.repo.run(self.gc.upstream, 'bobly'), None)
self.assertEquals(self.repo.run(self.gc.upstream, 'master'), None) self.assertEqual(self.repo.run(self.gc.upstream, 'master'), None)
self.repo.git('checkout', '-tb', 'happybranch', 'master') self.repo.git('checkout', '-tb', 'happybranch', 'master')
self.assertEquals(self.repo.run(self.gc.upstream, 'happybranch'), self.assertEqual(self.repo.run(self.gc.upstream, 'happybranch'),
'master') 'master')
def testNormalizedVersion(self): def testNormalizedVersion(self):
@ -505,7 +505,7 @@ class GitMutableFunctionsTest(git_test_utils.GitRepoReadWriteTestBase,
), ),
'to_delete': None 'to_delete': None
} }
self.assertEquals(expected, actual) self.assertEqual(expected, actual)
class GitMutableStructuredTest(git_test_utils.GitRepoReadWriteTestBase, class GitMutableStructuredTest(git_test_utils.GitRepoReadWriteTestBase,
@ -520,12 +520,12 @@ class GitMutableStructuredTest(git_test_utils.GitRepoReadWriteTestBase,
CAT DOG CAT DOG
""" """
COMMIT_B = {'file': {'data': 'B'}} COMMIT_B = {'file': {'data': b'B'}}
COMMIT_H = {'file': {'data': 'H'}} COMMIT_H = {'file': {'data': b'H'}}
COMMIT_I = {'file': {'data': 'I'}} COMMIT_I = {'file': {'data': b'I'}}
COMMIT_J = {'file': {'data': 'J'}} COMMIT_J = {'file': {'data': b'J'}}
COMMIT_K = {'file': {'data': 'K'}} COMMIT_K = {'file': {'data': b'K'}}
COMMIT_L = {'file': {'data': 'L'}} COMMIT_L = {'file': {'data': b'L'}}
def setUp(self): def setUp(self):
super(GitMutableStructuredTest, self).setUp() super(GitMutableStructuredTest, self).setUp()
@ -536,7 +536,7 @@ class GitMutableStructuredTest(git_test_utils.GitRepoReadWriteTestBase,
self.repo.git('branch', '--set-upstream-to', 'root_X', 'root_A') self.repo.git('branch', '--set-upstream-to', 'root_X', 'root_A')
def testTooManyBranches(self): def testTooManyBranches(self):
for i in xrange(30): for i in range(30):
self.repo.git('branch', 'a'*i) self.repo.git('branch', 'a'*i)
_, rslt = self.repo.capture_stdio(list, self.gc.branches()) _, rslt = self.repo.capture_stdio(list, self.gc.branches())
@ -597,8 +597,8 @@ class GitMutableStructuredTest(git_test_utils.GitRepoReadWriteTestBase,
self.repo.run(self.gc.remove_merge_base, 'branch_K') self.repo.run(self.gc.remove_merge_base, 'branch_K')
self.repo.run(self.gc.remove_merge_base, 'branch_L') self.repo.run(self.gc.remove_merge_base, 'branch_L')
self.assertEqual(None, self.repo.run(self.gc.get_config, self.assertEqual(
'branch.branch_K.base')) None, self.repo.run(self.gc.get_config, 'branch.branch_K.base'))
self.assertEqual({}, self.repo.run(self.gc.branch_config_map, 'base')) self.assertEqual({}, self.repo.run(self.gc.branch_config_map, 'base'))
@ -658,20 +658,20 @@ class GitMutableStructuredTest(git_test_utils.GitRepoReadWriteTestBase,
self.repo.capture_stdio( self.repo.capture_stdio(
lambda: retval.append(self.repo.run(self.gc.is_dirty_git_tree, 'foo'))) lambda: retval.append(self.repo.run(self.gc.is_dirty_git_tree, 'foo')))
self.assertEquals(False, retval[0]) self.assertEqual(False, retval[0])
self.repo.open('test.file', 'w').write('test data') self.repo.open('test.file', 'w').write('test data')
self.repo.git('add', 'test.file') self.repo.git('add', 'test.file')
retval = [] retval = []
self.repo.capture_stdio( self.repo.capture_stdio(
lambda: retval.append(self.repo.run(self.gc.is_dirty_git_tree, 'foo'))) lambda: retval.append(self.repo.run(self.gc.is_dirty_git_tree, 'foo')))
self.assertEquals(True, retval[0]) self.assertEqual(True, retval[0])
def testSquashBranch(self): def testSquashBranch(self):
self.repo.git('checkout', 'branch_K') self.repo.git('checkout', 'branch_K')
self.assertEquals(True, self.repo.run(self.gc.squash_current_branch, self.assertEqual(
'cool message')) True, self.repo.run(self.gc.squash_current_branch, 'cool message'))
lines = ['cool message', ''] lines = ['cool message', '']
for l in 'HIJK': for l in 'HIJK':
@ -679,18 +679,18 @@ class GitMutableStructuredTest(git_test_utils.GitRepoReadWriteTestBase,
lines.pop() lines.pop()
msg = '\n'.join(lines) msg = '\n'.join(lines)
self.assertEquals(self.repo.run(self.gc.run, 'log', '-n1', '--format=%B'), self.assertEqual(self.repo.run(self.gc.run, 'log', '-n1', '--format=%B'),
msg) msg)
self.assertEquals( self.assertEqual(
self.repo.git('cat-file', 'blob', 'branch_K:file').stdout, self.repo.git('cat-file', 'blob', 'branch_K:file').stdout,
'K' 'K'
) )
def testSquashBranchDefaultMessage(self): def testSquashBranchDefaultMessage(self):
self.repo.git('checkout', 'branch_K') self.repo.git('checkout', 'branch_K')
self.assertEquals(True, self.repo.run(self.gc.squash_current_branch)) self.assertEqual(True, self.repo.run(self.gc.squash_current_branch))
self.assertEquals(self.repo.run(self.gc.run, 'log', '-n1', '--format=%s'), self.assertEqual(self.repo.run(self.gc.run, 'log', '-n1', '--format=%s'),
'git squash commit for branch_K.') 'git squash commit for branch_K.')
def testSquashBranchEmpty(self): def testSquashBranchEmpty(self):
@ -699,7 +699,7 @@ class GitMutableStructuredTest(git_test_utils.GitRepoReadWriteTestBase,
self.repo.git('commit', '-m', 'revert all changes no branch') self.repo.git('commit', '-m', 'revert all changes no branch')
# Should return False since the quash would result in an empty commit # Should return False since the quash would result in an empty commit
stdout = self.repo.capture_stdio(self.gc.squash_current_branch)[0] stdout = self.repo.capture_stdio(self.gc.squash_current_branch)[0]
self.assertEquals(stdout, 'Nothing to commit; squashed branch is empty\n') self.assertEqual(stdout, 'Nothing to commit; squashed branch is empty\n')
def testRebase(self): def testRebase(self):
self.assertSchema(""" self.assertSchema("""
@ -782,24 +782,24 @@ class GitFreezeThaw(git_test_utils.GitRepoReadWriteTestBase):
""" """
COMMIT_A = { COMMIT_A = {
'some/files/file1': {'data': 'file1'}, 'some/files/file1': {'data': b'file1'},
'some/files/file2': {'data': 'file2'}, 'some/files/file2': {'data': b'file2'},
'some/files/file3': {'data': 'file3'}, 'some/files/file3': {'data': b'file3'},
'some/other/file': {'data': 'otherfile'}, 'some/other/file': {'data': b'otherfile'},
} }
COMMIT_C = { COMMIT_C = {
'some/files/file2': { 'some/files/file2': {
'mode': 0o755, 'mode': 0o755,
'data': 'file2 - vanilla'}, 'data': b'file2 - vanilla'},
} }
COMMIT_E = { COMMIT_E = {
'some/files/file2': {'data': 'file2 - merged'}, 'some/files/file2': {'data': b'file2 - merged'},
} }
COMMIT_D = { COMMIT_D = {
'some/files/file2': {'data': 'file2 - vanilla\nfile2 - merged'}, 'some/files/file2': {'data': b'file2 - vanilla\nfile2 - merged'},
} }
def testNothing(self): def testNothing(self):
@ -825,23 +825,23 @@ class GitFreezeThaw(git_test_utils.GitRepoReadWriteTestBase):
self.repo.git('add', 'some/files/file5') self.repo.git('add', 'some/files/file5')
# Freeze group 1 # Freeze group 1
self.assertEquals(self.repo.git('status', '--porcelain').stdout, STATUS_1) self.assertEqual(self.repo.git('status', '--porcelain').stdout, STATUS_1)
self.assertIsNone(self.gc.freeze()) self.assertIsNone(self.gc.freeze())
self.assertEquals(self.repo.git('status', '--porcelain').stdout, '') self.assertEqual(self.repo.git('status', '--porcelain').stdout, '')
# Freeze group 2 # Freeze group 2
with open('some/files/file2', 'a') as f2: with open('some/files/file2', 'a') as f2:
print('new! appended line!', file=f2) print('new! appended line!', file=f2)
self.assertEquals(self.repo.git('status', '--porcelain').stdout, self.assertEqual(self.repo.git('status', '--porcelain').stdout,
' M some/files/file2\n') ' M some/files/file2\n')
self.assertIsNone(self.gc.freeze()) self.assertIsNone(self.gc.freeze())
self.assertEquals(self.repo.git('status', '--porcelain').stdout, '') self.assertEqual(self.repo.git('status', '--porcelain').stdout, '')
# Thaw it out! # Thaw it out!
self.assertIsNone(self.gc.thaw()) self.assertIsNone(self.gc.thaw())
self.assertIsNotNone(self.gc.thaw()) # One thaw should thaw everything self.assertIsNotNone(self.gc.thaw()) # One thaw should thaw everything
self.assertEquals(self.repo.git('status', '--porcelain').stdout, STATUS_1) self.assertEqual(self.repo.git('status', '--porcelain').stdout, STATUS_1)
self.repo.run(inner) self.repo.run(inner)
@ -850,7 +850,7 @@ class GitFreezeThaw(git_test_utils.GitRepoReadWriteTestBase):
self.repo.git('config', 'depot-tools.freeze-size-limit', '1') self.repo.git('config', 'depot-tools.freeze-size-limit', '1')
with open('bigfile', 'w') as f: with open('bigfile', 'w') as f:
chunk = 'NERDFACE' * 1024 chunk = 'NERDFACE' * 1024
for _ in xrange(128 * 2 + 1): # Just over 2 mb for _ in range(128 * 2 + 1): # Just over 2 mb
f.write(chunk) f.write(chunk)
_, err = self.repo.capture_stdio(self.gc.freeze) _, err = self.repo.capture_stdio(self.gc.freeze)
self.assertIn('too much untracked+unignored', err) self.assertIn('too much untracked+unignored', err)
@ -860,10 +860,10 @@ class GitFreezeThaw(git_test_utils.GitRepoReadWriteTestBase):
def testTooBigMultipleFiles(self): def testTooBigMultipleFiles(self):
def inner(): def inner():
self.repo.git('config', 'depot-tools.freeze-size-limit', '1') self.repo.git('config', 'depot-tools.freeze-size-limit', '1')
for i in xrange(3): for i in range(3):
with open('file%d' % i, 'w') as f: with open('file%d' % i, 'w') as f:
chunk = 'NERDFACE' * 1024 chunk = 'NERDFACE' * 1024
for _ in xrange(50): # About 400k for _ in range(50): # About 400k
f.write(chunk) f.write(chunk)
_, err = self.repo.capture_stdio(self.gc.freeze) _, err = self.repo.capture_stdio(self.gc.freeze)
self.assertIn('too much untracked+unignored', err) self.assertIn('too much untracked+unignored', err)
@ -896,7 +896,7 @@ class GitFreezeThaw(git_test_utils.GitRepoReadWriteTestBase):
self.repo.git('checkout', '-b', 'unreadable_file_branch') self.repo.git('checkout', '-b', 'unreadable_file_branch')
with open('bad_file', 'w') as f: with open('bad_file', 'w') as f:
f.write('some text') f.write('some text')
os.chmod('bad_file', 0111) os.chmod('bad_file', 0o0111)
ret = self.repo.run(self.gc.freeze) ret = self.repo.run(self.gc.freeze)
self.assertIn('Failed to index some unindexed files.', ret) self.assertIn('Failed to index some unindexed files.', ret)
@ -935,11 +935,11 @@ class GitTestUtilsTest(git_test_utils.GitRepoReadOnlyTestBase):
""" """
COMMIT_A = { COMMIT_A = {
'file1': {'data': 'file1'}, 'file1': {'data': b'file1'},
} }
COMMIT_B = { COMMIT_B = {
'file1': {'data': 'file1 changed'}, 'file1': {'data': b'file1 changed'},
} }
# Test special keys (custom commit data). # Test special keys (custom commit data).
@ -952,7 +952,7 @@ class GitTestUtilsTest(git_test_utils.GitRepoReadOnlyTestBase):
GitRepo.COMMITTER_EMAIL: 'committer@example.com', GitRepo.COMMITTER_EMAIL: 'committer@example.com',
GitRepo.COMMITTER_DATE: datetime.datetime(1990, 4, 5, 6, 7, 8, GitRepo.COMMITTER_DATE: datetime.datetime(1990, 4, 5, 6, 7, 8,
tzinfo=git_test_utils.UTC), tzinfo=git_test_utils.UTC),
'file1': {'data': 'file1 changed again'}, 'file1': {'data': b'file1 changed again'},
} }
def testAutomaticCommitDates(self): def testAutomaticCommitDates(self):
@ -960,20 +960,20 @@ class GitTestUtilsTest(git_test_utils.GitRepoReadOnlyTestBase):
# must be in UTC (otherwise the tests are system-dependent, and if your # must be in UTC (otherwise the tests are system-dependent, and if your
# local timezone is positive, timestamps will be <0 which causes bizarre # local timezone is positive, timestamps will be <0 which causes bizarre
# behaviour in Git; http://crbug.com/581895). # behaviour in Git; http://crbug.com/581895).
self.assertEquals('Author McAuthorly 1970-01-01 00:00:00 +0000', self.assertEqual('Author McAuthorly 1970-01-01 00:00:00 +0000',
self.repo.show_commit('A', format_string='%an %ai')) self.repo.show_commit('A', format_string='%an %ai'))
self.assertEquals('Charles Committish 1970-01-02 00:00:00 +0000', self.assertEqual('Charles Committish 1970-01-02 00:00:00 +0000',
self.repo.show_commit('A', format_string='%cn %ci')) self.repo.show_commit('A', format_string='%cn %ci'))
self.assertEquals('Author McAuthorly 1970-01-03 00:00:00 +0000', self.assertEqual('Author McAuthorly 1970-01-03 00:00:00 +0000',
self.repo.show_commit('B', format_string='%an %ai')) self.repo.show_commit('B', format_string='%an %ai'))
self.assertEquals('Charles Committish 1970-01-04 00:00:00 +0000', self.assertEqual('Charles Committish 1970-01-04 00:00:00 +0000',
self.repo.show_commit('B', format_string='%cn %ci')) self.repo.show_commit('B', format_string='%cn %ci'))
def testCustomCommitData(self): def testCustomCommitData(self):
self.assertEquals('Custom Author author@example.com ' self.assertEqual('Custom Author author@example.com '
'1980-09-08 07:06:05 +0000', '1980-09-08 07:06:05 +0000',
self.repo.show_commit('C', format_string='%an %ae %ai')) self.repo.show_commit('C', format_string='%an %ae %ai'))
self.assertEquals('Custom Committer committer@example.com ' self.assertEqual('Custom Committer committer@example.com '
'1990-04-05 06:07:08 +0000', '1990-04-05 06:07:08 +0000',
self.repo.show_commit('C', format_string='%cn %ce %ci')) self.repo.show_commit('C', format_string='%cn %ce %ci'))

@ -4,15 +4,21 @@
# found in the LICENSE file. # found in the LICENSE file.
"""Tests for git_dates.""" """Tests for git_dates."""
from __future__ import unicode_literals
import datetime import datetime
import os import os
import re import re
import shutil import shutil
import StringIO
import sys import sys
import tempfile import tempfile
import unittest import unittest
if sys.version_info.major == 2:
from StringIO import StringIO
else:
from io import StringIO
DEPOT_TOOLS_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) DEPOT_TOOLS_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, DEPOT_TOOLS_ROOT) sys.path.insert(0, DEPOT_TOOLS_ROOT)
@ -32,8 +38,8 @@ class GitHyperBlameTestBase(git_test_utils.GitRepoReadOnlyTestBase):
cls.git_hyper_blame = git_hyper_blame cls.git_hyper_blame = git_hyper_blame
def run_hyperblame(self, ignored, filename, revision): def run_hyperblame(self, ignored, filename, revision):
stdout = StringIO.StringIO() stdout = StringIO()
stderr = StringIO.StringIO() stderr = StringIO()
ignored = [self.repo[c] for c in ignored] ignored = [self.repo[c] for c in ignored]
retval = self.repo.run(self.git_hyper_blame.hyper_blame, ignored, filename, retval = self.repo.run(self.git_hyper_blame.hyper_blame, ignored, filename,
revision=revision, out=stdout, err=stderr) revision=revision, out=stdout, err=stderr)
@ -61,22 +67,22 @@ class GitHyperBlameMainTest(GitHyperBlameTestBase):
REPO_SCHEMA = "A B C D" REPO_SCHEMA = "A B C D"
COMMIT_A = { COMMIT_A = {
'some/files/file': {'data': 'line 1\nline 2\n'}, 'some/files/file': {'data': b'line 1\nline 2\n'},
} }
COMMIT_B = { COMMIT_B = {
'some/files/file': {'data': 'line 1\nline 2.1\n'}, 'some/files/file': {'data': b'line 1\nline 2.1\n'},
} }
COMMIT_C = { COMMIT_C = {
'some/files/file': {'data': 'line 1.1\nline 2.1\n'}, 'some/files/file': {'data': b'line 1.1\nline 2.1\n'},
} }
COMMIT_D = { COMMIT_D = {
# This file should be automatically considered for ignore. # This file should be automatically considered for ignore.
'.git-blame-ignore-revs': {'data': 'tag_C'}, '.git-blame-ignore-revs': {'data': b'tag_C'},
# This file should not be considered. # This file should not be considered.
'some/files/.git-blame-ignore-revs': {'data': 'tag_B'}, 'some/files/.git-blame-ignore-revs': {'data': b'tag_B'},
} }
def setUp(self): def setUp(self):
@ -89,8 +95,8 @@ class GitHyperBlameMainTest(GitHyperBlameTestBase):
"""Tests the main function (simple end-to-end test with no ignores).""" """Tests the main function (simple end-to-end test with no ignores)."""
expected_output = [self.blame_line('C', '1) line 1.1'), expected_output = [self.blame_line('C', '1) line 1.1'),
self.blame_line('B', '2) line 2.1')] self.blame_line('B', '2) line 2.1')]
stdout = StringIO.StringIO() stdout = StringIO()
stderr = StringIO.StringIO() stderr = StringIO()
retval = self.repo.run(self.git_hyper_blame.main, retval = self.repo.run(self.git_hyper_blame.main,
args=['tag_C', 'some/files/file'], stdout=stdout, args=['tag_C', 'some/files/file'], stdout=stdout,
stderr=stderr) stderr=stderr)
@ -102,8 +108,8 @@ class GitHyperBlameMainTest(GitHyperBlameTestBase):
"""Tests the main function (simple end-to-end test with ignores).""" """Tests the main function (simple end-to-end test with ignores)."""
expected_output = [self.blame_line('C', ' 1) line 1.1'), expected_output = [self.blame_line('C', ' 1) line 1.1'),
self.blame_line('A', '2*) line 2.1')] self.blame_line('A', '2*) line 2.1')]
stdout = StringIO.StringIO() stdout = StringIO()
stderr = StringIO.StringIO() stderr = StringIO()
retval = self.repo.run(self.git_hyper_blame.main, retval = self.repo.run(self.git_hyper_blame.main,
args=['-i', 'tag_B', 'tag_C', 'some/files/file'], args=['-i', 'tag_B', 'tag_C', 'some/files/file'],
stdout=stdout, stderr=stderr) stdout=stdout, stderr=stderr)
@ -118,8 +124,8 @@ class GitHyperBlameMainTest(GitHyperBlameTestBase):
tempdir = tempfile.mkdtemp(suffix='_nogit', prefix='git_repo') tempdir = tempfile.mkdtemp(suffix='_nogit', prefix='git_repo')
try: try:
os.chdir(tempdir) os.chdir(tempdir)
stdout = StringIO.StringIO() stdout = StringIO()
stderr = StringIO.StringIO() stderr = StringIO()
retval = self.git_hyper_blame.main( retval = self.git_hyper_blame.main(
args=['-i', 'tag_B', 'tag_C', 'some/files/file'], stdout=stdout, args=['-i', 'tag_B', 'tag_C', 'some/files/file'], stdout=stdout,
stderr=stderr) stderr=stderr)
@ -134,8 +140,8 @@ class GitHyperBlameMainTest(GitHyperBlameTestBase):
def testBadFilename(self): def testBadFilename(self):
"""Tests the main function (bad filename).""" """Tests the main function (bad filename)."""
stdout = StringIO.StringIO() stdout = StringIO()
stderr = StringIO.StringIO() stderr = StringIO()
retval = self.repo.run(self.git_hyper_blame.main, retval = self.repo.run(self.git_hyper_blame.main,
args=['-i', 'tag_B', 'tag_C', 'some/files/xxxx'], args=['-i', 'tag_B', 'tag_C', 'some/files/xxxx'],
stdout=stdout, stderr=stderr) stdout=stdout, stderr=stderr)
@ -150,8 +156,8 @@ class GitHyperBlameMainTest(GitHyperBlameTestBase):
def testBadRevision(self): def testBadRevision(self):
"""Tests the main function (bad revision to blame from).""" """Tests the main function (bad revision to blame from)."""
stdout = StringIO.StringIO() stdout = StringIO()
stderr = StringIO.StringIO() stderr = StringIO()
retval = self.repo.run(self.git_hyper_blame.main, retval = self.repo.run(self.git_hyper_blame.main,
args=['-i', 'tag_B', 'xxxx', 'some/files/file'], args=['-i', 'tag_B', 'xxxx', 'some/files/file'],
stdout=stdout, stderr=stderr) stdout=stdout, stderr=stderr)
@ -165,8 +171,8 @@ class GitHyperBlameMainTest(GitHyperBlameTestBase):
"""Tests the main function (bad revision passed to -i).""" """Tests the main function (bad revision passed to -i)."""
expected_output = [self.blame_line('C', '1) line 1.1'), expected_output = [self.blame_line('C', '1) line 1.1'),
self.blame_line('B', '2) line 2.1')] self.blame_line('B', '2) line 2.1')]
stdout = StringIO.StringIO() stdout = StringIO()
stderr = StringIO.StringIO() stderr = StringIO()
retval = self.repo.run(self.git_hyper_blame.main, retval = self.repo.run(self.git_hyper_blame.main,
args=['-i', 'xxxx', 'tag_C', 'some/files/file'], args=['-i', 'xxxx', 'tag_C', 'some/files/file'],
stdout=stdout, stderr=stderr) stdout=stdout, stderr=stderr)
@ -178,8 +184,8 @@ class GitHyperBlameMainTest(GitHyperBlameTestBase):
"""Tests passing the ignore list in a file.""" """Tests passing the ignore list in a file."""
expected_output = [self.blame_line('C', ' 1) line 1.1'), expected_output = [self.blame_line('C', ' 1) line 1.1'),
self.blame_line('A', '2*) line 2.1')] self.blame_line('A', '2*) line 2.1')]
stdout = StringIO.StringIO() stdout = StringIO()
stderr = StringIO.StringIO() stderr = StringIO()
with tempfile.NamedTemporaryFile(mode='w+', prefix='ignore') as ignore_file: with tempfile.NamedTemporaryFile(mode='w+', prefix='ignore') as ignore_file:
ignore_file.write('# Line comments are allowed.\n') ignore_file.write('# Line comments are allowed.\n')
@ -205,8 +211,8 @@ class GitHyperBlameMainTest(GitHyperBlameTestBase):
expected_output = [self.blame_line('A', '1*) line 1.1'), expected_output = [self.blame_line('A', '1*) line 1.1'),
self.blame_line('B', ' 2) line 2.1')] self.blame_line('B', ' 2) line 2.1')]
stdout = StringIO.StringIO() stdout = StringIO()
stderr = StringIO.StringIO() stderr = StringIO()
retval = self.repo.run(self.git_hyper_blame.main, retval = self.repo.run(self.git_hyper_blame.main,
args=['tag_D', 'some/files/file'], args=['tag_D', 'some/files/file'],
@ -219,8 +225,8 @@ class GitHyperBlameMainTest(GitHyperBlameTestBase):
# Test blame from a different revision. Despite the default ignore file # Test blame from a different revision. Despite the default ignore file
# *not* being committed at that revision, it should still be picked up # *not* being committed at that revision, it should still be picked up
# because D is currently checked out. # because D is currently checked out.
stdout = StringIO.StringIO() stdout = StringIO()
stderr = StringIO.StringIO() stderr = StringIO()
retval = self.repo.run(self.git_hyper_blame.main, retval = self.repo.run(self.git_hyper_blame.main,
args=['tag_C', 'some/files/file'], args=['tag_C', 'some/files/file'],
@ -238,8 +244,8 @@ class GitHyperBlameMainTest(GitHyperBlameTestBase):
expected_output = [self.blame_line('C', '1) line 1.1'), expected_output = [self.blame_line('C', '1) line 1.1'),
self.blame_line('B', '2) line 2.1')] self.blame_line('B', '2) line 2.1')]
stdout = StringIO.StringIO() stdout = StringIO()
stderr = StringIO.StringIO() stderr = StringIO()
retval = self.repo.run( retval = self.repo.run(
self.git_hyper_blame.main, self.git_hyper_blame.main,
@ -257,44 +263,44 @@ class GitHyperBlameSimpleTest(GitHyperBlameTestBase):
""" """
COMMIT_A = { COMMIT_A = {
'some/files/file1': {'data': 'file1'}, 'some/files/file1': {'data': b'file1'},
'some/files/file2': {'data': 'file2'}, 'some/files/file2': {'data': b'file2'},
'some/files/empty': {'data': ''}, 'some/files/empty': {'data': b''},
'some/other/file': {'data': 'otherfile'}, 'some/other/file': {'data': b'otherfile'},
} }
COMMIT_B = { COMMIT_B = {
'some/files/file2': { 'some/files/file2': {
'mode': 0o755, 'mode': 0o755,
'data': 'file2 - vanilla\n'}, 'data': b'file2 - vanilla\n'},
'some/files/empty': {'data': 'not anymore'}, 'some/files/empty': {'data': b'not anymore'},
'some/files/file3': {'data': 'file3'}, 'some/files/file3': {'data': b'file3'},
} }
COMMIT_C = { COMMIT_C = {
'some/files/file2': {'data': 'file2 - merged\n'}, 'some/files/file2': {'data': b'file2 - merged\n'},
} }
COMMIT_D = { COMMIT_D = {
'some/files/file2': {'data': 'file2 - vanilla\nfile2 - merged\n'}, 'some/files/file2': {'data': b'file2 - vanilla\nfile2 - merged\n'},
} }
COMMIT_E = { COMMIT_E = {
'some/files/file2': {'data': 'file2 - vanilla\nfile_x - merged\n'}, 'some/files/file2': {'data': b'file2 - vanilla\nfile_x - merged\n'},
} }
COMMIT_F = { COMMIT_F = {
'some/files/file2': {'data': 'file2 - vanilla\nfile_y - merged\n'}, 'some/files/file2': {'data': b'file2 - vanilla\nfile_y - merged\n'},
} }
# Move file2 from files to other. # Move file2 from files to other.
COMMIT_G = { COMMIT_G = {
'some/files/file2': {'data': None}, 'some/files/file2': {'data': None},
'some/other/file2': {'data': 'file2 - vanilla\nfile_y - merged\n'}, 'some/other/file2': {'data': b'file2 - vanilla\nfile_y - merged\n'},
} }
COMMIT_H = { COMMIT_H = {
'some/other/file2': {'data': 'file2 - vanilla\nfile_z - merged\n'}, 'some/other/file2': {'data': b'file2 - vanilla\nfile_z - merged\n'},
} }
def testBlameError(self): def testBlameError(self):
@ -387,34 +393,34 @@ class GitHyperBlameLineMotionTest(GitHyperBlameTestBase):
""" """
COMMIT_A = { COMMIT_A = {
'file': {'data': 'A\ngreen\nblue\n'}, 'file': {'data': b'A\ngreen\nblue\n'},
} }
# Change "green" to "yellow". # Change "green" to "yellow".
COMMIT_B = { COMMIT_B = {
'file': {'data': 'A\nyellow\nblue\n'}, 'file': {'data': b'A\nyellow\nblue\n'},
} }
# Insert 2 lines at the top, # Insert 2 lines at the top,
# Change "yellow" to "red". # Change "yellow" to "red".
# Insert 1 line at the bottom. # Insert 1 line at the bottom.
COMMIT_C = { COMMIT_C = {
'file': {'data': 'X\nY\nA\nred\nblue\nZ\n'}, 'file': {'data': b'X\nY\nA\nred\nblue\nZ\n'},
} }
# Insert 2 more lines at the top. # Insert 2 more lines at the top.
COMMIT_D = { COMMIT_D = {
'file': {'data': 'earth\nfire\nX\nY\nA\nred\nblue\nZ\n'}, 'file': {'data': b'earth\nfire\nX\nY\nA\nred\nblue\nZ\n'},
} }
# Insert a line before "red", and indent "red" and "blue". # Insert a line before "red", and indent "red" and "blue".
COMMIT_E = { COMMIT_E = {
'file': {'data': 'earth\nfire\nX\nY\nA\ncolors:\n red\n blue\nZ\n'}, 'file': {'data': b'earth\nfire\nX\nY\nA\ncolors:\n red\n blue\nZ\n'},
} }
# Insert a line between "A" and "colors". # Insert a line between "A" and "colors".
COMMIT_F = { COMMIT_F = {
'file': {'data': 'earth\nfire\nX\nY\nA\nB\ncolors:\n red\n blue\nZ\n'}, 'file': {'data': b'earth\nfire\nX\nY\nA\nB\ncolors:\n red\n blue\nZ\n'},
} }
def testCacheDiffHunks(self): def testCacheDiffHunks(self):
@ -537,22 +543,22 @@ class GitHyperBlameLineNumberTest(GitHyperBlameTestBase):
""" """
COMMIT_A = { COMMIT_A = {
'file': {'data': 'red\nblue\n'}, 'file': {'data': b'red\nblue\n'},
} }
# Change "blue" to "green". # Change "blue" to "green".
COMMIT_B = { COMMIT_B = {
'file': {'data': 'red\ngreen\n'}, 'file': {'data': b'red\ngreen\n'},
} }
# Insert 2 lines at the top, # Insert 2 lines at the top,
COMMIT_C = { COMMIT_C = {
'file': {'data': '\n\nred\ngreen\n'}, 'file': {'data': b'\n\nred\ngreen\n'},
} }
# Change "green" to "yellow". # Change "green" to "yellow".
COMMIT_D = { COMMIT_D = {
'file': {'data': '\n\nred\nyellow\n'}, 'file': {'data': b'\n\nred\nyellow\n'},
} }
def testTwoChangesWithAddedLines(self): def testTwoChangesWithAddedLines(self):
@ -584,19 +590,19 @@ class GitHyperBlameUnicodeTest(GitHyperBlameTestBase):
COMMIT_A = { COMMIT_A = {
GitRepo.AUTHOR_NAME: 'ASCII Author', GitRepo.AUTHOR_NAME: 'ASCII Author',
'file': {'data': 'red\nblue\n'}, 'file': {'data': b'red\nblue\n'},
} }
# Add a line. # Add a line.
COMMIT_B = { COMMIT_B = {
GitRepo.AUTHOR_NAME: u'\u4e2d\u56fd\u4f5c\u8005'.encode('utf-8'), GitRepo.AUTHOR_NAME: '\u4e2d\u56fd\u4f5c\u8005'.encode('utf-8'),
'file': {'data': 'red\ngreen\nblue\n'}, 'file': {'data': b'red\ngreen\nblue\n'},
} }
# Modify a line with non-UTF-8 author and file text. # Modify a line with non-UTF-8 author and file text.
COMMIT_C = { COMMIT_C = {
GitRepo.AUTHOR_NAME: u'Lat\u00edn-1 Author'.encode('latin-1'), GitRepo.AUTHOR_NAME: 'Lat\u00edn-1 Author'.encode('latin-1'),
'file': {'data': u'red\ngre\u00e9n\nblue\n'.encode('latin-1')}, 'file': {'data': 'red\ngre\u00e9n\nblue\n'.encode('latin-1')},
} }
def testNonASCIIAuthorName(self): def testNonASCIIAuthorName(self):
@ -610,8 +616,8 @@ class GitHyperBlameUnicodeTest(GitHyperBlameTestBase):
expected_output = [ expected_output = [
self.blame_line('A', '1) red', author='ASCII Author'), self.blame_line('A', '1) red', author='ASCII Author'),
# Expect 8 spaces, to line up with the other name. # Expect 8 spaces, to line up with the other name.
self.blame_line('B', '2) green', self.blame_line(
author=u'\u4e2d\u56fd\u4f5c\u8005 '.encode('utf-8')), 'B', '2) green', author='\u4e2d\u56fd\u4f5c\u8005 '),
self.blame_line('A', '3) blue', author='ASCII Author'), self.blame_line('A', '3) blue', author='ASCII Author'),
] ]
retval, output = self.run_hyperblame([], 'file', 'tag_B') retval, output = self.run_hyperblame([], 'file', 'tag_B')
@ -626,9 +632,9 @@ class GitHyperBlameUnicodeTest(GitHyperBlameTestBase):
""" """
expected_output = [ expected_output = [
self.blame_line('A', '1) red', author='ASCII Author '), self.blame_line('A', '1) red', author='ASCII Author '),
# The Author has been re-encoded as UTF-8. The file data is preserved as # The Author has been re-encoded as UTF-8. The file data is converted to
# raw byte data. # UTF8 and unknown characters replaced.
self.blame_line('C', '2) gre\xe9n', author='Lat\xc3\xadn-1 Author'), self.blame_line('C', '2) gre\ufffdn', author='Lat\xedn-1 Author'),
self.blame_line('A', '3) blue', author='ASCII Author '), self.blame_line('A', '3) blue', author='ASCII Author '),
] ]
retval, output = self.run_hyperblame([], 'file', 'tag_C') retval, output = self.run_hyperblame([], 'file', 'tag_C')

Loading…
Cancel
Save