def test_read_text_file_unicode_decode_error(self): fs = FileSystem() text_path = None try: text_path = tempfile.mktemp(prefix='write_text_unittest_') fs.write_binary_file(text_path, bytearray(b'\x73\x74\x72\x8b')) self.assertRaises(UnicodeDecodeError, fs.read_text_file, text_path) self.assertEqual(u'str\ufffd', fs.read_text_file(text_path, errors='replace')) self.assertEqual('str', fs.read_text_file(text_path, errors='ignore')) finally: if text_path and fs.isfile(text_path): os.remove(text_path)
def test_read_and_write_file(self): fs = FileSystem() text_path = None binary_path = None unicode_text_string = u'\u016An\u012Dc\u014Dde\u033D' hex_equivalent = '\xC5\xAA\x6E\xC4\xAD\x63\xC5\x8D\x64\x65\xCC\xBD' try: text_path = tempfile.mktemp(prefix='tree_unittest_') binary_path = tempfile.mktemp(prefix='tree_unittest_') fs.write_text_file(text_path, unicode_text_string) contents = fs.read_binary_file(text_path) self.assertEqual(contents, hex_equivalent) fs.write_binary_file(binary_path, hex_equivalent) text_contents = fs.read_text_file(binary_path) self.assertEqual(text_contents, unicode_text_string) finally: if text_path and fs.isfile(text_path): os.remove(text_path) if binary_path and fs.isfile(binary_path): os.remove(binary_path)
def test_read_and_write_file(self): fs = FileSystem() text_path = None binary_path = None unicode_text_string = u'\u016An\u012Dc\u014Dde\u033D' hex_equivalent = b'\xC5\xAA\x6E\xC4\xAD\x63\xC5\x8D\x64\x65\xCC\xBD' malformed_text_hex = b'\x4D\x69\x63\x72\x6F\x73\x6F\x66\x74\xAE\x20\x56\x69\x73\x75\x61\x6C\x20\x53\x74\x75\x64\x69\x6F\xAE\x20\x32\x30\x31\x30\x0D\x0A' malformed_ignored_text_hex = b'\x4D\x69\x63\x72\x6F\x73\x6F\x66\x74\x20\x56\x69\x73\x75\x61\x6C\x20\x53\x74\x75\x64\x69\x6F\x20\x32\x30\x31\x30\x0D\x0A' try: text_path = tempfile.mktemp(prefix='tree_unittest_') binary_path = tempfile.mktemp(prefix='tree_unittest_') fs.write_text_file(text_path, unicode_text_string) contents = fs.read_binary_file(text_path) self.assertEqual(contents, hex_equivalent) fs.write_binary_file(binary_path, hex_equivalent) text_contents = fs.read_text_file(binary_path) self.assertEqual(text_contents, unicode_text_string) self.assertRaises(ValueError, fs.write_text_file, binary_path, malformed_text_hex) fs.write_binary_file(binary_path, malformed_text_hex) self.assertRaises(ValueError, fs.read_text_file, binary_path) text_contents = fs.read_binary_file(binary_path).decode( 'utf8', 'ignore') self.assertEqual( text_contents, malformed_ignored_text_hex.decode('utf8', 'ignore')) with fs.open_text_file_for_reading(binary_path, 'replace') as file: file.readline() finally: if text_path and fs.isfile(text_path): os.remove(text_path) if binary_path and fs.isfile(binary_path): os.remove(binary_path)
class SCMTestBase(unittest.TestCase): def __init__(self, *args, **kwargs): super(SCMTestBase, self).__init__(*args, **kwargs) self.scm = None self.executive = None self.fs = None self.original_cwd = None def setUp(self): self.executive = Executive() self.fs = FileSystem() self.original_cwd = self.fs.getcwd() def tearDown(self): self._chdir(self.original_cwd) def _join(self, *comps): return self.fs.join(*comps) def _chdir(self, path): self.fs.chdir(path) def _mkdir(self, path): assert not self.fs.exists(path) self.fs.maybe_make_directory(path) def _mkdtemp(self, **kwargs): return str(self.fs.mkdtemp(**kwargs)) def _remove(self, path): self.fs.remove(path) def _rmtree(self, path): self.fs.rmtree(path) def _run(self, *args, **kwargs): return self.executive.run_command(*args, **kwargs) def _run_silent(self, args, **kwargs): self.executive.run_and_throw_if_fail(args, quiet=True, **kwargs) def _write_text_file(self, path, contents): self.fs.write_text_file(path, contents) def _write_binary_file(self, path, contents): self.fs.write_binary_file(path, contents) def _make_diff(self, command, *args): # We use this wrapper to disable output decoding. diffs should be treated as # binary files since they may include text files of multiple differnet encodings. return self._run([command, "diff"] + list(args), decode_output=False) def _svn_diff(self, *args): return self._make_diff("svn", *args) def _git_diff(self, *args): return self._make_diff("git", *args) def _svn_add(self, path): self._run(["svn", "add", path]) def _svn_commit(self, message): self._run(["svn", "commit", "--quiet", "--message", message]) # This is a hot function since it's invoked by unittest before calling each test_ method in SVNTest and # GitTest. We create a mock SVN repo once and then perform an SVN checkout from a filesystem copy of # it since it's expensive to create the mock repo. def _set_up_svn_checkout(self): global cached_svn_repo_path global original_cwd if not cached_svn_repo_path: cached_svn_repo_path = self._set_up_svn_repo() original_cwd = self.original_cwd self.temp_directory = self._mkdtemp(suffix="svn_test") self.svn_repo_path = self._join(self.temp_directory, "repo") self.svn_repo_url = "file://%s" % self.svn_repo_path self.svn_checkout_path = self._join(self.temp_directory, "checkout") shutil.copytree(cached_svn_repo_path, self.svn_repo_path) self._run(["svn", "checkout", "--quiet", self.svn_repo_url + "/trunk", self.svn_checkout_path]) def _set_up_svn_repo(self): svn_repo_path = self._mkdtemp(suffix="svn_test_repo") svn_repo_url = "file://%s" % svn_repo_path # Not sure this will work on windows # git svn complains if we don't pass --pre-1.5-compatible, not sure why: # Expected FS format '2'; found format '3' at /usr/local/libexec/git-core//git-svn line 1477 self._run(["svnadmin", "create", "--pre-1.5-compatible", svn_repo_path]) # Create a test svn checkout svn_checkout_path = self._mkdtemp(suffix="svn_test_checkout") self._run(["svn", "checkout", "--quiet", svn_repo_url, svn_checkout_path]) # Create and checkout a trunk dir to match the standard svn configuration to match git-svn's expectations self._chdir(svn_checkout_path) self._mkdir("trunk") self._svn_add("trunk") # We can add tags and branches as well if we ever need to test those. self._svn_commit("add trunk") self._rmtree(svn_checkout_path) self._set_up_svn_test_commits(svn_repo_url + "/trunk") return svn_repo_path def _set_up_svn_test_commits(self, svn_repo_url): svn_checkout_path = self._mkdtemp(suffix="svn_test_checkout") self._run(["svn", "checkout", "--quiet", svn_repo_url, svn_checkout_path]) # Add some test commits self._chdir(svn_checkout_path) self._write_text_file("test_file", "test1") self._svn_add("test_file") self._svn_commit("initial commit") self._write_text_file("test_file", "test1test2") # This used to be the last commit, but doing so broke # GitTest.test_apply_git_patch which use the inverse diff of the last commit. # svn-apply fails to remove directories in Git, see: # https://bugs.webkit.org/show_bug.cgi?id=34871 self._mkdir("test_dir") # Slash should always be the right path separator since we use cygwin on Windows. test_file3_path = "test_dir/test_file3" self._write_text_file(test_file3_path, "third file") self._svn_add("test_dir") self._svn_commit("second commit") self._write_text_file("test_file", "test1test2test3\n") self._write_text_file("test_file2", "second file") self._svn_add("test_file2") self._svn_commit("third commit") # This 4th commit is used to make sure that our patch file handling # code correctly treats patches as binary and does not attempt to # decode them assuming they're utf-8. self._write_binary_file("test_file", u"latin1 test: \u00A0\n".encode("latin-1")) self._write_binary_file("test_file2", u"utf-8 test: \u00A0\n".encode("utf-8")) self._svn_commit("fourth commit") # svn does not seem to update after commit as I would expect. self._run(["svn", "update"]) self._rmtree(svn_checkout_path) def _tear_down_svn_checkout(self): self._rmtree(self.temp_directory) def _shared_test_add_recursively(self): self._mkdir("added_dir") self._write_text_file("added_dir/added_file", "new stuff") self.scm.add("added_dir/added_file") self.assertIn("added_dir/added_file", self.scm._added_files()) def _shared_test_delete_recursively(self): self._mkdir("added_dir") self._write_text_file("added_dir/added_file", "new stuff") self.scm.add("added_dir/added_file") self.assertIn("added_dir/added_file", self.scm._added_files()) self.scm.delete("added_dir/added_file") self.assertNotIn("added_dir", self.scm._added_files()) def _shared_test_delete_recursively_or_not(self): self._mkdir("added_dir") self._write_text_file("added_dir/added_file", "new stuff") self._write_text_file("added_dir/another_added_file", "more new stuff") self.scm.add("added_dir/added_file") self.scm.add("added_dir/another_added_file") self.assertIn("added_dir/added_file", self.scm._added_files()) self.assertIn("added_dir/another_added_file", self.scm._added_files()) self.scm.delete("added_dir/added_file") self.assertIn("added_dir/another_added_file", self.scm._added_files()) def _shared_test_exists(self, scm, commit_function): self._chdir(scm.checkout_root) self.assertFalse(scm.exists("foo.txt")) self._write_text_file("foo.txt", "some stuff") self.assertFalse(scm.exists("foo.txt")) scm.add("foo.txt") commit_function("adding foo") self.assertTrue(scm.exists("foo.txt")) scm.delete("foo.txt") commit_function("deleting foo") self.assertFalse(scm.exists("foo.txt")) def _shared_test_move(self): self._write_text_file("added_file", "new stuff") self.scm.add("added_file") self.scm.move("added_file", "moved_file") self.assertIn("moved_file", self.scm._added_files()) def _shared_test_move_recursive(self): self._mkdir("added_dir") self._write_text_file("added_dir/added_file", "new stuff") self._write_text_file("added_dir/another_added_file", "more new stuff") self.scm.add("added_dir") self.scm.move("added_dir", "moved_dir") self.assertIn("moved_dir/added_file", self.scm._added_files()) self.assertIn("moved_dir/another_added_file", self.scm._added_files())
class TextFileReaderTest(LoggingTestCase): class MockProcessor(ProcessorBase): """A processor for test purposes. This processor simply records the parameters passed to its process() method for later checking by the unittest test methods. """ def __init__(self): self.processed = [] """The parameters passed for all calls to the process() method.""" def should_process(self, file_path): return not file_path.endswith('should_not_process.txt') def process(self, lines, file_path, test_kwarg=None): self.processed.append((lines, file_path, test_kwarg)) def setUp(self): LoggingTestCase.setUp(self) # FIXME: This should be a MockFileSystem once TextFileReader is moved entirely on top of FileSystem. self.filesystem = FileSystem() self._temp_dir = str(self.filesystem.mkdtemp()) self._processor = TextFileReaderTest.MockProcessor() self._file_reader = TextFileReader(self.filesystem, self._processor) def tearDown(self): LoggingTestCase.tearDown(self) self.filesystem.rmtree(self._temp_dir) def _create_file(self, rel_path, text): """Create a file with given text and return the path to the file.""" # FIXME: There are better/more secure APIs for creating tmp file paths. file_path = self.filesystem.join(self._temp_dir, rel_path) self.filesystem.write_text_file(file_path, text) return file_path def _passed_to_processor(self): """Return the parameters passed to MockProcessor.process().""" return self._processor.processed def _assert_file_reader(self, passed_to_processor, file_count): """Assert the state of the file reader.""" self.assertEqual(passed_to_processor, self._passed_to_processor()) self.assertEqual(file_count, self._file_reader.file_count) def test_process_file__does_not_exist(self): try: self._file_reader.process_file('does_not_exist.txt') except IOError as err: self.assertEqual(str(err), "File does not exist") else: self.fail('No Exception raised.') self._assert_file_reader([], 1) self.assertLog(["ERROR: File does not exist: 'does_not_exist.txt'\n"]) def test_process_file__is_dir(self): temp_dir = self.filesystem.join(self._temp_dir, 'test_dir') self.filesystem.maybe_make_directory(temp_dir) self._file_reader.process_file(temp_dir) # Because the log message below contains exception text, it is # possible that the text varies across platforms. For this reason, # we check only the portion of the log message that we control, # namely the text at the beginning. log_messages = self.logMessages() # We remove the message we are looking at to prevent the tearDown() # from raising an exception when it asserts that no log messages # remain. message = log_messages.pop() self.assertTrue(message.startswith("WARNING: Could not read file. Skipping: '%s'\n " % temp_dir)) self._assert_file_reader([], 1) def test_process_file__should_not_process(self): file_path = self._create_file('should_not_process.txt', 'contents') self._file_reader.process_file(file_path) self._assert_file_reader([], 1) def test_process_file__multiple_lines(self): file_path = self._create_file('foo.txt', 'line one\r\nline two\n') self._file_reader.process_file(file_path) processed = [(['line one\r', 'line two', ''], file_path, None)] self._assert_file_reader(processed, 1) def test_process_file__file_stdin(self): file_path = self._create_file('-', 'file contents') self._file_reader.process_file(file_path=file_path, test_kwarg='foo') processed = [(['file contents'], file_path, 'foo')] self._assert_file_reader(processed, 1) def test_process_file__with_kwarg(self): file_path = self._create_file('foo.txt', 'file contents') self._file_reader.process_file(file_path=file_path, test_kwarg='foo') processed = [(['file contents'], file_path, 'foo')] self._assert_file_reader(processed, 1) def test_process_paths(self): # We test a list of paths that contains both a file and a directory. dir = self.filesystem.join(self._temp_dir, 'foo_dir') self.filesystem.maybe_make_directory(dir) file_path1 = self._create_file('file1.txt', 'foo') rel_path = self.filesystem.join('foo_dir', 'file2.txt') file_path2 = self._create_file(rel_path, 'bar') self._file_reader.process_paths([dir, file_path1]) processed = [(['bar'], file_path2, None), (['foo'], file_path1, None)] self._assert_file_reader(processed, 2) def test_delete_file(self): self._file_reader.delete_file() delete_only_file_count = self._file_reader.delete_only_file_count self.assertEqual(delete_only_file_count, 1) def test_process_malformed_file(self): file_path = tempfile.mktemp(prefix='filereader_unittest_') self.filesystem.write_binary_file(file_path, '\x4D\x69\x63\x72\x6F\x73\x6F\x66\x74\xAE') self._file_reader.process_file(file_path)
class GitTestWithRealFilesystemAndExecutive(unittest.TestCase): def setUp(self): self.executive = Executive() self.filesystem = FileSystem() self.original_cwd = self.filesystem.getcwd() # Set up fresh git repository with one commit. self.untracking_checkout_path = self._mkdtemp( suffix='-git_unittest_untracking') self._run(['git', 'init', self.untracking_checkout_path]) self._chdir(self.untracking_checkout_path) self._write_text_file('foo_file', 'foo') self._run(['git', 'add', 'foo_file']) self._run(['git', 'commit', '-am', 'dummy commit']) self.untracking_scm = Git(cwd=self.untracking_checkout_path, filesystem=self.filesystem, executive=self.executive) # Then set up a second git repo that tracks the first one. self.tracking_git_checkout_path = self._mkdtemp( suffix='-git_unittest_tracking') self._run([ 'git', 'clone', '--quiet', self.untracking_checkout_path, self.tracking_git_checkout_path ]) self._chdir(self.tracking_git_checkout_path) self.tracking_scm = Git(cwd=self.tracking_git_checkout_path, filesystem=self.filesystem, executive=self.executive) def tearDown(self): self._chdir(self.original_cwd) self._run(['rm', '-rf', self.tracking_git_checkout_path]) self._run(['rm', '-rf', self.untracking_checkout_path]) def _join(self, *comps): return self.filesystem.join(*comps) def _chdir(self, path): self.filesystem.chdir(path) def _mkdir(self, path): assert not self.filesystem.exists(path) self.filesystem.maybe_make_directory(path) def _mkdtemp(self, **kwargs): return str(self.filesystem.mkdtemp(**kwargs)) def _remove(self, path): self.filesystem.remove(path) def _run(self, *args, **kwargs): return self.executive.run_command(*args, **kwargs) def _run_silent(self, args, **kwargs): self.executive.run_command(args, **kwargs) def _write_text_file(self, path, contents): self.filesystem.write_text_file(path, contents) def _write_binary_file(self, path, contents): self.filesystem.write_binary_file(path, contents) def _make_diff(self, command, *args): # We use this wrapper to disable output decoding. diffs should be treated as # binary files since they may include text files of multiple different encodings. return self._run([command, 'diff'] + list(args), decode_output=False) def _git_diff(self, *args): return self._make_diff('git', *args) def test_add_list(self): self._chdir(self.untracking_checkout_path) git = self.untracking_scm self._mkdir('added_dir') self._write_text_file('added_dir/added_file', 'new stuff') print self._run(['ls', 'added_dir']) print self._run(['pwd']) print self._run(['cat', 'added_dir/added_file']) git.add_list(['added_dir/added_file']) self.assertIn('added_dir/added_file', git.added_files()) def test_delete_recursively(self): self._chdir(self.untracking_checkout_path) git = self.untracking_scm self._mkdir('added_dir') self._write_text_file('added_dir/added_file', 'new stuff') git.add_list(['added_dir/added_file']) self.assertIn('added_dir/added_file', git.added_files()) git.delete_list(['added_dir/added_file']) self.assertNotIn('added_dir', git.added_files()) def test_delete_recursively_or_not(self): self._chdir(self.untracking_checkout_path) git = self.untracking_scm self._mkdir('added_dir') self._write_text_file('added_dir/added_file', 'new stuff') self._write_text_file('added_dir/another_added_file', 'more new stuff') git.add_list(['added_dir/added_file', 'added_dir/another_added_file']) self.assertIn('added_dir/added_file', git.added_files()) self.assertIn('added_dir/another_added_file', git.added_files()) git.delete_list(['added_dir/added_file']) self.assertIn('added_dir/another_added_file', git.added_files()) def test_exists(self): self._chdir(self.untracking_checkout_path) git = self.untracking_scm self._chdir(git.checkout_root) self.assertFalse(git.exists('foo.txt')) self._write_text_file('foo.txt', 'some stuff') self.assertFalse(git.exists('foo.txt')) git.add_list(['foo.txt']) git.commit_locally_with_message('adding foo') self.assertTrue(git.exists('foo.txt')) git.delete_list(['foo.txt']) git.commit_locally_with_message('deleting foo') self.assertFalse(git.exists('foo.txt')) def test_move(self): self._chdir(self.untracking_checkout_path) git = self.untracking_scm self._write_text_file('added_file', 'new stuff') git.add_list(['added_file']) git.move('added_file', 'moved_file') self.assertIn('moved_file', git.added_files()) def test_move_recursive(self): self._chdir(self.untracking_checkout_path) git = self.untracking_scm self._mkdir('added_dir') self._write_text_file('added_dir/added_file', 'new stuff') self._write_text_file('added_dir/another_added_file', 'more new stuff') git.add_list(['added_dir']) git.move('added_dir', 'moved_dir') self.assertIn('moved_dir/added_file', git.added_files()) self.assertIn('moved_dir/another_added_file', git.added_files()) def test_remote_branch_ref(self): # This tests a protected method. pylint: disable=protected-access self.assertEqual(self.tracking_scm._remote_branch_ref(), 'refs/remotes/origin/master') self._chdir(self.untracking_checkout_path) self.assertRaises(ScriptError, self.untracking_scm._remote_branch_ref) def test_create_patch(self): self._chdir(self.tracking_git_checkout_path) git = self.tracking_scm self._write_text_file('test_file_commit1', 'contents') self._run(['git', 'add', 'test_file_commit1']) git.commit_locally_with_message('message') git._patch_order = lambda: '' # pylint: disable=protected-access patch = git.create_patch() self.assertNotRegexpMatches(patch, r'Subversion Revision:') def test_patches_have_filenames_with_prefixes(self): self._chdir(self.tracking_git_checkout_path) git = self.tracking_scm self._write_text_file('test_file_commit1', 'contents') self._run(['git', 'add', 'test_file_commit1']) git.commit_locally_with_message('message') # Even if diff.noprefix is enabled, create_patch() produces diffs with prefixes. self._run(['git', 'config', 'diff.noprefix', 'true']) git._patch_order = lambda: '' # pylint: disable=protected-access patch = git.create_patch() self.assertRegexpMatches( patch, r'^diff --git a/test_file_commit1 b/test_file_commit1') def test_rename_files(self): self._chdir(self.tracking_git_checkout_path) git = self.tracking_scm git.move('foo_file', 'bar_file') git.commit_locally_with_message('message') def test_commit_position_from_git_log(self): # This tests a protected method. pylint: disable=protected-access git_log = """ commit 624c3081c0 Author: foobarbaz1 <*****@*****.**> Date: Mon Sep 28 19:10:30 2015 -0700 Test foo bar baz qux 123. BUG=000000 Review URL: https://codereview.chromium.org/999999999 Cr-Commit-Position: refs/heads/master@{#1234567} """ self._chdir(self.tracking_git_checkout_path) git = self.tracking_scm self.assertEqual(git._commit_position_from_git_log(git_log), 1234567) def test_timestamp_of_revision(self): # This tests a protected method. pylint: disable=protected-access self._chdir(self.tracking_git_checkout_path) git = self.tracking_scm position_regex = git._commit_position_regex_for_timestamp() git.most_recent_log_matching(position_regex, git.checkout_root)
class SCMTestBase(unittest.TestCase): def __init__(self, *args, **kwargs): super(SCMTestBase, self).__init__(*args, **kwargs) self.scm = None self.executive = None self.fs = None self.original_cwd = None def setUp(self): self.executive = Executive() self.fs = FileSystem() self.original_cwd = self.fs.getcwd() def tearDown(self): self._chdir(self.original_cwd) def _join(self, *comps): return self.fs.join(*comps) def _chdir(self, path): self.fs.chdir(path) def _mkdir(self, path): assert not self.fs.exists(path) self.fs.maybe_make_directory(path) def _mkdtemp(self, **kwargs): return str(self.fs.mkdtemp(**kwargs)) def _remove(self, path): self.fs.remove(path) def _rmtree(self, path): self.fs.rmtree(path) def _run(self, *args, **kwargs): return self.executive.run_command(*args, **kwargs) def _run_silent(self, args, **kwargs): self.executive.run_command(args, **kwargs) def _write_text_file(self, path, contents): self.fs.write_text_file(path, contents) def _write_binary_file(self, path, contents): self.fs.write_binary_file(path, contents) def _make_diff(self, command, *args): # We use this wrapper to disable output decoding. diffs should be treated as # binary files since they may include text files of multiple differnet encodings. return self._run([command, "diff"] + list(args), decode_output=False) def _git_diff(self, *args): return self._make_diff("git", *args) def _shared_test_add_recursively(self): self._mkdir("added_dir") self._write_text_file("added_dir/added_file", "new stuff") self.scm.add("added_dir/added_file") self.assertIn("added_dir/added_file", self.scm._added_files()) def _shared_test_delete_recursively(self): self._mkdir("added_dir") self._write_text_file("added_dir/added_file", "new stuff") self.scm.add("added_dir/added_file") self.assertIn("added_dir/added_file", self.scm._added_files()) self.scm.delete("added_dir/added_file") self.assertNotIn("added_dir", self.scm._added_files()) def _shared_test_delete_recursively_or_not(self): self._mkdir("added_dir") self._write_text_file("added_dir/added_file", "new stuff") self._write_text_file("added_dir/another_added_file", "more new stuff") self.scm.add("added_dir/added_file") self.scm.add("added_dir/another_added_file") self.assertIn("added_dir/added_file", self.scm._added_files()) self.assertIn("added_dir/another_added_file", self.scm._added_files()) self.scm.delete("added_dir/added_file") self.assertIn("added_dir/another_added_file", self.scm._added_files()) def _shared_test_exists(self, scm, commit_function): self._chdir(scm.checkout_root) self.assertFalse(scm.exists('foo.txt')) self._write_text_file('foo.txt', 'some stuff') self.assertFalse(scm.exists('foo.txt')) scm.add('foo.txt') commit_function('adding foo') self.assertTrue(scm.exists('foo.txt')) scm.delete('foo.txt') commit_function('deleting foo') self.assertFalse(scm.exists('foo.txt')) def _shared_test_move(self): self._write_text_file('added_file', 'new stuff') self.scm.add('added_file') self.scm.move('added_file', 'moved_file') self.assertIn('moved_file', self.scm._added_files()) def _shared_test_move_recursive(self): self._mkdir("added_dir") self._write_text_file('added_dir/added_file', 'new stuff') self._write_text_file('added_dir/another_added_file', 'more new stuff') self.scm.add('added_dir') self.scm.move('added_dir', 'moved_dir') self.assertIn('moved_dir/added_file', self.scm._added_files()) self.assertIn('moved_dir/another_added_file', self.scm._added_files())
class SCMTestBase(unittest.TestCase): def __init__(self, *args, **kwargs): super(SCMTestBase, self).__init__(*args, **kwargs) self.scm = None self.executive = None self.fs = None self.original_cwd = None def setUp(self): self.executive = Executive() self.fs = FileSystem() self.original_cwd = self.fs.getcwd() def tearDown(self): self._chdir(self.original_cwd) def _join(self, *comps): return self.fs.join(*comps) def _chdir(self, path): self.fs.chdir(path) def _mkdir(self, path): assert not self.fs.exists(path) self.fs.maybe_make_directory(path) def _mkdtemp(self, **kwargs): return str(self.fs.mkdtemp(**kwargs)) def _remove(self, path): self.fs.remove(path) def _rmtree(self, path): self.fs.rmtree(path) def _run(self, *args, **kwargs): return self.executive.run_command(*args, **kwargs) def _run_silent(self, args, **kwargs): self.executive.run_and_throw_if_fail(args, quiet=True, **kwargs) def _write_text_file(self, path, contents): self.fs.write_text_file(path, contents) def _write_binary_file(self, path, contents): self.fs.write_binary_file(path, contents) def _make_diff(self, command, *args): # We use this wrapper to disable output decoding. diffs should be treated as # binary files since they may include text files of multiple differnet encodings. return self._run([command, "diff"] + list(args), decode_output=False) def _svn_diff(self, *args): return self._make_diff("svn", *args) def _git_diff(self, *args): return self._make_diff("git", *args) def _svn_add(self, path): self._run(["svn", "add", path]) def _svn_commit(self, message): self._run(["svn", "commit", "--quiet", "--message", message]) # This is a hot function since it's invoked by unittest before calling each test_ method in SVNTest and # GitTest. We create a mock SVN repo once and then perform an SVN checkout from a filesystem copy of # it since it's expensive to create the mock repo. def _set_up_svn_checkout(self): global cached_svn_repo_path global original_cwd if not cached_svn_repo_path: cached_svn_repo_path = self._set_up_svn_repo() original_cwd = self.original_cwd self.temp_directory = self._mkdtemp(suffix="svn_test") self.svn_repo_path = self._join(self.temp_directory, "repo") self.svn_repo_url = "file://%s" % self.svn_repo_path self.svn_checkout_path = self._join(self.temp_directory, "checkout") shutil.copytree(cached_svn_repo_path, self.svn_repo_path) self._run([ 'svn', 'checkout', '--quiet', self.svn_repo_url + "/trunk", self.svn_checkout_path ]) def _set_up_svn_repo(self): svn_repo_path = self._mkdtemp(suffix="svn_test_repo") svn_repo_url = "file://%s" % svn_repo_path # Not sure this will work on windows # git svn complains if we don't pass --pre-1.5-compatible, not sure why: # Expected FS format '2'; found format '3' at /usr/local/libexec/git-core//git-svn line 1477 self._run( ['svnadmin', 'create', '--pre-1.5-compatible', svn_repo_path]) # Create a test svn checkout svn_checkout_path = self._mkdtemp(suffix="svn_test_checkout") self._run( ['svn', 'checkout', '--quiet', svn_repo_url, svn_checkout_path]) # Create and checkout a trunk dir to match the standard svn configuration to match git-svn's expectations self._chdir(svn_checkout_path) self._mkdir('trunk') self._svn_add('trunk') # We can add tags and branches as well if we ever need to test those. self._svn_commit('add trunk') self._rmtree(svn_checkout_path) self._set_up_svn_test_commits(svn_repo_url + "/trunk") return svn_repo_path def _set_up_svn_test_commits(self, svn_repo_url): svn_checkout_path = self._mkdtemp(suffix="svn_test_checkout") self._run( ['svn', 'checkout', '--quiet', svn_repo_url, svn_checkout_path]) # Add some test commits self._chdir(svn_checkout_path) self._write_text_file("test_file", "test1") self._svn_add("test_file") self._svn_commit("initial commit") self._write_text_file("test_file", "test1test2") # This used to be the last commit, but doing so broke # GitTest.test_apply_git_patch which use the inverse diff of the last commit. # svn-apply fails to remove directories in Git, see: # https://bugs.webkit.org/show_bug.cgi?id=34871 self._mkdir("test_dir") # Slash should always be the right path separator since we use cygwin on Windows. test_file3_path = "test_dir/test_file3" self._write_text_file(test_file3_path, "third file") self._svn_add("test_dir") self._svn_commit("second commit") self._write_text_file("test_file", "test1test2test3\n") self._write_text_file("test_file2", "second file") self._svn_add("test_file2") self._svn_commit("third commit") # This 4th commit is used to make sure that our patch file handling # code correctly treats patches as binary and does not attempt to # decode them assuming they're utf-8. self._write_binary_file("test_file", u"latin1 test: \u00A0\n".encode("latin-1")) self._write_binary_file("test_file2", u"utf-8 test: \u00A0\n".encode("utf-8")) self._svn_commit("fourth commit") # svn does not seem to update after commit as I would expect. self._run(['svn', 'update']) self._rmtree(svn_checkout_path) def _tear_down_svn_checkout(self): self._rmtree(self.temp_directory) def _shared_test_add_recursively(self): self._mkdir("added_dir") self._write_text_file("added_dir/added_file", "new stuff") self.scm.add("added_dir/added_file") self.assertIn("added_dir/added_file", self.scm._added_files()) def _shared_test_delete_recursively(self): self._mkdir("added_dir") self._write_text_file("added_dir/added_file", "new stuff") self.scm.add("added_dir/added_file") self.assertIn("added_dir/added_file", self.scm._added_files()) self.scm.delete("added_dir/added_file") self.assertNotIn("added_dir", self.scm._added_files()) def _shared_test_delete_recursively_or_not(self): self._mkdir("added_dir") self._write_text_file("added_dir/added_file", "new stuff") self._write_text_file("added_dir/another_added_file", "more new stuff") self.scm.add("added_dir/added_file") self.scm.add("added_dir/another_added_file") self.assertIn("added_dir/added_file", self.scm._added_files()) self.assertIn("added_dir/another_added_file", self.scm._added_files()) self.scm.delete("added_dir/added_file") self.assertIn("added_dir/another_added_file", self.scm._added_files()) def _shared_test_exists(self, scm, commit_function): self._chdir(scm.checkout_root) self.assertFalse(scm.exists('foo.txt')) self._write_text_file('foo.txt', 'some stuff') self.assertFalse(scm.exists('foo.txt')) scm.add('foo.txt') commit_function('adding foo') self.assertTrue(scm.exists('foo.txt')) scm.delete('foo.txt') commit_function('deleting foo') self.assertFalse(scm.exists('foo.txt')) def _shared_test_move(self): self._write_text_file('added_file', 'new stuff') self.scm.add('added_file') self.scm.move('added_file', 'moved_file') self.assertIn('moved_file', self.scm._added_files()) def _shared_test_move_recursive(self): self._mkdir("added_dir") self._write_text_file('added_dir/added_file', 'new stuff') self._write_text_file('added_dir/another_added_file', 'more new stuff') self.scm.add('added_dir') self.scm.move('added_dir', 'moved_dir') self.assertIn('moved_dir/added_file', self.scm._added_files()) self.assertIn('moved_dir/another_added_file', self.scm._added_files())
class SCMTestBase(unittest.TestCase): def __init__(self, *args, **kwargs): super(SCMTestBase, self).__init__(*args, **kwargs) self.scm = None self.executive = None self.fs = None self.original_cwd = None def setUp(self): self.executive = Executive() self.fs = FileSystem() self.original_cwd = self.fs.getcwd() def tearDown(self): self._chdir(self.original_cwd) def _join(self, *comps): return self.fs.join(*comps) def _chdir(self, path): self.fs.chdir(path) def _mkdir(self, path): assert not self.fs.exists(path) self.fs.maybe_make_directory(path) def _mkdtemp(self, **kwargs): return str(self.fs.mkdtemp(**kwargs)) def _remove(self, path): self.fs.remove(path) def _rmtree(self, path): self.fs.rmtree(path) def _run(self, *args, **kwargs): return self.executive.run_command(*args, **kwargs) def _run_silent(self, args, **kwargs): self.executive.run_command(args, **kwargs) def _write_text_file(self, path, contents): self.fs.write_text_file(path, contents) def _write_binary_file(self, path, contents): self.fs.write_binary_file(path, contents) def _make_diff(self, command, *args): # We use this wrapper to disable output decoding. diffs should be treated as # binary files since they may include text files of multiple different encodings. return self._run([command, "diff"] + list(args), decode_output=False) def _git_diff(self, *args): return self._make_diff("git", *args) def _shared_test_add_recursively(self): self._mkdir("added_dir") self._write_text_file("added_dir/added_file", "new stuff") self.scm.add("added_dir/added_file") self.assertIn("added_dir/added_file", self.scm._added_files()) def _shared_test_delete_recursively(self): self._mkdir("added_dir") self._write_text_file("added_dir/added_file", "new stuff") self.scm.add("added_dir/added_file") self.assertIn("added_dir/added_file", self.scm._added_files()) self.scm.delete("added_dir/added_file") self.assertNotIn("added_dir", self.scm._added_files()) def _shared_test_delete_recursively_or_not(self): self._mkdir("added_dir") self._write_text_file("added_dir/added_file", "new stuff") self._write_text_file("added_dir/another_added_file", "more new stuff") self.scm.add("added_dir/added_file") self.scm.add("added_dir/another_added_file") self.assertIn("added_dir/added_file", self.scm._added_files()) self.assertIn("added_dir/another_added_file", self.scm._added_files()) self.scm.delete("added_dir/added_file") self.assertIn("added_dir/another_added_file", self.scm._added_files()) def _shared_test_exists(self, scm, commit_function): self._chdir(scm.checkout_root) self.assertFalse(scm.exists('foo.txt')) self._write_text_file('foo.txt', 'some stuff') self.assertFalse(scm.exists('foo.txt')) scm.add('foo.txt') commit_function('adding foo') self.assertTrue(scm.exists('foo.txt')) scm.delete('foo.txt') commit_function('deleting foo') self.assertFalse(scm.exists('foo.txt')) def _shared_test_move(self): self._write_text_file('added_file', 'new stuff') self.scm.add('added_file') self.scm.move('added_file', 'moved_file') self.assertIn('moved_file', self.scm._added_files()) def _shared_test_move_recursive(self): self._mkdir("added_dir") self._write_text_file('added_dir/added_file', 'new stuff') self._write_text_file('added_dir/another_added_file', 'more new stuff') self.scm.add('added_dir') self.scm.move('added_dir', 'moved_dir') self.assertIn('moved_dir/added_file', self.scm._added_files()) self.assertIn('moved_dir/another_added_file', self.scm._added_files())