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 from __future__ import with_statement 30 31 import codecs 32 import os 33 import shutil 34 import tempfile 35 import unittest 36 37 from webkitpy.common.checkout.api import Checkout 38 from webkitpy.common.checkout.changelog import ChangeLogEntry 39 from webkitpy.common.checkout.scm import detect_scm_system, CommitMessage 40 from webkitpy.common.system.outputcapture import OutputCapture 41 from webkitpy.common.system.executive import ScriptError 42 from webkitpy.thirdparty.mock import Mock 43 44 45 # FIXME: Copied from scm_unittest.py 46 def write_into_file_at_path(file_path, contents, encoding="utf-8"): 47 with codecs.open(file_path, "w", encoding) as file: 48 file.write(contents) 49 50 51 _changelog1entry1 = u"""2010-03-25 Tor Arne Vestb\u00f8 <vestbo (at] webkit.org> 52 53 Unreviewed build fix to un-break webkit-patch land. 54 55 Move commit_message_for_this_commit from scm to checkout 56 https://bugs.webkit.org/show_bug.cgi?id=36629 57 58 * Scripts/webkitpy/common/checkout/api.py: import scm.CommitMessage 59 """ 60 _changelog1entry2 = u"""2010-03-25 Adam Barth <abarth (at] webkit.org> 61 62 Reviewed by Eric Seidel. 63 64 Move commit_message_for_this_commit from scm to checkout 65 https://bugs.webkit.org/show_bug.cgi?id=36629 66 67 * Scripts/webkitpy/common/checkout/api.py: 68 """ 69 _changelog1 = u"\n".join([_changelog1entry1, _changelog1entry2]) 70 _changelog2 = u"""2010-03-25 Tor Arne Vestb\u00f8 <vestbo (at] webkit.org> 71 72 Unreviewed build fix to un-break webkit-patch land. 73 74 Second part of this complicated change. 75 76 * Path/To/Complicated/File: Added. 77 78 2010-03-25 Adam Barth <abarth (at] webkit.org> 79 80 Reviewed by Eric Seidel. 81 82 Filler change. 83 """ 84 85 class CommitMessageForThisCommitTest(unittest.TestCase): 86 expected_commit_message = u"""2010-03-25 Tor Arne Vestb\u00f8 <vestbo (at] webkit.org> 87 88 Unreviewed build fix to un-break webkit-patch land. 89 90 Move commit_message_for_this_commit from scm to checkout 91 https://bugs.webkit.org/show_bug.cgi?id=36629 92 93 * Scripts/webkitpy/common/checkout/api.py: import scm.CommitMessage 94 2010-03-25 Tor Arne Vestb\u00f8 <vestbo (at] webkit.org> 95 96 Unreviewed build fix to un-break webkit-patch land. 97 98 Second part of this complicated change. 99 100 * Path/To/Complicated/File: Added. 101 """ 102 103 def setUp(self): 104 self.temp_dir = tempfile.mkdtemp(suffix="changelogs") 105 self.old_cwd = os.getcwd() 106 os.chdir(self.temp_dir) 107 write_into_file_at_path("ChangeLog1", _changelog1) 108 write_into_file_at_path("ChangeLog2", _changelog2) 109 110 def tearDown(self): 111 shutil.rmtree(self.temp_dir, ignore_errors=True) 112 os.chdir(self.old_cwd) 113 114 # FIXME: This should not need to touch the file system, however 115 # ChangeLog is difficult to mock at current. 116 def test_commit_message_for_this_commit(self): 117 checkout = Checkout(None) 118 checkout.modified_changelogs = lambda git_commit, changed_files=None: ["ChangeLog1", "ChangeLog2"] 119 output = OutputCapture() 120 expected_stderr = "Parsing ChangeLog: ChangeLog1\nParsing ChangeLog: ChangeLog2\n" 121 commit_message = output.assert_outputs(self, checkout.commit_message_for_this_commit, 122 kwargs={"git_commit": None}, expected_stderr=expected_stderr) 123 self.assertEqual(commit_message.message(), self.expected_commit_message) 124 125 126 class CheckoutTest(unittest.TestCase): 127 def test_latest_entry_for_changelog_at_revision(self): 128 scm = Mock() 129 def mock_contents_at_revision(changelog_path, revision): 130 self.assertEqual(changelog_path, "foo") 131 self.assertEqual(revision, "bar") 132 # contents_at_revision is expected to return a byte array (str) 133 # so we encode our unicode ChangeLog down to a utf-8 stream. 134 # The ChangeLog utf-8 decoding should ignore invalid codepoints. 135 invalid_utf8 = "\255" 136 return _changelog1.encode("utf-8") + invalid_utf8 137 scm.contents_at_revision = mock_contents_at_revision 138 checkout = Checkout(scm) 139 entry = checkout._latest_entry_for_changelog_at_revision("foo", "bar") 140 self.assertEqual(entry.contents(), _changelog1entry1) 141 142 # FIXME: This tests a hack around our current changed_files handling. 143 # Right now changelog_entries_for_revision tries to fetch deleted files 144 # from revisions, resulting in a ScriptError exception. Test that we 145 # recover from those and still return the other ChangeLog entries. 146 def test_changelog_entries_for_revision(self): 147 scm = Mock() 148 scm.changed_files_for_revision = lambda revision: ['foo/ChangeLog', 'bar/ChangeLog'] 149 checkout = Checkout(scm) 150 151 def mock_latest_entry_for_changelog_at_revision(path, revision): 152 if path == "foo/ChangeLog": 153 return 'foo' 154 raise ScriptError() 155 156 checkout._latest_entry_for_changelog_at_revision = mock_latest_entry_for_changelog_at_revision 157 158 # Even though fetching one of the entries failed, the other should succeed. 159 entries = checkout.changelog_entries_for_revision(1) 160 self.assertEqual(len(entries), 1) 161 self.assertEqual(entries[0], 'foo') 162 163 def test_commit_info_for_revision(self): 164 scm = Mock() 165 scm.committer_email_for_revision = lambda revision: "committer (at] example.com" 166 checkout = Checkout(scm) 167 checkout.changelog_entries_for_revision = lambda revision: [ChangeLogEntry(_changelog1entry1)] 168 commitinfo = checkout.commit_info_for_revision(4) 169 self.assertEqual(commitinfo.bug_id(), 36629) 170 self.assertEqual(commitinfo.author_name(), u"Tor Arne Vestb\u00f8") 171 self.assertEqual(commitinfo.author_email(), "vestbo (at] webkit.org") 172 self.assertEqual(commitinfo.reviewer_text(), None) 173 self.assertEqual(commitinfo.reviewer(), None) 174 self.assertEqual(commitinfo.committer_email(), "committer (at] example.com") 175 self.assertEqual(commitinfo.committer(), None) 176 177 checkout.changelog_entries_for_revision = lambda revision: [] 178 self.assertEqual(checkout.commit_info_for_revision(1), None) 179 180 def test_bug_id_for_revision(self): 181 scm = Mock() 182 scm.committer_email_for_revision = lambda revision: "committer (at] example.com" 183 checkout = Checkout(scm) 184 checkout.changelog_entries_for_revision = lambda revision: [ChangeLogEntry(_changelog1entry1)] 185 self.assertEqual(checkout.bug_id_for_revision(4), 36629) 186 187 def test_bug_id_for_this_commit(self): 188 scm = Mock() 189 checkout = Checkout(scm) 190 checkout.commit_message_for_this_commit = lambda git_commit, changed_files=None: CommitMessage(ChangeLogEntry(_changelog1entry1).contents().splitlines()) 191 self.assertEqual(checkout.bug_id_for_this_commit(git_commit=None), 36629) 192 193 def test_modified_changelogs(self): 194 scm = Mock() 195 scm.checkout_root = "/foo/bar" 196 scm.changed_files = lambda git_commit: ["file1", "ChangeLog", "relative/path/ChangeLog"] 197 checkout = Checkout(scm) 198 expected_changlogs = ["/foo/bar/ChangeLog", "/foo/bar/relative/path/ChangeLog"] 199 self.assertEqual(checkout.modified_changelogs(git_commit=None), expected_changlogs) 200 201 def test_suggested_reviewers(self): 202 def mock_changelog_entries_for_revision(revision): 203 if revision % 2 == 0: 204 return [ChangeLogEntry(_changelog1entry1)] 205 return [ChangeLogEntry(_changelog1entry2)] 206 207 def mock_revisions_changing_file(path, limit=5): 208 if path.endswith("ChangeLog"): 209 return [3] 210 return [4, 8] 211 212 scm = Mock() 213 scm.checkout_root = "/foo/bar" 214 scm.changed_files = lambda git_commit: ["file1", "file2", "relative/path/ChangeLog"] 215 scm.revisions_changing_file = mock_revisions_changing_file 216 checkout = Checkout(scm) 217 checkout.changelog_entries_for_revision = mock_changelog_entries_for_revision 218 reviewers = checkout.suggested_reviewers(git_commit=None) 219 reviewer_names = [reviewer.full_name for reviewer in reviewers] 220 self.assertEqual(reviewer_names, [u'Tor Arne Vestb\xf8']) 221