Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(101)

Side by Side Diff: tests/presubmit_unittest.py

Issue 115964: Rewrite the presubmit test to be much more hermetic. (Closed)
Patch Set: 80 cols Created 11 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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()
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698