1 # Copyright (C) 2009 Google Inc. All rights reserved.
2 # Copyright (C) 2009 Apple Inc. All rights reserved.
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
8 # * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 # * Redistributions in binary form must reproduce the above
11 # copyright notice, this list of conditions and the following disclaimer
12 # in the documentation and/or other materials provided with the
14 # * Neither the name of Google Inc. nor the names of its
15 # contributors may be used to endorse or promote products derived from
16 # this software without specific prior written permission.
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 from datetime import date
41 from modules.scm import detect_scm_system, SCM, ScriptError, CheckoutNeedsUpdate, ignore_error, commit_error_handler
44 # Eventually we will want to write tests which work for both scms. (like update_webkit, changed_files, etc.)
45 # Perhaps through some SCMTest base-class which both SVNTest and GitTest inherit from.
47 def run(args, cwd=None):
48 return SCM.run_command(args, cwd=cwd)
50 def run_silent(args, cwd=None):
51 process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd)
52 process.communicate() # ignore output
53 exit_code = process.wait()
55 raise ScriptError('Failed to run "%s" exit_code: %d cwd: %s' % (args, exit_code, cwd))
57 def write_into_file_at_path(file_path, contents):
58 file = open(file_path, 'w')
62 def read_from_path(file_path):
63 file = open(file_path, 'r')
64 contents = file.read()
68 # Exists to share svn repository creation code between the git and svn tests
69 class SVNTestRepository:
71 def _setup_test_commits(test_object):
72 # Add some test commits
73 os.chdir(test_object.svn_checkout_path)
74 test_file = open('test_file', 'w')
75 test_file.write("test1")
78 run(['svn', 'add', 'test_file'])
79 run(['svn', 'commit', '--quiet', '--message', 'initial commit'])
81 test_file.write("test2")
84 run(['svn', 'commit', '--quiet', '--message', 'second commit'])
86 test_file.write("test3\n")
89 run(['svn', 'commit', '--quiet', '--message', 'third commit'])
91 test_file.write("test4\n")
94 run(['svn', 'commit', '--quiet', '--message', 'fourth commit'])
96 # svn does not seem to update after commit as I would expect.
97 run(['svn', 'update'])
100 def setup(cls, test_object):
101 # Create an test SVN repository
102 test_object.svn_repo_path = tempfile.mkdtemp(suffix="svn_test_repo")
103 test_object.svn_repo_url = "file://%s" % test_object.svn_repo_path # Not sure this will work on windows
104 # git svn complains if we don't pass --pre-1.5-compatible, not sure why:
105 # Expected FS format '2'; found format '3' at /usr/local/libexec/git-core//git-svn line 1477
106 run(['svnadmin', 'create', '--pre-1.5-compatible', test_object.svn_repo_path])
108 # Create a test svn checkout
109 test_object.svn_checkout_path = tempfile.mkdtemp(suffix="svn_test_checkout")
110 run(['svn', 'checkout', '--quiet', test_object.svn_repo_url, test_object.svn_checkout_path])
112 cls._setup_test_commits(test_object)
115 def tear_down(cls, test_object):
116 run(['rm', '-rf', test_object.svn_repo_path])
117 run(['rm', '-rf', test_object.svn_checkout_path])
119 # For testing the SCM baseclass directly.
120 class SCMClassTests(unittest.TestCase):
122 self.dev_null = open(os.devnull, "w") # Used to make our Popen calls quiet.
125 self.dev_null.close()
127 def test_run_command_with_pipe(self):
128 input_process = subprocess.Popen(['/bin/echo', 'foo\nbar'], stdout=subprocess.PIPE, stderr=self.dev_null)
129 self.assertEqual(SCM.run_command(['/usr/bin/grep', 'bar'], input=input_process.stdout), "bar\n")
131 # Test the non-pipe case too:
132 self.assertEqual(SCM.run_command(['/usr/bin/grep', 'bar'], input="foo\nbar"), "bar\n")
134 command_returns_non_zero = ['/bin/sh', '--invalid-option']
135 # Test when the input pipe process fails.
136 input_process = subprocess.Popen(command_returns_non_zero, stdout=subprocess.PIPE, stderr=self.dev_null)
137 self.assertTrue(input_process.poll() != 0)
138 self.assertRaises(ScriptError, SCM.run_command, ['/usr/bin/grep', 'bar'], input=input_process.stdout)
140 # Test when the run_command process fails.
141 input_process = subprocess.Popen(['/bin/echo', 'foo\nbar'], stdout=subprocess.PIPE, stderr=self.dev_null) # grep shows usage and calls exit(2) when called w/o arguments.
142 self.assertRaises(ScriptError, SCM.run_command, command_returns_non_zero, input=input_process.stdout)
144 def test_error_handlers(self):
145 git_failure_message="Merge conflict during commit: Your file or directory 'WebCore/ChangeLog' is probably out-of-date: resource out of date; try updating at /usr/local/libexec/git-core//git-svn line 469"
146 svn_failure_message="""svn: Commit failed (details follow):
147 svn: File or directory 'ChangeLog' is out of date; try updating
148 svn: resource out of date; try updating
150 command_does_not_exist = ['does_not_exist', 'invalid_option']
151 self.assertRaises(OSError, SCM.run_command, command_does_not_exist)
152 self.assertRaises(OSError, SCM.run_command, command_does_not_exist, error_handler=ignore_error)
154 command_returns_non_zero = ['/bin/sh', '--invalid-option']
155 self.assertRaises(ScriptError, SCM.run_command, command_returns_non_zero)
156 # Check if returns error text:
157 self.assertTrue(SCM.run_command(command_returns_non_zero, error_handler=ignore_error, return_stderr=True))
159 self.assertRaises(CheckoutNeedsUpdate, commit_error_handler, ScriptError(output=git_failure_message))
160 self.assertRaises(CheckoutNeedsUpdate, commit_error_handler, ScriptError(output=svn_failure_message))
161 self.assertRaises(ScriptError, commit_error_handler, ScriptError(output='blah blah blah'))
164 # GitTest and SVNTest inherit from this so any test_ methods here will be run once for this class and then once for each subclass.
165 class SCMTest(unittest.TestCase):
166 def _create_patch(self, patch_contents):
167 patch_path = os.path.join(self.svn_checkout_path, 'patch.diff')
168 write_into_file_at_path(patch_path, patch_contents)
170 patch['reviewer'] = 'Joe Cool'
171 patch['bug_id'] = '12345'
172 patch['url'] = 'file://%s' % urllib.pathname2url(patch_path)
175 def _setup_webkittools_scripts_symlink(self, local_scm):
176 webkit_scm = detect_scm_system(os.path.dirname(os.path.abspath(__file__)))
177 webkit_scripts_directory = webkit_scm.scripts_directory()
178 local_scripts_directory = local_scm.scripts_directory()
179 os.mkdir(os.path.dirname(local_scripts_directory))
180 os.symlink(webkit_scripts_directory, local_scripts_directory)
182 # Tests which both GitTest and SVNTest should run.
183 # FIXME: There must be a simpler way to add these w/o adding a wrapper method to both subclasses
184 def _shared_test_commit_with_message(self):
185 write_into_file_at_path('test_file', 'more test content')
186 commit_text = self.scm.commit_with_message('another test commit')
187 self.assertEqual(self.scm.svn_revision_from_commit_text(commit_text), '5')
189 self.scm.dryrun = True
190 write_into_file_at_path('test_file', 'still more test content')
191 commit_text = self.scm.commit_with_message('yet another test commit')
192 self.assertEqual(self.scm.svn_revision_from_commit_text(commit_text), '0')
194 def _shared_test_reverse_diff(self):
195 self._setup_webkittools_scripts_symlink(self.scm) # Git's apply_reverse_diff uses resolve-ChangeLogs
196 # Only test the simple case, as any other will end up with conflict markers.
197 self.scm.apply_reverse_diff('4')
198 self.assertEqual(read_from_path('test_file'), "test1test2test3\n")
200 def _shared_test_diff_for_revision(self):
201 # Patch formats are slightly different between svn and git, so just regexp for things we know should be there.
202 r3_patch = self.scm.diff_for_revision(3)
203 self.assertTrue(re.search('test3', r3_patch))
204 self.assertFalse(re.search('test4', r3_patch))
205 self.assertTrue(re.search('test2', r3_patch))
206 self.assertTrue(re.search('test2', self.scm.diff_for_revision(2)))
208 def _shared_test_svn_apply_git_patch(self):
209 self._setup_webkittools_scripts_symlink(self.scm)
210 git_binary_addition = """diff --git a/fizzbuzz7.gif b/fizzbuzz7.gif
212 index 0000000000000000000000000000000000000000..64a9532e7794fcd791f6f12157406d90
216 zcmZ?wbhEHbRAx|MU|?iW{Kxc~?KofD;ckY;H+&5HnHl!!GQMD7h+sU{_)e9f^V3c?
217 zhJP##HdZC#4K}7F68@!1jfWQg2daCm-gs#3|JREDT>c+pG4L<_2;w##WMO#ysPPap
218 zLqpAf1OE938xAsSp4!5f-o><?VKe(#0jEcwfHGF4%M1^kRs14oVBp2ZEL{E1N<-zJ
219 zsfLmOtKta;2_;2c#^S1-8cf<nb!QnGl>c!Xe6RXvrEtAWBvSDTgTO1j3vA31Puw!A
220 zs(87q)j_mVDTqBo-P+03-P5mHCEnJ+x}YdCuS7#bCCyePUe(ynK+|4b-3qK)T?Z&)
221 zYG+`tl4h?GZv_$t82}X4*DTE|$;{DEiPyF@)U-1+FaX++T9H{&%cag`W1|zVP@`%b
222 zqiSkp6{BTpWTkCr!=<C6Q=?#~R8^JfrliAF6Q^gV9Iup8RqCXqqhqC`qsyhk<-nlB
223 z00f{QZvfK&|Nm#oZ0TQl`Yr$BIa6A@16O26ud7H<QM=xl`toLKnz-3h@9c9q&wm|X
224 z{89I|WPyD!*M?gv?q`;L=2YFeXrJQNti4?}s!zFo=5CzeBxC69xA<zrjP<wUcCRh4
225 ptUl-ZG<%a~#LwkIWv&q!KSCH7tQ8cJDiw+|GV?MN)RjY50RTb-xvT&H
231 self.scm.apply_patch(self._create_patch(git_binary_addition))
232 added = read_from_path('fizzbuzz7.gif')
233 self.assertEqual(512, len(added))
234 self.assertTrue(added.startswith('GIF89a'))
235 self.assertTrue('fizzbuzz7.gif' in self.scm.changed_files())
237 # The file already exists.
238 self.assertRaises(ScriptError, self.scm.apply_patch, self._create_patch(git_binary_addition))
240 git_binary_modification = """diff --git a/fizzbuzz7.gif b/fizzbuzz7.gif
241 index 64a9532e7794fcd791f6f12157406d9060151690..323fae03f4606ea9991df8befbb2fca7
244 OcmYex&reD$;sO8*F9L)B
247 zcmZ?wbhEHbRAx|MU|?iW{Kxc~?KofD;ckY;H+&5HnHl!!GQMD7h+sU{_)e9f^V3c?
248 zhJP##HdZC#4K}7F68@!1jfWQg2daCm-gs#3|JREDT>c+pG4L<_2;w##WMO#ysPPap
249 zLqpAf1OE938xAsSp4!5f-o><?VKe(#0jEcwfHGF4%M1^kRs14oVBp2ZEL{E1N<-zJ
250 zsfLmOtKta;2_;2c#^S1-8cf<nb!QnGl>c!Xe6RXvrEtAWBvSDTgTO1j3vA31Puw!A
251 zs(87q)j_mVDTqBo-P+03-P5mHCEnJ+x}YdCuS7#bCCyePUe(ynK+|4b-3qK)T?Z&)
252 zYG+`tl4h?GZv_$t82}X4*DTE|$;{DEiPyF@)U-1+FaX++T9H{&%cag`W1|zVP@`%b
253 zqiSkp6{BTpWTkCr!=<C6Q=?#~R8^JfrliAF6Q^gV9Iup8RqCXqqhqC`qsyhk<-nlB
254 z00f{QZvfK&|Nm#oZ0TQl`Yr$BIa6A@16O26ud7H<QM=xl`toLKnz-3h@9c9q&wm|X
255 z{89I|WPyD!*M?gv?q`;L=2YFeXrJQNti4?}s!zFo=5CzeBxC69xA<zrjP<wUcCRh4
256 ptUl-ZG<%a~#LwkIWv&q!KSCH7tQ8cJDiw+|GV?MN)RjY50RTb-xvT&H
259 self.scm.apply_patch(self._create_patch(git_binary_modification))
260 modified = read_from_path('fizzbuzz7.gif')
261 self.assertEqual('foobar\n', modified)
262 self.assertTrue('fizzbuzz7.gif' in self.scm.changed_files())
264 # Applying the same modification should fail.
265 self.assertRaises(ScriptError, self.scm.apply_patch, self._create_patch(git_binary_modification))
267 git_binary_deletion = """diff --git a/fizzbuzz7.gif b/fizzbuzz7.gif
268 deleted file mode 100644
269 index 323fae0..0000000
275 OcmYex&reD$;sO8*F9L)B
278 self.scm.apply_patch(self._create_patch(git_binary_deletion))
279 self.assertFalse(os.path.exists('fizzbuzz7.gif'))
280 self.assertFalse('fizzbuzz7.gif' in self.scm.changed_files())
282 # Cannot delete again.
283 self.assertRaises(ScriptError, self.scm.apply_patch, self._create_patch(git_binary_deletion))
286 class SVNTest(SCMTest):
289 def _set_date_and_reviewer(changelog_entry):
290 # Joe Cool matches the reviewer set in SCMTest._create_patch
291 changelog_entry = changelog_entry.replace('REVIEWER_HERE', 'Joe Cool')
292 # svn-apply will update ChangeLog entries with today's date.
293 return changelog_entry.replace('DATE_HERE', date.today().isoformat())
295 def test_svn_apply(self):
296 first_entry = """2009-10-26 Eric Seidel <eric@webkit.org>
300 Most awesome change ever.
304 intermediate_entry = """2009-10-27 Eric Seidel <eric@webkit.org>
308 A more awesomer change yet!
312 one_line_overlap_patch = """Index: ChangeLog
313 ===================================================================
314 --- ChangeLog (revision 5)
315 +++ ChangeLog (working copy)
317 2009-10-26 Eric Seidel <eric@webkit.org>
319 + Reviewed by NOBODY (OOPS!).
321 + Second most awsome change ever.
325 +2009-10-26 Eric Seidel <eric@webkit.org>
329 Most awesome change ever.
331 one_line_overlap_entry = """DATE_HERE Eric Seidel <eric@webkit.org>
333 Reviewed by REVIEWER_HERE.
335 Second most awsome change ever.
339 two_line_overlap_patch = """Index: ChangeLog
340 ===================================================================
341 --- ChangeLog (revision 5)
342 +++ ChangeLog (working copy)
347 + Second most awsome change ever.
351 +2009-10-26 Eric Seidel <eric@webkit.org>
353 + Reviewed by Foo Bar.
355 Most awesome change ever.
359 two_line_overlap_entry = """DATE_HERE Eric Seidel <eric@webkit.org>
363 Second most awsome change ever.
367 write_into_file_at_path('ChangeLog', first_entry)
368 run(['svn', 'add', 'ChangeLog'])
369 run(['svn', 'commit', '--quiet', '--message', 'ChangeLog commit'])
371 # Patch files were created against just 'first_entry'.
372 # Add a second commit to make svn-apply have to apply the patches with fuzz.
373 changelog_contents = "%s\n%s" % (intermediate_entry, first_entry)
374 write_into_file_at_path('ChangeLog', changelog_contents)
375 run(['svn', 'commit', '--quiet', '--message', 'Intermediate commit'])
377 self._setup_webkittools_scripts_symlink(self.scm)
378 self.scm.apply_patch(self._create_patch(one_line_overlap_patch))
379 expected_changelog_contents = "%s\n%s" % (self._set_date_and_reviewer(one_line_overlap_entry), changelog_contents)
380 self.assertEquals(read_from_path('ChangeLog'), expected_changelog_contents)
382 self.scm.revert_files(['ChangeLog'])
383 self.scm.apply_patch(self._create_patch(two_line_overlap_patch))
384 expected_changelog_contents = "%s\n%s" % (self._set_date_and_reviewer(two_line_overlap_entry), changelog_contents)
385 self.assertEquals(read_from_path('ChangeLog'), expected_changelog_contents)
388 SVNTestRepository.setup(self)
389 os.chdir(self.svn_checkout_path)
390 self.scm = detect_scm_system(self.svn_checkout_path)
393 SVNTestRepository.tear_down(self)
395 def test_create_patch_is_full_patch(self):
396 test_dir_path = os.path.join(self.svn_checkout_path, 'test_dir')
397 os.mkdir(test_dir_path)
398 test_file_path = os.path.join(test_dir_path, 'test_file2')
399 write_into_file_at_path(test_file_path, 'test content')
400 run(['svn', 'add', 'test_dir'])
402 # create_patch depends on 'svn-create-patch', so make a dummy version.
403 scripts_path = os.path.join(self.svn_checkout_path, 'WebKitTools', 'Scripts')
404 os.makedirs(scripts_path)
405 create_patch_path = os.path.join(scripts_path, 'svn-create-patch')
406 write_into_file_at_path(create_patch_path, '#!/bin/sh\necho $PWD')
407 os.chmod(create_patch_path, stat.S_IXUSR | stat.S_IRUSR)
409 # Change into our test directory and run the create_patch command.
410 os.chdir(test_dir_path)
411 scm = detect_scm_system(test_dir_path)
412 self.assertEqual(scm.checkout_root, self.svn_checkout_path) # Sanity check that detection worked right.
413 patch_contents = scm.create_patch()
414 # Our fake 'svn-create-patch' returns $PWD instead of a patch, check that it was executed from the root of the repo.
415 self.assertEqual(os.path.realpath(scm.checkout_root), patch_contents)
417 def test_detection(self):
418 scm = detect_scm_system(self.svn_checkout_path)
419 self.assertEqual(scm.display_name(), "svn")
420 self.assertEqual(scm.supports_local_commits(), False)
422 def test_apply_small_binary_patch(self):
423 patch_contents = """Index: test_file.swf
424 ===================================================================
425 Cannot display: file marked as a binary type.
426 svn:mime-type = application/octet-stream
428 Property changes on: test_file.swf
429 ___________________________________________________________________
431 + application/octet-stream
434 Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
436 expected_contents = base64.b64decode("Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==")
437 self._setup_webkittools_scripts_symlink(self.scm)
438 patch_file = self._create_patch(patch_contents)
439 self.scm.apply_patch(patch_file)
440 actual_contents = read_from_path("test_file.swf")
441 self.assertEqual(actual_contents, expected_contents)
443 def test_apply_svn_patch(self):
444 scm = detect_scm_system(self.svn_checkout_path)
445 patch = self._create_patch(run(['svn', 'diff', '-r4:3']))
446 self._setup_webkittools_scripts_symlink(scm)
447 scm.apply_patch(patch)
449 def test_apply_svn_patch_force(self):
450 scm = detect_scm_system(self.svn_checkout_path)
451 patch = self._create_patch(run(['svn', 'diff', '-r2:4']))
452 self._setup_webkittools_scripts_symlink(scm)
453 self.assertRaises(ScriptError, scm.apply_patch, patch, force=True)
455 def test_commit_logs(self):
456 # Commits have dates and usernames in them, so we can't just direct compare.
457 self.assertTrue(re.search('fourth commit', self.scm.last_svn_commit_log()))
458 self.assertTrue(re.search('second commit', self.scm.svn_commit_log(2)))
460 def test_commit_text_parsing(self):
461 self._shared_test_commit_with_message()
463 def test_reverse_diff(self):
464 self._shared_test_reverse_diff()
466 def test_diff_for_revision(self):
467 self._shared_test_diff_for_revision()
469 def test_svn_apply_git_patch(self):
470 self._shared_test_svn_apply_git_patch()
472 class GitTest(SCMTest):
474 def _setup_git_clone_of_svn_repository(self):
475 self.git_checkout_path = tempfile.mkdtemp(suffix="git_test_checkout")
476 # --quiet doesn't make git svn silent, so we use run_silent to redirect output
477 run_silent(['git', 'svn', '--quiet', 'clone', self.svn_repo_url, self.git_checkout_path])
479 def _tear_down_git_clone_of_svn_repository(self):
480 run(['rm', '-rf', self.git_checkout_path])
483 SVNTestRepository.setup(self)
484 self._setup_git_clone_of_svn_repository()
485 os.chdir(self.git_checkout_path)
486 self.scm = detect_scm_system(self.git_checkout_path)
489 SVNTestRepository.tear_down(self)
490 self._tear_down_git_clone_of_svn_repository()
492 def test_detection(self):
493 scm = detect_scm_system(self.git_checkout_path)
494 self.assertEqual(scm.display_name(), "git")
495 self.assertEqual(scm.supports_local_commits(), True)
497 def test_rebase_in_progress(self):
498 svn_test_file = os.path.join(self.svn_checkout_path, 'test_file')
499 write_into_file_at_path(svn_test_file, "svn_checkout")
500 run(['svn', 'commit', '--message', 'commit to conflict with git commit'], cwd=self.svn_checkout_path)
502 git_test_file = os.path.join(self.git_checkout_path, 'test_file')
503 write_into_file_at_path(git_test_file, "git_checkout")
504 run(['git', 'commit', '-a', '-m', 'commit to be thrown away by rebase abort'])
506 # --quiet doesn't make git svn silent, so use run_silent to redirect output
507 self.assertRaises(ScriptError, run_silent, ['git', 'svn', '--quiet', 'rebase']) # Will fail due to a conflict leaving us mid-rebase.
509 scm = detect_scm_system(self.git_checkout_path)
510 self.assertTrue(scm.rebase_in_progress())
512 # Make sure our cleanup works.
513 scm.clean_working_directory()
514 self.assertFalse(scm.rebase_in_progress())
516 # Make sure cleanup doesn't throw when no rebase is in progress.
517 scm.clean_working_directory()
519 def test_commitish_parsing(self):
520 scm = detect_scm_system(self.git_checkout_path)
522 # Multiple revisions are cherry-picked.
523 self.assertEqual(len(scm.commit_ids_from_commitish_arguments(['HEAD~2'])), 1)
524 self.assertEqual(len(scm.commit_ids_from_commitish_arguments(['HEAD', 'HEAD~2'])), 2)
526 # ... is an invalid range specifier
527 self.assertRaises(ScriptError, scm.commit_ids_from_commitish_arguments, ['trunk...HEAD'])
529 def test_commitish_order(self):
530 scm = detect_scm_system(self.git_checkout_path)
532 commit_range = 'HEAD~3..HEAD'
534 actual_commits = scm.commit_ids_from_commitish_arguments([commit_range])
535 expected_commits = []
536 expected_commits += reversed(run(['git', 'rev-list', commit_range]).splitlines())
538 self.assertEqual(actual_commits, expected_commits)
540 def test_apply_git_patch(self):
541 scm = detect_scm_system(self.git_checkout_path)
542 patch = self._create_patch(run(['git', 'diff', 'HEAD..HEAD^']))
543 self._setup_webkittools_scripts_symlink(scm)
544 scm.apply_patch(patch)
546 def test_apply_git_patch_force(self):
547 scm = detect_scm_system(self.git_checkout_path)
548 patch = self._create_patch(run(['git', 'diff', 'HEAD~2..HEAD']))
549 self._setup_webkittools_scripts_symlink(scm)
550 self.assertRaises(ScriptError, scm.apply_patch, patch, force=True)
552 def test_commit_text_parsing(self):
553 self._shared_test_commit_with_message()
555 def test_reverse_diff(self):
556 self._shared_test_reverse_diff()
558 def test_diff_for_revision(self):
559 self._shared_test_diff_for_revision()
561 def test_svn_apply_git_patch(self):
562 self._shared_test_svn_apply_git_patch()
564 def test_create_binary_patch(self):
565 # Create a git binary patch and check the contents.
566 scm = detect_scm_system(self.git_checkout_path)
567 test_file_name = 'binary_file'
568 test_file_path = os.path.join(self.git_checkout_path, test_file_name)
569 file_contents = ''.join(map(chr, range(256)))
570 write_into_file_at_path(test_file_path, file_contents)
571 run(['git', 'add', test_file_name])
572 patch = scm.create_patch()
573 self.assertTrue(re.search(r'\nliteral 0\n', patch))
574 self.assertTrue(re.search(r'\nliteral 256\n', patch))
576 # Check if we can apply the created patch.
577 run(['git', 'rm', '-f', test_file_name])
578 self._setup_webkittools_scripts_symlink(scm)
579 self.scm.apply_patch(self._create_patch(patch))
580 self.assertEqual(file_contents, read_from_path(test_file_path))
582 # Check if we can create a patch from a local commit.
583 write_into_file_at_path(test_file_path, file_contents)
584 run(['git', 'add', test_file_name])
585 run(['git', 'commit', '-m', 'binary diff'])
586 patch_from_local_commit = scm.create_patch_from_local_commit('HEAD')
587 self.assertTrue(re.search(r'\nliteral 0\n', patch_from_local_commit))
588 self.assertTrue(re.search(r'\nliteral 256\n', patch_from_local_commit))
589 patch_since_local_commit = scm.create_patch_since_local_commit('HEAD^1')
590 self.assertTrue(re.search(r'\nliteral 0\n', patch_since_local_commit))
591 self.assertTrue(re.search(r'\nliteral 256\n', patch_since_local_commit))
592 self.assertEqual(patch_from_local_commit, patch_since_local_commit)
595 if __name__ == '__main__':