OLD | NEW |
---|---|
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Unit tests for presubmit_support.py and presubmit_canned_checks.py.""" | 6 """Unit tests for presubmit_support.py and presubmit_canned_checks.py.""" |
7 | 7 |
8 import os | 8 import exceptions |
9 import StringIO | 9 import StringIO |
10 import sys | |
11 import unittest | 10 import unittest |
12 | 11 |
13 # Local imports | 12 # Local imports |
14 import __init__ | 13 import __init__ |
15 import gcl | |
16 import gclient | |
17 import presubmit_support as presubmit | 14 import presubmit_support as presubmit |
18 import presubmit_canned_checks | 15 import presubmit_canned_checks |
19 mox = __init__.mox | 16 mox = __init__.mox |
20 | 17 |
21 | 18 |
22 class PresubmitTestsBase(mox.MoxTestBase): | 19 class PresubmitTestsBase(mox.MoxTestBase): |
23 """Setups and tear downs the mocks but doesn't test anything as-is.""" | 20 """Setups and tear downs the mocks but doesn't test anything as-is.""" |
24 def setUp(self): | 21 presubmit_text = """ |
25 super(PresubmitTestsBase, self).setUp() | |
26 self.mox.StubOutWithMock(presubmit, 'warnings') | |
27 self.original_IsFile = os.path.isfile | |
28 def MockIsFile(f): | |
29 dir = os.path.dirname(f) | |
30 return dir.endswith('haspresubmit') or dir == '' | |
31 os.path.isfile = MockIsFile | |
32 | |
33 self.original_CaptureSVNInfo = gclient.CaptureSVNInfo | |
34 def MockCaptureSVNInfo(path): | |
35 if path.count('notfound'): | |
36 return {} | |
37 results = { | |
38 'Path': path[len('svn:/foo/'):], | |
39 'URL': 'svn:/foo/%s' % path.replace('\\', '/'), | |
40 } | |
41 if path.endswith('isdir'): | |
42 results['Node Kind'] = 'directory' | |
43 else: | |
44 results['Node Kind'] = 'file' | |
45 return results | |
46 gclient.CaptureSVNInfo = MockCaptureSVNInfo | |
47 | |
48 self.original_GetSVNFileProperty = gcl.GetSVNFileProperty | |
49 def MockGetSVNFileProperty(path, property_name): | |
50 if property_name == 'svn:secret-property': | |
51 return 'secret-property-value' | |
52 elif path.count('binary'): | |
53 return 'application/octet-stream' | |
54 else: | |
55 if len(path) % 2: | |
56 return 'text/plain' | |
57 else: | |
58 return '' | |
59 gcl.GetSVNFileProperty = MockGetSVNFileProperty | |
60 | |
61 self.original_ReadFile = gcl.ReadFile | |
62 def MockReadFile(path, dummy='r'): | |
63 if path.count('nosuchfile'): | |
64 return None | |
65 elif path.endswith('isdir'): | |
66 self.fail('Should not attempt to read file that is directory.') | |
67 elif path.endswith('PRESUBMIT.py'): | |
68 # used in testDoPresubmitChecks | |
69 return """ | |
70 def CheckChangeOnUpload(input_api, output_api): | 22 def CheckChangeOnUpload(input_api, output_api): |
71 if not input_api.change.NOSUCHKEY: | 23 if not input_api.change.NOSUCHKEY: |
72 return [output_api.PresubmitError("!!")] | 24 return [output_api.PresubmitError("!!")] |
73 elif not input_api.change.REALLYNOSUCHKEY: | 25 elif not input_api.change.REALLYNOSUCHKEY: |
74 return [output_api.PresubmitPromptWarning("??")] | 26 return [output_api.PresubmitPromptWarning("??")] |
75 elif not input_api.change.REALLYABSOLUTELYNOSUCHKEY: | 27 elif not input_api.change.REALLYABSOLUTELYNOSUCHKEY: |
76 return [output_api.PresubmitPromptWarning("??"), | 28 return [output_api.PresubmitPromptWarning("??"), |
77 output_api.PresubmitError("XX!!XX")] | 29 output_api.PresubmitError("XX!!XX")] |
78 else: | 30 else: |
79 return () | 31 return () |
80 """ | 32 """ |
81 else: | |
82 return 'one:%s\r\ntwo:%s' % (path, path) | |
83 gcl.ReadFile = MockReadFile | |
84 | 33 |
85 self.original_GetRepositoryRoot = gcl.GetRepositoryRoot | 34 def setUp(self): |
35 mox.MoxTestBase.setUp(self) | |
36 self.mox.StubOutWithMock(presubmit, 'warnings') | |
37 # Stub out 'os' but keep os.path.join(). | |
Jói Sigurðsson
2009/05/30 12:06:45
maybe update the comment since you're keeping more
| |
38 path_join = presubmit.os.path.join | |
39 path_dirname = presubmit.os.path.dirname | |
40 path_normpath = presubmit.os.path.normpath | |
41 self.mox.StubOutWithMock(presubmit, 'os') | |
42 self.mox.StubOutWithMock(presubmit.os, 'path') | |
43 presubmit.os.path.join = path_join | |
44 presubmit.os.path.dirname = path_dirname | |
45 presubmit.os.path.normpath = path_normpath | |
46 self.mox.StubOutWithMock(presubmit, 'sys') | |
47 # Special mock. | |
48 def MockAbsPath(f): | |
49 return f | |
50 presubmit.os.path.abspath = MockAbsPath | |
51 self.mox.StubOutWithMock(presubmit.gcl, 'GetRepositoryRoot') | |
86 def MockGetRepositoryRoot(): | 52 def MockGetRepositoryRoot(): |
87 return '' | 53 return '' |
88 gcl.GetRepositoryRoot = MockGetRepositoryRoot | 54 presubmit.gcl.GetRepositoryRoot = MockGetRepositoryRoot |
89 self._sys_stdout = sys.stdout | 55 self.mox.StubOutWithMock(presubmit.gclient, 'CaptureSVNInfo') |
90 sys.stdout = StringIO.StringIO() | 56 self.mox.StubOutWithMock(presubmit.gcl, 'GetSVNFileProperty') |
91 self._os_path_exists = os.path.exists | 57 self.mox.StubOutWithMock(presubmit.gcl, 'ReadFile') |
92 os.path.exists = self.mox.CreateMockAnything() | |
93 self._os_path_isdir = os.path.isdir | |
94 os.path.isdir = self.mox.CreateMockAnything() | |
95 | |
96 def tearDown(self): | |
97 os.path.isfile = self.original_IsFile | |
98 gclient.CaptureSVNInfo = self.original_CaptureSVNInfo | |
99 gcl.GetSVNFileProperty = self.original_GetSVNFileProperty | |
100 gcl.ReadFile = self.original_ReadFile | |
101 gcl.GetRepositoryRoot = self.original_GetRepositoryRoot | |
102 sys.stdout = self._sys_stdout | |
103 os.path.exists = self._os_path_exists | |
104 os.path.isdir = self._os_path_isdir | |
105 | 58 |
106 @staticmethod | 59 @staticmethod |
107 def MakeBasicChange(name, description): | 60 def MakeBasicChange(name, description): |
108 ci = gcl.ChangeInfo(name=name, | 61 ci = presubmit.gcl.ChangeInfo(name=name, description=description) |
109 description=description, | |
110 files=[]) | |
111 change = presubmit.GclChange(ci) | 62 change = presubmit.GclChange(ci) |
112 return change | 63 return change |
113 | 64 |
114 def compareMembers(self, object, members): | 65 def compareMembers(self, object, members): |
115 """If you add a member, be sure to add the relevant test!""" | 66 """If you add a member, be sure to add the relevant test!""" |
116 # Skip over members starting with '_' since they are usually not meant to | 67 # Skip over members starting with '_' since they are usually not meant to |
117 # be for public use. | 68 # be for public use. |
118 actual_members = [x for x in sorted(dir(object)) | 69 actual_members = [x for x in sorted(dir(object)) |
119 if not x.startswith('_')] | 70 if not x.startswith('_')] |
120 self.assertEqual(actual_members, sorted(members)) | 71 self.assertEqual(actual_members, sorted(members)) |
121 | 72 |
122 | 73 |
123 class PresubmitUnittest(PresubmitTestsBase): | 74 class PresubmitUnittest(PresubmitTestsBase): |
124 """General presubmit_support.py tests (excluding InputApi and OutputApi).""" | 75 """General presubmit_support.py tests (excluding InputApi and OutputApi).""" |
125 def testMembersChanged(self): | 76 def testMembersChanged(self): |
126 members = [ | 77 members = [ |
127 'AffectedFile', 'DoPresubmitChecks', 'GclChange', 'InputApi', | 78 'AffectedFile', 'DoPresubmitChecks', 'GclChange', 'InputApi', |
128 'ListRelevantPresubmitFiles', 'Main', 'NotImplementedException', | 79 'ListRelevantPresubmitFiles', 'Main', 'NotImplementedException', |
129 'OutputApi', 'ParseFiles', 'PresubmitExecuter', | 80 'OutputApi', 'ParseFiles', 'PresubmitExecuter', |
130 'ScanSubDirs', 'SvnAffectedFile', | 81 'ScanSubDirs', 'SvnAffectedFile', |
131 'cPickle', 'cStringIO', 'deprecated', 'exceptions', | 82 'cPickle', 'cStringIO', 'deprecated', 'exceptions', |
132 'fnmatch', 'gcl', 'gclient', 'glob', 'marshal', 'normpath', 'optparse', | 83 'fnmatch', 'gcl', 'gclient', 'glob', 'marshal', 'normpath', 'optparse', |
133 'os', 'pickle', 'presubmit_canned_checks', 're', 'subprocess', 'sys', | 84 'os', 'pickle', 'presubmit_canned_checks', 're', 'subprocess', 'sys', |
134 'tempfile', 'types', 'urllib2', 'warnings', | 85 'tempfile', 'types', 'urllib2', 'warnings', |
135 ] | 86 ] |
136 # If this test fails, you should add the relevant test. | 87 # If this test fails, you should add the relevant test. |
137 self.compareMembers(presubmit, members) | 88 self.compareMembers(presubmit, members) |
138 | 89 |
139 def testListRelevantPresubmitFiles(self): | 90 def testListRelevantPresubmitFiles(self): |
91 presubmit.os.path.isfile('PRESUBMIT.py').AndReturn(True) | |
92 presubmit.os.path.isfile( | |
93 presubmit.os.path.join('foo/haspresubmit/yodle', | |
94 'PRESUBMIT.py')).AndReturn(False) | |
95 presubmit.os.path.isfile( | |
96 presubmit.os.path.join('foo/haspresubmit', | |
97 'PRESUBMIT.py')).AndReturn(True) | |
98 presubmit.os.path.isfile( | |
99 presubmit.os.path.join('foo', 'PRESUBMIT.py')).AndReturn(False) | |
100 presubmit.os.path.isfile( | |
101 presubmit.os.path.join('moo/mat/gat', | |
102 'PRESUBMIT.py')).AndReturn(False) | |
103 presubmit.os.path.isfile( | |
104 presubmit.os.path.join('moo/mat', | |
105 'PRESUBMIT.py')).AndReturn(False) | |
106 presubmit.os.path.isfile( | |
107 presubmit.os.path.join('moo', 'PRESUBMIT.py')).AndReturn(False) | |
108 self.mox.ReplayAll() | |
140 presubmit_files = presubmit.ListRelevantPresubmitFiles([ | 109 presubmit_files = presubmit.ListRelevantPresubmitFiles([ |
141 'blat.cc', | 110 'blat.cc', |
142 'foo/haspresubmit/yodle/smart.h', | 111 'foo/haspresubmit/yodle/smart.h', |
143 'moo/mat/gat/yo.h', | 112 'moo/mat/gat/yo.h', |
144 'foo/luck.h']) | 113 'foo/luck.h']) |
145 self.failUnless(len(presubmit_files) == 2) | 114 self.assertEqual(len(presubmit_files), 2) |
146 self.failUnless(presubmit.normpath('PRESUBMIT.py') in presubmit_files) | 115 self.failUnless(presubmit.normpath('PRESUBMIT.py') in presubmit_files) |
147 self.failUnless(presubmit.normpath('foo/haspresubmit/PRESUBMIT.py') in | 116 self.failUnless(presubmit.normpath('foo/haspresubmit/PRESUBMIT.py') in |
148 presubmit_files) | 117 presubmit_files) |
149 | 118 |
150 def testTagLineRe(self): | 119 def testTagLineRe(self): |
151 m = presubmit.GclChange._tag_line_re.match(' BUG =1223, 1445 \t') | 120 m = presubmit.GclChange._tag_line_re.match(' BUG =1223, 1445 \t') |
152 self.failUnless(m) | 121 self.failUnless(m) |
153 self.failUnlessEqual(m.group('key'), 'BUG') | 122 self.failUnlessEqual(m.group('key'), 'BUG') |
154 self.failUnlessEqual(m.group('value'), '1223, 1445') | 123 self.failUnlessEqual(m.group('value'), '1223, 1445') |
155 | 124 |
156 def testGclChange(self): | 125 def testGclChange(self): |
157 description_lines = ('Hello there', | 126 description_lines = ('Hello there', |
158 'this is a change', | 127 'this is a change', |
159 'BUG=123', | 128 'BUG=123', |
160 ' STORY =http://foo/ \t', | 129 ' STORY =http://foo/ \t', |
161 'and some more regular text \t') | 130 'and some more regular text \t') |
162 files = [ | 131 files = [ |
163 ['A', 'foo/blat.cc'], | 132 ['A', 'foo/blat.cc'], |
164 ['M', 'binary.dll'], # a binary file | 133 ['M', 'binary.dll'], # a binary file |
165 ['A', 'isdir'], # a directory | 134 ['A', 'isdir'], # a directory |
166 ['M', 'flop/notfound.txt'], # not found in SVN, still exists locally | 135 ['?', 'flop/notfound.txt'], # not found in SVN, still exists locally |
167 ['D', 'boo/flap.h'], | 136 ['D', 'boo/flap.h'], |
168 ] | 137 ] |
169 os.path.exists(os.path.join('foo', 'blat.cc')).AndReturn(True) | 138 blat = presubmit.os.path.join('foo', 'blat.cc') |
170 os.path.isdir(os.path.join('foo', 'blat.cc')).AndReturn(False) | 139 notfound = presubmit.os.path.join('flop', 'notfound.txt') |
171 os.path.exists('binary.dll').AndReturn(True) | 140 flap = presubmit.os.path.join('boo', 'flap.h') |
172 os.path.isdir('binary.dll').AndReturn(False) | 141 presubmit.os.path.exists(blat).AndReturn(True) |
173 os.path.exists('isdir').AndReturn(True) | 142 presubmit.os.path.isdir(blat).AndReturn(False) |
174 os.path.isdir('isdir').AndReturn(True) | 143 presubmit.os.path.exists('binary.dll').AndReturn(True) |
175 os.path.exists(os.path.join('flop', 'notfound.txt')).AndReturn(False) | 144 presubmit.os.path.isdir('binary.dll').AndReturn(False) |
176 os.path.exists(os.path.join('boo', 'flap.h')).AndReturn(False) | 145 presubmit.os.path.exists('isdir').AndReturn(True) |
146 presubmit.os.path.isdir('isdir').AndReturn(True) | |
147 presubmit.os.path.exists(notfound).AndReturn(True) | |
148 presubmit.os.path.isdir(notfound).AndReturn(False) | |
149 presubmit.os.path.exists(flap).AndReturn(False) | |
150 presubmit.gclient.CaptureSVNInfo(flap | |
151 ).AndReturn({'Node Kind': 'file'}) | |
152 presubmit.gcl.GetSVNFileProperty(blat, 'svn:mime-type').AndReturn(None) | |
153 presubmit.gcl.GetSVNFileProperty( | |
154 'binary.dll', 'svn:mime-type').AndReturn('application/octet-stream') | |
155 presubmit.gcl.GetSVNFileProperty( | |
156 notfound, 'svn:mime-type').AndReturn('') | |
157 presubmit.gclient.CaptureSVNInfo(blat).AndReturn( | |
158 {'URL': 'svn:/foo/foo/blat.cc'}) | |
159 presubmit.gclient.CaptureSVNInfo('binary.dll').AndReturn( | |
160 {'URL': 'svn:/foo/binary.dll'}) | |
161 presubmit.gclient.CaptureSVNInfo(notfound).AndReturn({}) | |
162 presubmit.gclient.CaptureSVNInfo(flap).AndReturn( | |
163 {'URL': 'svn:/foo/boo/flap.h'}) | |
164 presubmit.gcl.ReadFile(blat).AndReturn('boo!\nahh?') | |
165 presubmit.gcl.ReadFile(notfound).AndReturn('look!\nthere?') | |
177 self.mox.ReplayAll() | 166 self.mox.ReplayAll() |
178 ci = gcl.ChangeInfo(name='mychange', | 167 |
179 description='\n'.join(description_lines), | 168 ci = presubmit.gcl.ChangeInfo(name='mychange', |
180 files=files) | 169 description='\n'.join(description_lines), |
170 files=files) | |
181 change = presubmit.GclChange(ci) | 171 change = presubmit.GclChange(ci) |
182 | 172 |
183 self.failUnless(change.Change() == 'mychange') | 173 self.failUnless(change.Change() == 'mychange') |
184 self.failUnless(change.DescriptionText() == | 174 self.failUnless(change.DescriptionText() == |
185 'Hello there\nthis is a change\nand some more regular text') | 175 'Hello there\nthis is a change\nand some more regular text') |
186 self.failUnless(change.FullDescriptionText() == | 176 self.failUnless(change.FullDescriptionText() == |
187 '\n'.join(description_lines)) | 177 '\n'.join(description_lines)) |
188 | 178 |
189 self.failUnless(change.BUG == '123') | 179 self.failUnless(change.BUG == '123') |
190 self.failUnless(change.STORY == 'http://foo/') | 180 self.failUnless(change.STORY == 'http://foo/') |
(...skipping 11 matching lines...) Expand all Loading... | |
202 | 192 |
203 local_paths = change.LocalPaths() | 193 local_paths = change.LocalPaths() |
204 expected_paths = [presubmit.normpath(f[1]) for f in files] | 194 expected_paths = [presubmit.normpath(f[1]) for f in files] |
205 self.failUnless( | 195 self.failUnless( |
206 len(filter(lambda x: x in expected_paths, local_paths)) == 4) | 196 len(filter(lambda x: x in expected_paths, local_paths)) == 4) |
207 | 197 |
208 server_paths = change.ServerPaths() | 198 server_paths = change.ServerPaths() |
209 expected_paths = ['svn:/foo/%s' % f[1] for f in files if | 199 expected_paths = ['svn:/foo/%s' % f[1] for f in files if |
210 f[1] != 'flop/notfound.txt'] | 200 f[1] != 'flop/notfound.txt'] |
211 expected_paths.append('') # one unknown file | 201 expected_paths.append('') # one unknown file |
212 self.failUnless( | 202 self.assertEqual( |
213 len(filter(lambda x: x in expected_paths, server_paths)) == 4) | 203 len(filter(lambda x: x in expected_paths, server_paths)), 4) |
214 | 204 |
215 files = [[x[0], presubmit.normpath(x[1])] for x in files] | 205 files = [[x[0], presubmit.normpath(x[1])] for x in files] |
216 | 206 |
217 rhs_lines = [] | 207 rhs_lines = [] |
218 for line in change.RightHandSideLines(): | 208 for line in change.RightHandSideLines(): |
219 rhs_lines.append(line) | 209 rhs_lines.append(line) |
220 self.failUnless(rhs_lines[0][0].LocalPath() == files[0][1]) | 210 self.assertEquals(rhs_lines[0][0].LocalPath(), files[0][1]) |
221 self.failUnless(rhs_lines[0][1] == 1) | 211 self.assertEquals(rhs_lines[0][1], 1) |
222 self.failUnless(rhs_lines[0][2] == 'one:%s' % files[0][1]) | 212 self.assertEquals(rhs_lines[0][2],'boo!') |
223 | 213 |
224 self.failUnless(rhs_lines[1][0].LocalPath() == files[0][1]) | 214 self.assertEquals(rhs_lines[1][0].LocalPath(), files[0][1]) |
225 self.failUnless(rhs_lines[1][1] == 2) | 215 self.assertEquals(rhs_lines[1][1], 2) |
226 self.failUnless(rhs_lines[1][2] == 'two:%s' % files[0][1]) | 216 self.assertEquals(rhs_lines[1][2], 'ahh?') |
227 | 217 |
228 self.failUnless(rhs_lines[2][0].LocalPath() == files[3][1]) | 218 self.assertEquals(rhs_lines[2][0].LocalPath(), files[3][1]) |
229 self.failUnless(rhs_lines[2][1] == 1) | 219 self.assertEquals(rhs_lines[2][1], 1) |
230 self.failUnless(rhs_lines[2][2] == 'one:%s' % files[3][1]) | 220 self.assertEquals(rhs_lines[2][2], 'look!') |
231 | 221 |
232 self.failUnless(rhs_lines[3][0].LocalPath() == files[3][1]) | 222 self.assertEquals(rhs_lines[3][0].LocalPath(), files[3][1]) |
233 self.failUnless(rhs_lines[3][1] == 2) | 223 self.assertEquals(rhs_lines[3][1], 2) |
234 self.failUnless(rhs_lines[3][2] == 'two:%s' % files[3][1]) | 224 self.assertEquals(rhs_lines[3][2], 'there?') |
235 self.mox.VerifyAll() | |
236 | 225 |
237 def testExecPresubmitScript(self): | 226 def testExecPresubmitScript(self): |
238 description_lines = ('Hello there', | 227 description_lines = ('Hello there', |
239 'this is a change', | 228 'this is a change', |
240 'STORY=http://tracker/123') | 229 'STORY=http://tracker/123') |
241 files = [ | 230 files = [ |
242 ['A', 'foo\\blat.cc'], | 231 ['A', 'foo\\blat.cc'], |
243 ] | 232 ] |
244 ci = gcl.ChangeInfo(name='mychange', | 233 self.mox.ReplayAll() |
245 description='\n'.join(description_lines), | 234 |
246 files=files) | 235 ci = presubmit.gcl.ChangeInfo(name='mychange', |
236 description='\n'.join(description_lines), | |
237 files=files) | |
247 | 238 |
248 executer = presubmit.PresubmitExecuter(ci, False) | 239 executer = presubmit.PresubmitExecuter(ci, False) |
249 self.failIf(executer.ExecPresubmitScript('', 'PRESUBMIT.py')) | 240 self.failIf(executer.ExecPresubmitScript('', 'PRESUBMIT.py')) |
250 # No error if no on-upload entry point | 241 # No error if no on-upload entry point |
251 self.failIf(executer.ExecPresubmitScript( | 242 self.failIf(executer.ExecPresubmitScript( |
252 ('def CheckChangeOnCommit(input_api, output_api):\n' | 243 ('def CheckChangeOnCommit(input_api, output_api):\n' |
253 ' return (output_api.PresubmitError("!!"))\n'), | 244 ' return (output_api.PresubmitError("!!"))\n'), |
254 'PRESUBMIT.py' | 245 'PRESUBMIT.py' |
255 )) | 246 )) |
256 | 247 |
(...skipping 16 matching lines...) Expand all Loading... | |
273 | 264 |
274 self.failUnless(executer.ExecPresubmitScript( | 265 self.failUnless(executer.ExecPresubmitScript( |
275 ('def CheckChangeOnCommit(input_api, output_api):\n' | 266 ('def CheckChangeOnCommit(input_api, output_api):\n' |
276 ' if not input_api.change.NOSUCHKEY:\n' | 267 ' if not input_api.change.NOSUCHKEY:\n' |
277 ' return [output_api.PresubmitError("!!")]\n' | 268 ' return [output_api.PresubmitError("!!")]\n' |
278 ' else:\n' | 269 ' else:\n' |
279 ' return ()'), | 270 ' return ()'), |
280 'PRESUBMIT.py' | 271 'PRESUBMIT.py' |
281 )) | 272 )) |
282 | 273 |
283 try: | 274 self.assertRaises(exceptions.RuntimeError, |
284 executer.ExecPresubmitScript( | 275 executer.ExecPresubmitScript, |
285 ('def CheckChangeOnCommit(input_api, output_api):\n' | 276 'def CheckChangeOnCommit(input_api, output_api):\n' |
286 ' return "foo"'), | 277 ' return "foo"', |
287 'PRESUBMIT.py') | 278 'PRESUBMIT.py') |
288 self.fail() | |
289 except: | |
290 pass # expected case | |
291 | 279 |
292 try: | 280 self.assertRaises(exceptions.RuntimeError, |
293 executer.ExecPresubmitScript( | 281 executer.ExecPresubmitScript, |
294 ('def CheckChangeOnCommit(input_api, output_api):\n' | 282 'def CheckChangeOnCommit(input_api, output_api):\n' |
295 ' return ["foo"]'), | 283 ' return ["foo"]', |
296 'PRESUBMIT.py') | 284 'PRESUBMIT.py') |
297 self.fail() | |
298 except: | |
299 pass # expected case | |
300 | 285 |
301 def testDoPresubmitChecks(self): | 286 def testDoPresubmitChecks(self): |
302 description_lines = ('Hello there', | 287 description_lines = ('Hello there', |
303 'this is a change', | 288 'this is a change', |
304 'STORY=http://tracker/123') | 289 'STORY=http://tracker/123') |
305 files = [ | 290 files = [ |
306 ['A', 'haspresubmit\\blat.cc'], | 291 ['A', 'haspresubmit\\blat.cc'], |
307 ] | 292 ] |
308 ci = gcl.ChangeInfo(name='mychange', | 293 path = presubmit.os.path.join('haspresubmit', 'PRESUBMIT.py') |
309 description='\n'.join(description_lines), | 294 presubmit.os.path.isfile(path).AndReturn(True) |
310 files=files) | 295 presubmit.os.path.isfile('PRESUBMIT.py').AndReturn(True) |
296 presubmit.gcl.ReadFile(path, 'rU').AndReturn(self.presubmit_text) | |
297 presubmit.gcl.ReadFile('PRESUBMIT.py', 'rU').AndReturn(self.presubmit_text) | |
298 self.mox.ReplayAll() | |
299 | |
300 ci = presubmit.gcl.ChangeInfo(name='mychange', | |
301 description='\n'.join(description_lines), | |
302 files=files) | |
311 | 303 |
312 output = StringIO.StringIO() | 304 output = StringIO.StringIO() |
313 input = StringIO.StringIO('y\n') | 305 input = StringIO.StringIO('y\n') |
314 | 306 |
315 self.failIf(presubmit.DoPresubmitChecks(ci, False, True, output, input, | 307 self.failIf(presubmit.DoPresubmitChecks(ci, False, True, output, input, |
316 None)) | 308 None)) |
317 self.assertEqual(output.getvalue().count('!!'), 2) | 309 self.assertEqual(output.getvalue().count('!!'), 2) |
318 | 310 |
319 def testDoPresubmitChecksPromptsAfterWarnings(self): | 311 def testDoPresubmitChecksPromptsAfterWarnings(self): |
320 description_lines = ('Hello there', | 312 description_lines = ('Hello there', |
321 'this is a change', | 313 'this is a change', |
322 'NOSUCHKEY=http://tracker/123') | 314 'NOSUCHKEY=http://tracker/123') |
323 files = [ | 315 files = [ |
324 ['A', 'haspresubmit\\blat.cc'], | 316 ['A', 'haspresubmit\\blat.cc'], |
325 ] | 317 ] |
326 ci = gcl.ChangeInfo(name='mychange', | 318 path = presubmit.os.path.join('haspresubmit', 'PRESUBMIT.py') |
327 description='\n'.join(description_lines), | 319 presubmit.os.path.isfile(path).AndReturn(True) |
328 files=files) | 320 presubmit.os.path.isfile('PRESUBMIT.py').AndReturn(True) |
321 presubmit.gcl.ReadFile(path, 'rU').AndReturn(self.presubmit_text) | |
322 presubmit.gcl.ReadFile('PRESUBMIT.py', 'rU').AndReturn(self.presubmit_text) | |
323 presubmit.os.path.isfile(path).AndReturn(True) | |
324 presubmit.os.path.isfile('PRESUBMIT.py').AndReturn(True) | |
325 presubmit.gcl.ReadFile(path, 'rU').AndReturn(self.presubmit_text) | |
326 presubmit.gcl.ReadFile('PRESUBMIT.py', 'rU').AndReturn(self.presubmit_text) | |
327 self.mox.ReplayAll() | |
328 | |
329 ci = presubmit.gcl.ChangeInfo(name='mychange', | |
330 description='\n'.join(description_lines), | |
331 files=files) | |
329 | 332 |
330 output = StringIO.StringIO() | 333 output = StringIO.StringIO() |
331 input = StringIO.StringIO('n\n') # say no to the warning | 334 input = StringIO.StringIO('n\n') # say no to the warning |
332 | |
333 self.failIf(presubmit.DoPresubmitChecks(ci, False, True, output, input, | 335 self.failIf(presubmit.DoPresubmitChecks(ci, False, True, output, input, |
334 None)) | 336 None)) |
335 self.assertEqual(output.getvalue().count('??'), 2) | 337 self.assertEqual(output.getvalue().count('??'), 2) |
336 | 338 |
337 output = StringIO.StringIO() | 339 output = StringIO.StringIO() |
338 input = StringIO.StringIO('y\n') # say yes to the warning | 340 input = StringIO.StringIO('y\n') # say yes to the warning |
339 | |
340 self.failUnless(presubmit.DoPresubmitChecks(ci, | 341 self.failUnless(presubmit.DoPresubmitChecks(ci, |
341 False, | 342 False, |
342 True, | 343 True, |
343 output, | 344 output, |
344 input, | 345 input, |
345 None)) | 346 None)) |
346 self.failUnless(output.getvalue().count('??')) | 347 self.assertEquals(output.getvalue().count('??'), 2) |
347 | 348 |
348 def testDoPresubmitChecksNoWarningPromptIfErrors(self): | 349 def testDoPresubmitChecksNoWarningPromptIfErrors(self): |
349 description_lines = ('Hello there', | 350 description_lines = ('Hello there', |
350 'this is a change', | 351 'this is a change', |
351 'NOSUCHKEY=http://tracker/123', | 352 'NOSUCHKEY=http://tracker/123', |
352 'REALLYNOSUCHKEY=http://tracker/123') | 353 'REALLYNOSUCHKEY=http://tracker/123') |
353 files = [ | 354 files = [ |
354 ['A', 'haspresubmit\\blat.cc'], | 355 ['A', 'haspresubmit\\blat.cc'], |
355 ] | 356 ] |
356 ci = gcl.ChangeInfo(name='mychange', | 357 path = presubmit.os.path.join('haspresubmit', 'PRESUBMIT.py') |
357 description='\n'.join(description_lines), | 358 presubmit.os.path.isfile(path).AndReturn(True) |
358 files=files) | 359 presubmit.os.path.isfile('PRESUBMIT.py').AndReturn(True) |
360 presubmit.gcl.ReadFile(path, 'rU').AndReturn(self.presubmit_text) | |
361 presubmit.gcl.ReadFile('PRESUBMIT.py', 'rU').AndReturn(self.presubmit_text) | |
362 self.mox.ReplayAll() | |
363 | |
364 ci = presubmit.gcl.ChangeInfo(name='mychange', | |
365 description='\n'.join(description_lines), | |
366 files=files) | |
359 | 367 |
360 output = StringIO.StringIO() | 368 output = StringIO.StringIO() |
361 input = StringIO.StringIO() # should be unused | 369 input = StringIO.StringIO() # should be unused |
362 | 370 |
363 self.failIf(presubmit.DoPresubmitChecks(ci, False, True, output, input, | 371 self.failIf(presubmit.DoPresubmitChecks(ci, False, True, output, input, |
364 None)) | 372 None)) |
365 self.assertEqual(output.getvalue().count('??'), 2) | 373 self.assertEqual(output.getvalue().count('??'), 2) |
366 self.assertEqual(output.getvalue().count('XX!!XX'), 2) | 374 self.assertEqual(output.getvalue().count('XX!!XX'), 2) |
367 self.assertEqual(output.getvalue().count('(y/N)'), 0) | 375 self.assertEqual(output.getvalue().count('(y/N)'), 0) |
368 | 376 |
369 def testDoDefaultPresubmitChecks(self): | 377 def testDoDefaultPresubmitChecks(self): |
370 description_lines = ('Hello there', | 378 description_lines = ('Hello there', |
371 'this is a change', | 379 'this is a change', |
372 'STORY=http://tracker/123') | 380 'STORY=http://tracker/123') |
373 files = [ | 381 files = [ |
374 ['A', 'haspresubmit\\blat.cc'], | 382 ['A', 'haspresubmit\\blat.cc'], |
375 ] | 383 ] |
376 ci = gcl.ChangeInfo(name='mychange', | |
377 description='\n'.join(description_lines), | |
378 files=files) | |
379 | |
380 output = StringIO.StringIO() | |
381 input = StringIO.StringIO('y\n') | |
382 # Always fail. | |
383 DEFAULT_SCRIPT = """ | 384 DEFAULT_SCRIPT = """ |
384 def CheckChangeOnUpload(input_api, output_api): | 385 def CheckChangeOnUpload(input_api, output_api): |
385 print 'This is a test' | |
386 return [output_api.PresubmitError("!!")] | 386 return [output_api.PresubmitError("!!")] |
387 def CheckChangeOnCommit(input_api, output_api): | 387 def CheckChangeOnCommit(input_api, output_api): |
388 raise Exception("Test error") | 388 raise Exception("Test error") |
389 """ | 389 """ |
390 def MockReadFile(dummy): | 390 path = presubmit.os.path.join('haspresubmit', 'PRESUBMIT.py') |
391 return '' | 391 presubmit.os.path.isfile(path).AndReturn(False) |
392 gcl.ReadFile = MockReadFile | 392 presubmit.os.path.isfile('PRESUBMIT.py').AndReturn(False) |
393 def MockIsFile(dummy): | 393 self.mox.ReplayAll() |
394 return False | 394 |
395 os.path.isfile = MockIsFile | 395 ci = presubmit.gcl.ChangeInfo(name='mychange', |
396 description='\n'.join(description_lines), | |
397 files=files) | |
398 | |
399 | |
400 output = StringIO.StringIO() | |
401 input = StringIO.StringIO('y\n') | |
402 # Always fail. | |
396 self.failIf(presubmit.DoPresubmitChecks(ci, False, True, output, input, | 403 self.failIf(presubmit.DoPresubmitChecks(ci, False, True, output, input, |
397 DEFAULT_SCRIPT)) | 404 DEFAULT_SCRIPT)) |
398 self.assertEquals(output.getvalue().count('!!'), 1) | 405 self.assertEquals(output.getvalue().count('!!'), 1) |
399 | 406 |
400 def testDirectoryHandling(self): | 407 def testDirectoryHandling(self): |
401 files = [ | 408 files = [ |
402 ['A', 'isdir'], | 409 ['A', 'isdir'], |
403 ['A', 'isdir\\blat.cc'], | 410 ['A', 'isdir\\blat.cc'], |
404 ] | 411 ] |
405 os.path.exists('isdir').AndReturn(True) | 412 presubmit.os.path.exists('isdir').AndReturn(True) |
406 os.path.isdir('isdir').AndReturn(True) | 413 presubmit.os.path.isdir('isdir').AndReturn(True) |
407 os.path.exists(os.path.join('isdir', 'blat.cc')).AndReturn(True) | 414 presubmit.os.path.exists(presubmit.os.path.join('isdir', 'blat.cc') |
408 os.path.isdir(os.path.join('isdir', 'blat.cc')).AndReturn(False) | 415 ).AndReturn(True) |
416 presubmit.os.path.isdir(presubmit.os.path.join('isdir', 'blat.cc') | |
417 ).AndReturn(False) | |
409 self.mox.ReplayAll() | 418 self.mox.ReplayAll() |
410 ci = gcl.ChangeInfo(name='mychange', | 419 ci = presubmit.gcl.ChangeInfo(name='mychange', |
411 description='foo', | 420 description='foo', |
412 files=files) | 421 files=files) |
413 change = presubmit.GclChange(ci) | 422 change = presubmit.GclChange(ci) |
414 | 423 |
415 affected_files = change.AffectedFiles(include_dirs=False) | 424 affected_files = change.AffectedFiles(include_dirs=False) |
416 self.failUnless(len(affected_files) == 1) | 425 self.failUnless(len(affected_files) == 1) |
417 self.failUnless(affected_files[0].LocalPath().endswith('blat.cc')) | 426 self.failUnless(affected_files[0].LocalPath().endswith('blat.cc')) |
418 self.mox.VerifyAll() | |
419 affected_files_and_dirs = change.AffectedFiles(include_dirs=True) | 427 affected_files_and_dirs = change.AffectedFiles(include_dirs=True) |
420 self.failUnless(len(affected_files_and_dirs) == 2) | 428 self.failUnless(len(affected_files_and_dirs) == 2) |
421 | 429 |
422 def testTags(self): | 430 def testTags(self): |
423 DEFAULT_SCRIPT = """ | 431 DEFAULT_SCRIPT = """ |
424 def CheckChangeOnUpload(input_api, output_api): | 432 def CheckChangeOnUpload(input_api, output_api): |
425 if input_api.change.tags['BUG'] != 'boo': | 433 if input_api.change.tags['BUG'] != 'boo': |
426 return [output_api.PresubmitError('Tag parsing failed. 1')] | 434 return [output_api.PresubmitError('Tag parsing failed. 1')] |
427 if input_api.change.tags['STORY'] != 'http://tracker.com/42': | 435 if input_api.change.tags['STORY'] != 'http://tracker.com/42': |
428 return [output_api.PresubmitError('Tag parsing failed. 2')] | 436 return [output_api.PresubmitError('Tag parsing failed. 2')] |
429 if 'TEST' in input_api.change.tags: | 437 if 'TEST' in input_api.change.tags: |
430 return [output_api.PresubmitError('Tag parsing failed. 3')] | 438 return [output_api.PresubmitError('Tag parsing failed. 3')] |
431 if input_api.change.DescriptionText() != 'Blah Blah': | 439 if input_api.change.DescriptionText() != 'Blah Blah': |
432 return [output_api.PresubmitError('Tag parsing failed. 4 ' + | 440 return [output_api.PresubmitError('Tag parsing failed. 4 ' + |
433 input_api.change.DescriptionText())] | 441 input_api.change.DescriptionText())] |
434 if (input_api.change.FullDescriptionText() != | 442 if (input_api.change.FullDescriptionText() != |
435 'Blah Blah\\n\\nSTORY=http://tracker.com/42\\nBUG=boo\\n'): | 443 'Blah Blah\\n\\nSTORY=http://tracker.com/42\\nBUG=boo\\n'): |
436 return [output_api.PresubmitError('Tag parsing failed. 5 ' + | 444 return [output_api.PresubmitError('Tag parsing failed. 5 ' + |
437 input_api.change.FullDescriptionText())] | 445 input_api.change.FullDescriptionText())] |
438 return [output_api.PresubmitNotifyResult(input_api.change.tags['STORY'])] | 446 return [output_api.PresubmitNotifyResult(input_api.change.tags['STORY'])] |
439 def CheckChangeOnCommit(input_api, output_api): | 447 def CheckChangeOnCommit(input_api, output_api): |
440 raise Exception("Test error") | 448 raise Exception("Test error") |
441 """ | 449 """ |
442 def MockReadFile(dummy): | 450 self.mox.ReplayAll() |
443 return '' | 451 change = presubmit.gcl.ChangeInfo( |
444 gcl.ReadFile = MockReadFile | |
445 def MockIsFile(dummy): | |
446 return False | |
447 os.path.isfile = MockIsFile | |
448 change = gcl.ChangeInfo( | |
449 name='foo', | 452 name='foo', |
450 description="Blah Blah\n\nSTORY=http://tracker.com/42\nBUG=boo\n") | 453 description="Blah Blah\n\nSTORY=http://tracker.com/42\nBUG=boo\n") |
451 output = StringIO.StringIO() | 454 output = StringIO.StringIO() |
452 input = StringIO.StringIO('y\n') | 455 input = StringIO.StringIO('y\n') |
453 self.failUnless(presubmit.DoPresubmitChecks(change, False, True, output, | 456 self.failUnless(presubmit.DoPresubmitChecks(change, False, True, output, |
454 input, DEFAULT_SCRIPT)) | 457 input, DEFAULT_SCRIPT)) |
455 self.assertEquals(output.getvalue(), | 458 self.assertEquals(output.getvalue(), |
456 ('Warning, no presubmit.py found.\n' | 459 ('Warning, no presubmit.py found.\n' |
457 'Running default presubmit script.\n\n' | 460 'Running default presubmit script.\n\n' |
458 '** Presubmit Messages **\n\n' | 461 '** Presubmit Messages **\n\n' |
459 'http://tracker.com/42\n\n')) | 462 'http://tracker.com/42\n\n')) |
460 | 463 |
461 | 464 |
462 class InputApiUnittest(PresubmitTestsBase): | 465 class InputApiUnittest(PresubmitTestsBase): |
463 """Tests presubmit.InputApi.""" | 466 """Tests presubmit.InputApi.""" |
464 def testMembersChanged(self): | 467 def testMembersChanged(self): |
465 members = [ | 468 members = [ |
466 'AbsoluteLocalPaths', 'AffectedFiles', 'AffectedTextFiles', | 469 'AbsoluteLocalPaths', 'AffectedFiles', 'AffectedTextFiles', |
467 'DepotToLocalPath', 'LocalPaths', 'LocalToDepotPath', | 470 'DepotToLocalPath', 'LocalPaths', 'LocalToDepotPath', |
468 'PresubmitLocalPath', 'RightHandSideLines', 'ServerPaths', | 471 'PresubmitLocalPath', 'RightHandSideLines', 'ServerPaths', |
469 'basename', 'cPickle', 'cStringIO', 'canned_checks', 'change', | 472 'basename', 'cPickle', 'cStringIO', 'canned_checks', 'change', |
470 'marshal', 'os_path', 'pickle', 'platform', | 473 'marshal', 'os_path', 'pickle', 'platform', |
471 're', 'subprocess', 'tempfile', 'urllib2', 'version', | 474 're', 'subprocess', 'tempfile', 'urllib2', 'version', |
472 ] | 475 ] |
473 # If this test fails, you should add the relevant test. | 476 # If this test fails, you should add the relevant test. |
474 self.compareMembers(presubmit.InputApi(None, './.'), members) | 477 self.compareMembers(presubmit.InputApi(None, './.'), members) |
475 | 478 |
476 def testDepotToLocalPath(self): | 479 def testDepotToLocalPath(self): |
477 path = presubmit.InputApi(None, './p').DepotToLocalPath('svn:/foo/smurf') | 480 presubmit.gclient.CaptureSVNInfo('svn://foo/smurf').AndReturn( |
478 self.failUnless(path == 'smurf') | 481 {'Path': 'prout'}) |
482 presubmit.gclient.CaptureSVNInfo('svn:/foo/notfound/burp').AndReturn({}) | |
483 self.mox.ReplayAll() | |
484 path = presubmit.InputApi(None, './p').DepotToLocalPath('svn://foo/smurf') | |
485 self.failUnless(path == 'prout') | |
479 path = presubmit.InputApi(None, './p').DepotToLocalPath( | 486 path = presubmit.InputApi(None, './p').DepotToLocalPath( |
480 'svn:/foo/notfound/burp') | 487 'svn:/foo/notfound/burp') |
481 self.failUnless(path == None) | 488 self.failUnless(path == None) |
482 | 489 |
483 def testLocalToDepotPath(self): | 490 def testLocalToDepotPath(self): |
491 presubmit.gclient.CaptureSVNInfo('smurf').AndReturn({'URL': 'svn://foo'}) | |
492 presubmit.gclient.CaptureSVNInfo('notfound-food').AndReturn({}) | |
493 self.mox.ReplayAll() | |
484 path = presubmit.InputApi(None, './p').LocalToDepotPath('smurf') | 494 path = presubmit.InputApi(None, './p').LocalToDepotPath('smurf') |
485 self.failUnless(path == 'svn:/foo/smurf') | 495 self.assertEqual(path, 'svn://foo') |
486 path = presubmit.InputApi(None, './p').LocalToDepotPath('notfound-food') | 496 path = presubmit.InputApi(None, './p').LocalToDepotPath('notfound-food') |
487 self.failUnless(path == None) | 497 self.failUnless(path == None) |
488 | 498 |
489 def testInputApiConstruction(self): | 499 def testInputApiConstruction(self): |
490 # Fudge the change object, it's not used during construction anyway | 500 # Fudge the change object, it's not used during construction anyway |
491 api = presubmit.InputApi(change=42, presubmit_path='foo/path/PRESUBMIT.py') | 501 api = presubmit.InputApi(change=42, presubmit_path='foo/path/PRESUBMIT.py') |
492 self.failUnless(api.PresubmitLocalPath() == 'foo/path') | 502 self.failUnless(api.PresubmitLocalPath() == 'foo/path') |
493 self.failUnless(api.change == 42) | 503 self.failUnless(api.change == 42) |
494 | 504 |
495 def testInputApiPresubmitScriptFiltering(self): | 505 def testInputApiPresubmitScriptFiltering(self): |
496 description_lines = ('Hello there', | 506 description_lines = ('Hello there', |
497 'this is a change', | 507 'this is a change', |
498 'BUG=123', | 508 'BUG=123', |
499 ' STORY =http://foo/ \t', | 509 ' STORY =http://foo/ \t', |
500 'and some more regular text') | 510 'and some more regular text') |
501 files = [ | 511 files = [ |
502 ['A', os.path.join('foo', 'blat.cc')], | 512 ['A', presubmit.os.path.join('foo', 'blat.cc')], |
503 ['M', os.path.join('foo', 'blat', 'binary.dll')], | 513 ['M', presubmit.os.path.join('foo', 'blat', 'binary.dll')], |
504 ['D', 'foo/mat/beingdeleted.txt'], | 514 ['D', 'foo/mat/beingdeleted.txt'], |
505 ['M', 'flop/notfound.txt'], | 515 ['M', 'flop/notfound.txt'], |
506 ['A', 'boo/flap.h'], | 516 ['A', 'boo/flap.h'], |
507 ] | 517 ] |
508 | 518 |
509 os.path.exists(os.path.join('foo', 'blat.cc')).AndReturn(True) | 519 blat = presubmit.os.path.join('foo', 'blat.cc') |
510 os.path.isdir(os.path.join('foo', 'blat.cc')).AndReturn(False) | 520 binary = presubmit.os.path.join('foo', 'blat', 'binary.dll') |
511 os.path.exists(os.path.join('foo', 'blat', 'binary.dll')).AndReturn(True) | 521 beingdeleted = presubmit.os.path.join('foo', 'mat', 'beingdeleted.txt') |
512 os.path.isdir(os.path.join('foo', 'blat', 'binary.dll')).AndReturn(False) | 522 notfound = presubmit.os.path.join('flop', 'notfound.txt') |
513 os.path.exists(os.path.join('foo', 'mat', 'beingdeleted.txt')).AndReturn( | 523 flap = presubmit.os.path.join('boo', 'flap.h') |
514 False) | 524 presubmit.os.path.exists(blat).AndReturn(True) |
515 os.path.exists(os.path.join('flop', 'notfound.txt')).AndReturn(False) | 525 presubmit.os.path.isdir(blat).AndReturn(False) |
516 os.path.exists(os.path.join('boo', 'flap.h')).AndReturn(True) | 526 presubmit.os.path.exists(binary).AndReturn(True) |
517 os.path.isdir(os.path.join('boo', 'flap.h')).AndReturn(False) | 527 presubmit.os.path.isdir(binary).AndReturn(False) |
528 presubmit.os.path.exists(beingdeleted).AndReturn(False) | |
529 presubmit.os.path.exists(notfound).AndReturn(False) | |
530 presubmit.os.path.exists(flap).AndReturn(True) | |
531 presubmit.os.path.isdir(flap).AndReturn(False) | |
532 presubmit.gclient.CaptureSVNInfo(beingdeleted).AndReturn({}) | |
533 presubmit.gclient.CaptureSVNInfo(notfound).AndReturn({}) | |
534 presubmit.gcl.GetSVNFileProperty(blat, 'svn:mime-type').AndReturn(None) | |
535 presubmit.gcl.GetSVNFileProperty(binary, 'svn:mime-type').AndReturn( | |
536 'application/octet-stream') | |
537 presubmit.gcl.ReadFile(blat).AndReturn('whatever\ncookie') | |
518 self.mox.ReplayAll() | 538 self.mox.ReplayAll() |
519 ci = gcl.ChangeInfo(name='mychange', | 539 |
520 description='\n'.join(description_lines), | 540 ci = presubmit.gcl.ChangeInfo(name='mychange', |
521 files=files) | 541 description='\n'.join(description_lines), |
542 files=files) | |
522 change = presubmit.GclChange(ci) | 543 change = presubmit.GclChange(ci) |
523 | 544 |
524 api = presubmit.InputApi(change, 'foo/PRESUBMIT.py') | 545 api = presubmit.InputApi(change, 'foo/PRESUBMIT.py') |
525 | 546 |
526 affected_files = api.AffectedFiles() | 547 affected_files = api.AffectedFiles() |
527 self.assertEquals(len(affected_files), 3) | 548 self.assertEquals(len(affected_files), 3) |
528 self.assertEquals(affected_files[0].LocalPath(), | 549 self.assertEquals(affected_files[0].LocalPath(), |
529 presubmit.normpath('foo/blat.cc')) | 550 presubmit.normpath('foo/blat.cc')) |
530 self.assertEquals(affected_files[1].LocalPath(), | 551 self.assertEquals(affected_files[1].LocalPath(), |
531 presubmit.normpath('foo/blat/binary.dll')) | 552 presubmit.normpath('foo/blat/binary.dll')) |
532 self.assertEquals(affected_files[2].LocalPath(), | 553 self.assertEquals(affected_files[2].LocalPath(), |
533 presubmit.normpath('foo/mat/beingdeleted.txt')) | 554 presubmit.normpath('foo/mat/beingdeleted.txt')) |
534 | 555 |
535 rhs_lines = [] | 556 rhs_lines = [] |
536 for line in api.RightHandSideLines(): | 557 for line in api.RightHandSideLines(): |
537 rhs_lines.append(line) | 558 rhs_lines.append(line) |
538 self.failUnless(len(rhs_lines) == 2) | 559 self.assertEquals(len(rhs_lines), 2) |
539 self.assertEqual(rhs_lines[0][0].LocalPath(), | 560 self.assertEqual(rhs_lines[0][0].LocalPath(), |
540 presubmit.normpath('foo/blat.cc')) | 561 presubmit.normpath('foo/blat.cc')) |
541 self.mox.VerifyAll() | |
542 | 562 |
543 def testGetAbsoluteLocalPath(self): | 563 def testGetAbsoluteLocalPath(self): |
544 # Regression test for bug of presubmit stuff that relies on invoking | 564 # Regression test for bug of presubmit stuff that relies on invoking |
545 # SVN (e.g. to get mime type of file) not working unless gcl invoked | 565 # SVN (e.g. to get mime type of file) not working unless gcl invoked |
546 # from the client root (e.g. if you were at 'src' and did 'cd base' before | 566 # from the client root (e.g. if you were at 'src' and did 'cd base' before |
547 # invoking 'gcl upload' it would fail because svn wouldn't find the files | 567 # invoking 'gcl upload' it would fail because svn wouldn't find the files |
548 # the presubmit script was asking about). | 568 # the presubmit script was asking about). |
549 files = [ | 569 files = [ |
550 ['A', 'isdir'], | 570 ['A', 'isdir'], |
551 ['A', os.path.join('isdir', 'blat.cc')] | 571 ['A', presubmit.os.path.join('isdir', 'blat.cc')] |
552 ] | 572 ] |
553 ci = gcl.ChangeInfo(name='mychange', | 573 ci = presubmit.gcl.ChangeInfo(name='mychange', |
554 description='', | 574 description='', |
555 files=files) | 575 files=files) |
556 # It doesn't make sense on non-Windows platform. This is somewhat hacky, | 576 # It doesn't make sense on non-Windows platform. This is somewhat hacky, |
557 # but it is needed since we can't just use os.path.join('c:', 'temp'). | 577 # but it is needed since we can't just use os.path.join('c:', 'temp'). |
558 change = presubmit.GclChange(ci, 'c:' + os.sep + 'temp') | 578 change = presubmit.GclChange(ci, 'c:' + presubmit.os.sep + 'temp') |
559 affected_files = change.AffectedFiles(include_dirs=True) | 579 affected_files = change.AffectedFiles(include_dirs=True) |
560 # Local paths should remain the same | 580 # Local paths should remain the same |
561 self.failUnless(affected_files[0].LocalPath() == | 581 self.failUnless(affected_files[0].LocalPath() == |
562 presubmit.normpath('isdir')) | 582 presubmit.normpath('isdir')) |
563 self.failUnless(affected_files[1].LocalPath() == | 583 self.failUnless(affected_files[1].LocalPath() == |
564 presubmit.normpath('isdir/blat.cc')) | 584 presubmit.normpath('isdir/blat.cc')) |
565 # Absolute paths should be prefixed | 585 # Absolute paths should be prefixed |
566 self.failUnless(affected_files[0].AbsoluteLocalPath() == | 586 self.failUnless(affected_files[0].AbsoluteLocalPath() == |
567 presubmit.normpath('c:/temp/isdir')) | 587 presubmit.normpath('c:/temp/isdir')) |
568 self.failUnless(affected_files[1].AbsoluteLocalPath() == | 588 self.failUnless(affected_files[1].AbsoluteLocalPath() == |
569 presubmit.normpath('c:/temp/isdir/blat.cc')) | 589 presubmit.normpath('c:/temp/isdir/blat.cc')) |
570 | 590 |
571 # New helper functions need to work | 591 # New helper functions need to work |
572 absolute_paths_from_change = change.AbsoluteLocalPaths(include_dirs=True) | 592 absolute_paths_from_change = change.AbsoluteLocalPaths(include_dirs=True) |
573 api = presubmit.InputApi(change=change, presubmit_path='isdir/PRESUBMIT.py') | 593 api = presubmit.InputApi(change=change, |
594 presubmit_path='isdir/PRESUBMIT.py') | |
574 absolute_paths_from_api = api.AbsoluteLocalPaths(include_dirs=True) | 595 absolute_paths_from_api = api.AbsoluteLocalPaths(include_dirs=True) |
575 for absolute_paths in [absolute_paths_from_change, | 596 for absolute_paths in [absolute_paths_from_change, |
576 absolute_paths_from_api]: | 597 absolute_paths_from_api]: |
577 self.failUnless(absolute_paths[0] == presubmit.normpath('c:/temp/isdir')) | 598 self.failUnless(absolute_paths[0] == presubmit.normpath('c:/temp/isdir')) |
578 self.failUnless(absolute_paths[1] == | 599 self.failUnless(absolute_paths[1] == |
579 presubmit.normpath('c:/temp/isdir/blat.cc')) | 600 presubmit.normpath('c:/temp/isdir/blat.cc')) |
580 | 601 |
581 def testDeprecated(self): | 602 def testDeprecated(self): |
582 presubmit.warnings.warn(mox.IgnoreArg(), category=mox.IgnoreArg(), | 603 presubmit.warnings.warn(mox.IgnoreArg(), category=mox.IgnoreArg(), |
583 stacklevel=2) | 604 stacklevel=2) |
584 self.mox.ReplayAll() | 605 self.mox.ReplayAll() |
585 change = presubmit.GclChange(gcl.ChangeInfo(name='mychange', | 606 change = presubmit.GclChange( |
586 description='Bleh\n')) | 607 presubmit.gcl.ChangeInfo(name='mychange', description='Bleh\n')) |
587 api = presubmit.InputApi(change, 'foo/PRESUBMIT.py') | 608 api = presubmit.InputApi(change, 'foo/PRESUBMIT.py') |
588 api.AffectedTextFiles(include_deletes=False) | 609 api.AffectedTextFiles(include_deletes=False) |
589 self.mox.VerifyAll() | |
590 | 610 |
591 | 611 |
592 class OuputApiUnittest(PresubmitTestsBase): | 612 class OuputApiUnittest(PresubmitTestsBase): |
593 """Tests presubmit.OutputApi.""" | 613 """Tests presubmit.OutputApi.""" |
594 def testMembersChanged(self): | 614 def testMembersChanged(self): |
595 members = [ | 615 members = [ |
596 'MailTextResult', 'PresubmitError', 'PresubmitNotifyResult', | 616 'MailTextResult', 'PresubmitError', 'PresubmitNotifyResult', |
597 'PresubmitPromptWarning', 'PresubmitResult', | 617 'PresubmitPromptWarning', 'PresubmitResult', |
598 ] | 618 ] |
599 # If this test fails, you should add the relevant test. | 619 # If this test fails, you should add the relevant test. |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
647 def testMembersChanged(self): | 667 def testMembersChanged(self): |
648 members = [ | 668 members = [ |
649 'AbsoluteLocalPath', 'Action', 'IsDirectory', 'IsTextFile', 'LocalPath', | 669 'AbsoluteLocalPath', 'Action', 'IsDirectory', 'IsTextFile', 'LocalPath', |
650 'NewContents', 'OldContents', 'OldFileTempPath', 'Property', 'ServerPath', | 670 'NewContents', 'OldContents', 'OldFileTempPath', 'Property', 'ServerPath', |
651 ] | 671 ] |
652 # If this test fails, you should add the relevant test. | 672 # If this test fails, you should add the relevant test. |
653 self.compareMembers(presubmit.AffectedFile('a', 'b'), members) | 673 self.compareMembers(presubmit.AffectedFile('a', 'b'), members) |
654 self.compareMembers(presubmit.SvnAffectedFile('a', 'b'), members) | 674 self.compareMembers(presubmit.SvnAffectedFile('a', 'b'), members) |
655 | 675 |
656 def testAffectedFile(self): | 676 def testAffectedFile(self): |
677 path = presubmit.os.path.join('foo', 'blat.cc') | |
678 presubmit.os.path.exists(path).AndReturn(True) | |
679 presubmit.os.path.isdir(path).AndReturn(False) | |
680 presubmit.gcl.ReadFile(path).AndReturn('whatever\ncookie') | |
681 presubmit.gclient.CaptureSVNInfo(path).AndReturn( | |
682 {'URL': 'svn:/foo/foo/blat.cc'}) | |
683 self.mox.ReplayAll() | |
657 af = presubmit.SvnAffectedFile('foo/blat.cc', 'M') | 684 af = presubmit.SvnAffectedFile('foo/blat.cc', 'M') |
658 os.path.exists(os.path.join('foo', 'blat.cc')).AndReturn(False) | |
659 self.mox.ReplayAll() | |
660 self.failUnless(af.ServerPath() == 'svn:/foo/foo/blat.cc') | 685 self.failUnless(af.ServerPath() == 'svn:/foo/foo/blat.cc') |
661 self.failUnless(af.LocalPath() == presubmit.normpath('foo/blat.cc')) | 686 self.failUnless(af.LocalPath() == presubmit.normpath('foo/blat.cc')) |
662 self.failUnless(af.Action() == 'M') | 687 self.failUnless(af.Action() == 'M') |
663 self.failUnless(af.NewContents() == ['one:%s' % af.LocalPath(), | 688 self.assertEquals(af.NewContents(), ['whatever', 'cookie']) |
664 'two:%s' % af.LocalPath()]) | |
665 self.mox.VerifyAll() | |
666 | |
667 af = presubmit.AffectedFile('notfound.cc', 'A') | 689 af = presubmit.AffectedFile('notfound.cc', 'A') |
668 self.failUnless(af.ServerPath() == '') | 690 self.failUnless(af.ServerPath() == '') |
669 | 691 |
670 def testProperty(self): | 692 def testProperty(self): |
693 presubmit.gcl.GetSVNFileProperty('foo.cc', 'svn:secret-property' | |
694 ).AndReturn('secret-property-value') | |
695 self.mox.ReplayAll() | |
671 affected_file = presubmit.SvnAffectedFile('foo.cc', 'A') | 696 affected_file = presubmit.SvnAffectedFile('foo.cc', 'A') |
697 # Verify cache coherency. | |
698 self.failUnless(affected_file.Property('svn:secret-property') == | |
699 'secret-property-value') | |
672 self.failUnless(affected_file.Property('svn:secret-property') == | 700 self.failUnless(affected_file.Property('svn:secret-property') == |
673 'secret-property-value') | 701 'secret-property-value') |
674 | 702 |
675 def testIsDirectoryNotExists(self): | 703 def testIsDirectoryNotExists(self): |
676 os.path.exists('foo.cc').AndReturn(False) | 704 presubmit.os.path.exists('foo.cc').AndReturn(False) |
705 presubmit.gclient.CaptureSVNInfo('foo.cc').AndReturn({}) | |
677 self.mox.ReplayAll() | 706 self.mox.ReplayAll() |
678 affected_file = presubmit.SvnAffectedFile('foo.cc', 'A') | 707 affected_file = presubmit.SvnAffectedFile('foo.cc', 'A') |
679 # Verify cache coherency. | 708 # Verify cache coherency. |
680 self.failIf(affected_file.IsDirectory()) | 709 self.failIf(affected_file.IsDirectory()) |
681 self.failIf(affected_file.IsDirectory()) | 710 self.failIf(affected_file.IsDirectory()) |
682 self.mox.VerifyAll() | |
683 | 711 |
684 def testIsDirectory(self): | 712 def testIsDirectory(self): |
685 os.path.exists('foo.cc').AndReturn(True) | 713 presubmit.os.path.exists('foo.cc').AndReturn(True) |
686 os.path.isdir('foo.cc').AndReturn(True) | 714 presubmit.os.path.isdir('foo.cc').AndReturn(True) |
687 self.mox.ReplayAll() | 715 self.mox.ReplayAll() |
688 affected_file = presubmit.SvnAffectedFile('foo.cc', 'A') | 716 affected_file = presubmit.SvnAffectedFile('foo.cc', 'A') |
689 # Verify cache coherency. | 717 # Verify cache coherency. |
690 self.failUnless(affected_file.IsDirectory()) | 718 self.failUnless(affected_file.IsDirectory()) |
691 self.failUnless(affected_file.IsDirectory()) | 719 self.failUnless(affected_file.IsDirectory()) |
692 self.mox.VerifyAll() | |
693 | 720 |
694 def testIsTextFile(self): | 721 def testIsTextFile(self): |
695 list = [presubmit.SvnAffectedFile('foo/blat.txt', 'M'), | 722 list = [presubmit.SvnAffectedFile('foo/blat.txt', 'M'), |
696 presubmit.SvnAffectedFile('foo/binary.blob', 'M'), | 723 presubmit.SvnAffectedFile('foo/binary.blob', 'M'), |
697 presubmit.SvnAffectedFile('blat/flop.txt', 'D')] | 724 presubmit.SvnAffectedFile('blat/flop.txt', 'D')] |
698 os.path.exists(os.path.join('foo', 'blat.txt')).AndReturn(True) | 725 blat = presubmit.os.path.join('foo', 'blat.txt') |
699 os.path.isdir(os.path.join('foo', 'blat.txt')).AndReturn(False) | 726 blob = presubmit.os.path.join('foo', 'binary.blob') |
700 os.path.exists(os.path.join('foo', 'binary.blob')).AndReturn(True) | 727 presubmit.os.path.exists(blat).AndReturn(True) |
701 os.path.isdir(os.path.join('foo', 'binary.blob')).AndReturn(False) | 728 presubmit.os.path.isdir(blat).AndReturn(False) |
729 presubmit.os.path.exists(blob).AndReturn(True) | |
730 presubmit.os.path.isdir(blob).AndReturn(False) | |
731 presubmit.gcl.GetSVNFileProperty(blat, 'svn:mime-type').AndReturn(None) | |
732 presubmit.gcl.GetSVNFileProperty(blob, 'svn:mime-type' | |
733 ).AndReturn('application/octet-stream') | |
702 self.mox.ReplayAll() | 734 self.mox.ReplayAll() |
703 | 735 |
704 output = filter(lambda x: x.IsTextFile(), list) | 736 output = filter(lambda x: x.IsTextFile(), list) |
705 self.failUnless(len(output) == 1) | 737 self.failUnless(len(output) == 1) |
706 self.failUnless(list[0] == output[0]) | 738 self.failUnless(list[0] == output[0]) |
707 self.mox.VerifyAll() | |
708 | 739 |
709 | 740 |
710 class CannedChecksUnittest(PresubmitTestsBase): | 741 class CannedChecksUnittest(PresubmitTestsBase): |
711 """Tests presubmit_canned_checks.py.""" | 742 """Tests presubmit_canned_checks.py.""" |
712 class MockInputApi(object): | 743 class MockInputApi(object): |
713 class MockUrllib2(object): | 744 class MockUrllib2(object): |
714 class urlopen(object): | 745 class urlopen(object): |
715 def __init__(self, url): | 746 def __init__(self, url): |
716 if url == 'url_to_open': | 747 if url == 'url_to_open': |
717 self.result = '1' | 748 self.result = '1' |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
842 # TODO(maruel): Add real tests. | 873 # TODO(maruel): Add real tests. |
843 self.failIf(presubmit_canned_checks.RunPythonUnitTests( | 874 self.failIf(presubmit_canned_checks.RunPythonUnitTests( |
844 self.MockInputApi(), | 875 self.MockInputApi(), |
845 presubmit.OutputApi, [])) | 876 presubmit.OutputApi, [])) |
846 self.failUnless(presubmit_canned_checks.RunPythonUnitTests( | 877 self.failUnless(presubmit_canned_checks.RunPythonUnitTests( |
847 self.MockInputApi(), | 878 self.MockInputApi(), |
848 presubmit.OutputApi, ['non_existent_module'])) | 879 presubmit.OutputApi, ['non_existent_module'])) |
849 | 880 |
850 if __name__ == '__main__': | 881 if __name__ == '__main__': |
851 unittest.main() | 882 unittest.main() |
OLD | NEW |