Sync up w3c import script with changes in Blink
[WebKit-https.git] / Tools / Scripts / webkitpy / common / checkout / checkout_unittest.py
1 # Copyright (C) 2010 Google Inc. All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are
5 # met:
6 #
7 #    * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer.
9 #    * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following disclaimer
11 # in the documentation and/or other materials provided with the
12 # distribution.
13 #    * Neither the name of Google Inc. nor the names of its
14 # contributors may be used to endorse or promote products derived from
15 # this software without specific prior written permission.
16 #
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 import codecs
30 import os
31 import shutil
32 import tempfile
33 import unittest2 as unittest
34
35 from .checkout import Checkout
36 from .changelog import ChangeLogEntry
37 from .scm import CommitMessage, SCMDetector
38 from .scm.scm_mock import MockSCM
39 from webkitpy.common.webkit_finder import WebKitFinder
40 from webkitpy.common.system.executive import Executive, ScriptError
41 from webkitpy.common.system.filesystem import FileSystem  # FIXME: This should not be needed.
42 from webkitpy.common.system.filesystem_mock import MockFileSystem
43 from webkitpy.common.system.executive_mock import MockExecutive
44 from webkitpy.common.system.outputcapture import OutputCapture
45 from webkitpy.thirdparty.mock import Mock
46
47
48 _changelog1entry1 = u"""2010-03-25  Tor Arne Vestb\u00f8  <vestbo@webkit.org>
49
50         Unreviewed build fix to un-break webkit-patch land.
51
52         Move commit_message_for_this_commit from scm to checkout
53         https://bugs.webkit.org/show_bug.cgi?id=36629
54
55         * Scripts/webkitpy/common/checkout/api.py: import scm.CommitMessage
56 """
57 _changelog1entry2 = u"""2010-03-25  Adam Barth  <abarth@webkit.org>
58
59         Reviewed by Eric Seidel.
60
61         Move commit_message_for_this_commit from scm to checkout
62         https://bugs.webkit.org/show_bug.cgi?id=36629
63
64         * Scripts/webkitpy/common/checkout/api.py:
65 """
66 _changelog1 = u"\n".join([_changelog1entry1, _changelog1entry2])
67 _changelog2 = u"""2010-03-25  Tor Arne Vestb\u00f8  <vestbo@webkit.org>
68
69         Unreviewed build fix to un-break webkit-patch land.
70
71         Second part of this complicated change by me, Tor Arne Vestb\u00f8!
72
73         * Path/To/Complicated/File: Added.
74
75 2010-03-25  Adam Barth  <abarth@webkit.org>
76
77         Reviewed by Eric Seidel.
78
79         Filler change.
80 """
81
82 class CommitMessageForThisCommitTest(unittest.TestCase):
83     expected_commit_message = u"""Unreviewed build fix to un-break webkit-patch land.
84
85 Tools: 
86
87 Move commit_message_for_this_commit from scm to checkout
88 https://bugs.webkit.org/show_bug.cgi?id=36629
89
90 * Scripts/webkitpy/common/checkout/api.py: import scm.CommitMessage
91
92 LayoutTests: 
93
94 Second part of this complicated change by me, Tor Arne Vestb\u00f8!
95
96 * Path/To/Complicated/File: Added.
97 """
98
99     def setUp(self):
100         # FIXME: This should not need to touch the filesystem, however
101         # ChangeLog is difficult to mock at current.
102         self.filesystem = FileSystem()
103         self.temp_dir = str(self.filesystem.mkdtemp(suffix="changelogs"))
104         self.old_cwd = self.filesystem.getcwd()
105         self.filesystem.chdir(self.temp_dir)
106         self.webkit_base = WebKitFinder(self.filesystem).webkit_base()
107
108         # Trick commit-log-editor into thinking we're in a Subversion working copy so it won't
109         # complain about not being able to figure out what SCM is in use.
110         # FIXME: VCSTools.pm is no longer so easily fooled.  It logs because "svn info" doesn't
111         # treat a bare .svn directory being part of an svn checkout.
112         self.filesystem.maybe_make_directory(".svn")
113
114         self.changelogs = map(self.filesystem.abspath, (self.filesystem.join("Tools", "ChangeLog"), self.filesystem.join("LayoutTests", "ChangeLog")))
115         for path, contents in zip(self.changelogs, (_changelog1, _changelog2)):
116             self.filesystem.maybe_make_directory(self.filesystem.dirname(path))
117             self.filesystem.write_text_file(path, contents)
118
119     def tearDown(self):
120         self.filesystem.rmtree(self.temp_dir)
121         self.filesystem.chdir(self.old_cwd)
122
123     def test_commit_message_for_this_commit(self):
124         executive = Executive()
125
126         def mock_run(*args, **kwargs):
127             # Note that we use a real Executive here, not a MockExecutive, so we can test that we're
128             # invoking commit-log-editor correctly.
129             env = os.environ.copy()
130             env['CHANGE_LOG_EMAIL_ADDRESS'] = 'vestbo@webkit.org'
131             kwargs['env'] = env
132             return executive.run_command(*args, **kwargs)
133
134         detector = SCMDetector(self.filesystem, executive)
135         real_scm = detector.detect_scm_system(self.webkit_base)
136
137         mock_scm = MockSCM()
138         mock_scm.run = mock_run
139         mock_scm.script_path = real_scm.script_path
140
141         checkout = Checkout(mock_scm)
142         checkout.modified_changelogs = lambda git_commit, changed_files=None: self.changelogs
143         commit_message = checkout.commit_message_for_this_commit(git_commit=None, return_stderr=True)
144         # Throw away the first line - a warning about unknown VCS root.
145         commit_message.message_lines = commit_message.message_lines[1:]
146         self.assertMultiLineEqual(commit_message.message(), self.expected_commit_message)
147
148
149 class CheckoutTest(unittest.TestCase):
150     def _make_checkout(self):
151         return Checkout(scm=MockSCM(), filesystem=MockFileSystem(), executive=MockExecutive())
152
153     def test_latest_entry_for_changelog_at_revision(self):
154         def mock_contents_at_revision(changelog_path, revision):
155             self.assertEqual(changelog_path, "foo")
156             self.assertEqual(revision, "bar")
157             # contents_at_revision is expected to return a byte array (str)
158             # so we encode our unicode ChangeLog down to a utf-8 stream.
159             # The ChangeLog utf-8 decoding should ignore invalid codepoints.
160             invalid_utf8 = "\255"
161             return _changelog1.encode("utf-8") + invalid_utf8
162         checkout = self._make_checkout()
163         checkout._scm.contents_at_revision = mock_contents_at_revision
164         entry = checkout._latest_entry_for_changelog_at_revision("foo", "bar")
165         self.assertMultiLineEqual(entry.contents(), _changelog1entry1)  # Pylint is confused about this line, pylint: disable=E1101
166
167     # FIXME: This tests a hack around our current changed_files handling.
168     # Right now changelog_entries_for_revision tries to fetch deleted files
169     # from revisions, resulting in a ScriptError exception.  Test that we
170     # recover from those and still return the other ChangeLog entries.
171     def test_changelog_entries_for_revision(self):
172         checkout = self._make_checkout()
173         checkout._scm.changed_files_for_revision = lambda revision: ['foo/ChangeLog', 'bar/ChangeLog']
174
175         def mock_latest_entry_for_changelog_at_revision(path, revision):
176             if path == "foo/ChangeLog":
177                 return 'foo'
178             raise ScriptError()
179
180         checkout._latest_entry_for_changelog_at_revision = mock_latest_entry_for_changelog_at_revision
181
182         # Even though fetching one of the entries failed, the other should succeed.
183         entries = checkout.changelog_entries_for_revision(1)
184         self.assertEqual(len(entries), 1)
185         self.assertEqual(entries[0], 'foo')
186
187     def test_commit_info_for_revision(self):
188         checkout = self._make_checkout()
189         checkout._scm.changed_files_for_revision = lambda revision: ['path/to/file', 'another/file']
190         checkout._scm.committer_email_for_revision = lambda revision, changed_files=None: "committer@example.com"
191         checkout.changelog_entries_for_revision = lambda revision, changed_files=None: [ChangeLogEntry(_changelog1entry1)]
192         commitinfo = checkout.commit_info_for_revision(4)
193         self.assertEqual(commitinfo.bug_id(), 36629)
194         self.assertEqual(commitinfo.author_name(), u"Tor Arne Vestb\u00f8")
195         self.assertEqual(commitinfo.author_email(), "vestbo@webkit.org")
196         self.assertIsNone(commitinfo.reviewer_text())
197         self.assertIsNone(commitinfo.reviewer())
198         self.assertEqual(commitinfo.committer_email(), "committer@example.com")
199         self.assertIsNone(commitinfo.committer())
200         self.assertEqual(commitinfo.to_json(), {
201             'bug_id': 36629,
202             'author_email': 'vestbo@webkit.org',
203             'changed_files': [
204                 'path/to/file',
205                 'another/file',
206             ],
207             'reviewer_text': None,
208             'author_name': u'Tor Arne Vestb\xf8',
209         })
210
211         checkout.changelog_entries_for_revision = lambda revision, changed_files=None: []
212         self.assertIsNone(checkout.commit_info_for_revision(1))
213
214     def test_bug_id_for_revision(self):
215         checkout = self._make_checkout()
216         checkout._scm.committer_email_for_revision = lambda revision: "committer@example.com"
217         checkout.changelog_entries_for_revision = lambda revision, changed_files=None: [ChangeLogEntry(_changelog1entry1)]
218         self.assertEqual(checkout.bug_id_for_revision(4), 36629)
219
220     def test_bug_id_for_this_commit(self):
221         checkout = self._make_checkout()
222         checkout.commit_message_for_this_commit = lambda git_commit, changed_files=None: CommitMessage(ChangeLogEntry(_changelog1entry1).contents().splitlines())
223         self.assertEqual(checkout.bug_id_for_this_commit(git_commit=None), 36629)
224
225     def test_modified_changelogs(self):
226         checkout = self._make_checkout()
227         checkout._scm.checkout_root = "/foo/bar"
228         checkout._scm.changed_files = lambda git_commit: ["file1", "ChangeLog", "relative/path/ChangeLog"]
229         expected_changlogs = ["/foo/bar/ChangeLog", "/foo/bar/relative/path/ChangeLog"]
230         self.assertEqual(checkout.modified_changelogs(git_commit=None), expected_changlogs)
231
232     def test_suggested_reviewers(self):
233         def mock_changelog_entries_for_revision(revision, changed_files=None):
234             if revision % 2 == 0:
235                 return [ChangeLogEntry(_changelog1entry1)]
236             return [ChangeLogEntry(_changelog1entry2)]
237
238         def mock_revisions_changing_file(path, limit=5):
239             if path.endswith("ChangeLog"):
240                 return [3]
241             return [4, 8]
242
243         checkout = self._make_checkout()
244         checkout._scm.checkout_root = "/foo/bar"
245         checkout._scm.changed_files = lambda git_commit: ["file1", "file2", "relative/path/ChangeLog"]
246         checkout._scm.revisions_changing_file = mock_revisions_changing_file
247         checkout.changelog_entries_for_revision = mock_changelog_entries_for_revision
248         reviewers = checkout.suggested_reviewers(git_commit=None)
249         reviewer_names = [reviewer.full_name for reviewer in reviewers]
250         self.assertEqual(reviewer_names, [u'Tor Arne Vestb\xf8'])
251
252     def test_apply_patch(self):
253         checkout = self._make_checkout()
254         checkout._executive = MockExecutive(should_log=True)
255         checkout._scm.script_path = lambda script: script
256         mock_patch = Mock()
257         mock_patch.contents = lambda: "foo"
258         mock_patch.reviewer = lambda: None
259         expected_logs = "MOCK run_command: ['svn-apply', '--force'], cwd=/mock-checkout, input=foo\n"
260         OutputCapture().assert_outputs(self, checkout.apply_patch, [mock_patch], expected_logs=expected_logs)