blob: bb510f3388cbdbf0c5cb19f778efb7875fa57cae [file] [log] [blame]
Doug Andersonf0c73952011-01-18 13:46:07 -08001#!/usr/bin/python
2#
Doug Andersone91900d2011-01-26 11:37:17 -08003# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
Doug Andersonf0c73952011-01-18 13:46:07 -08004# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
Doug Andersone91900d2011-01-26 11:37:17 -08007"""Unit tests for main.py."""
Doug Andersonf0c73952011-01-18 13:46:07 -08008
9import doctest
10import os
11import re
12import unittest
13
Doug Andersona9b10902011-02-01 17:54:31 -080014import chromite.lib.cros_build_lib as cros_lib
Doug Andersone91900d2011-01-26 11:37:17 -080015from chromite.lib import text_menu
16from chromite.shell import main
Doug Andersona9b10902011-02-01 17:54:31 -080017from chromite.shell import utils
Doug Andersonf0c73952011-01-18 13:46:07 -080018import mox
19
20
Doug Andersona17e0102011-02-07 13:16:55 -080021# Allow protected access, since we are closely partnered with the
22# code that we're testing...
23#
24# pylint: disable=W0212
25
26# Needed to make pylint not yell so much about mocked out stuff
27# (it yells about AndReturn, MultipleTimes, ...).
28#
29# TODO(dianders): Any better solution than this heavy hammer?
30#
31# pylint: disable=E1101, E1103
32
33# Just being a unittest.TestCase gives us 14 public methods. Unless we
34# disable this, we can only have 6 tests in a TestCase. That's not enough.
35#
36# pylint: disable=R0904
37
38
Doug Andersonf0c73952011-01-18 13:46:07 -080039class _DeathException(Exception):
Doug Andersona9b10902011-02-01 17:54:31 -080040 """A bogus exception used by the mock out of cros_lib.Die."""
Doug Andersonf0c73952011-01-18 13:46:07 -080041 pass
42
43
44class TestFindCommand(unittest.TestCase):
Doug Andersone91900d2011-01-26 11:37:17 -080045 """Test main._FindCommand."""
46 # TODO(dianders): Add a test where I override main._COMMAND_HANDLERS
47 # and main._COMMAND_STRS so that I can test more of _FindCommand().
Doug Andersonf0c73952011-01-18 13:46:07 -080048
49 def setUp(self):
50 """Test initialization."""
51 # Create our mox and stub out function calls used by _FindCommand()...
52 self.mox = mox.Mox()
Doug Andersona9b10902011-02-01 17:54:31 -080053 self.mox.StubOutWithMock(cros_lib, 'Die')
Doug Andersonf0c73952011-01-18 13:46:07 -080054 self.mox.StubOutWithMock(text_menu, 'TextMenu')
55
56 def tearDown(self):
57 """Test cleanup."""
58 # Unset stubs...
59 self.mox.UnsetStubs()
60
61 def testInvalidCommand(self):
Doug Andersona9b10902011-02-01 17:54:31 -080062 """Test that _FindCommand('implode') causes cros_lib.Die()."""
63 # Should be a call to cros_lib.Die. We'll have it fake a _DeathException...
64 cros_lib.Die(mox.IsA(basestring)).AndRaise(_DeathException)
Doug Andersonf0c73952011-01-18 13:46:07 -080065
66 # Run the command and verify proper mocks were called...
67 self.mox.ReplayAll()
Doug Andersone91900d2011-01-26 11:37:17 -080068 self.assertRaises(_DeathException, main._FindCommand, 'implode')
Doug Andersonf0c73952011-01-18 13:46:07 -080069 self.mox.VerifyAll()
70
71 def testBlankCommandWithQuit(self):
72 """Test that _FindCommand('') shows menu, mocking quit.
73
74 This tests the case that the user quit out of the menu without choosing
75 anything.
76 """
77 # Should be one call to TextMenu, which will return None for quit.
78 text_menu.TextMenu(mox.IsA(list),
79 mox.IsA(basestring),
80 menu_width=0).AndReturn(None)
81
82 # Should die in response to the quit.
Doug Andersona9b10902011-02-01 17:54:31 -080083 cros_lib.Die(mox.IsA(basestring)).AndRaise(_DeathException)
Doug Andersonf0c73952011-01-18 13:46:07 -080084
85 # Run the command and verify proper mocks were called...
86 self.mox.ReplayAll()
Doug Andersone91900d2011-01-26 11:37:17 -080087 self.assertRaises(_DeathException, main._FindCommand, '')
Doug Andersonf0c73952011-01-18 13:46:07 -080088 self.mox.VerifyAll()
89
90 def testBlankCommandWithChoice0(self):
91 """Test that _FindCommand('') shows menu, mocking choice 0.
92
93 This tests the case that the user chose choice 0 for the menu.
94 """
95 # Should be one call to TextMenu, which will return item 0.
96 text_menu.TextMenu(mox.IsA(list),
97 mox.IsA(basestring),
98 menu_width=0).AndReturn(0)
99
100 # Run the command and verify proper mocks were called...
101 self.mox.ReplayAll()
Doug Andersone91900d2011-01-26 11:37:17 -0800102 cmd_str = main._FindCommand('')
Doug Andersonf0c73952011-01-18 13:46:07 -0800103 self.mox.VerifyAll()
104
105 self.assertTrue(isinstance(cmd_str, basestring),
106 '_FindCommand should return a string')
107 self.assertTrue(bool(cmd_str),
108 '_FindCommand should not return a blank string')
109
110 def _TestExactCommand(self, cmd_to_find):
111 """Helper for tests that try to find an exact match.
112
113 Args:
114 cmd_to_find: The name of the command to find, like 'Build', ...
115 """
116 # Expect no mocks to be called...
117
118 # Run the command and verify proper mocks were called...
119 self.mox.ReplayAll()
Doug Andersone91900d2011-01-26 11:37:17 -0800120 cmd_str = main._FindCommand(cmd_to_find)
Doug Andersonf0c73952011-01-18 13:46:07 -0800121 self.mox.VerifyAll()
122
123 self.assertEqual(cmd_str, cmd_to_find.lower(),
124 '_FindCommand("%s") should return "%s" back.' %
125 (cmd_to_find, cmd_to_find.lower()))
126
127 def testCaseSensitiveBuild(self):
128 """Test that _FindCommand('build') returns 'build'.
129
130 The command matching should be case sensitive.
131 """
132 self._TestExactCommand('build')
133
134 def testCaseInsensitiveBuild(self):
135 """Test that _FindCommand('BUiLD') returns 'build'.
136
137 The command matching should be case insensitive.
138 """
139 self._TestExactCommand('BUiLD')
140
141 def testShCommand(self):
142 """Test that _FindCommand('sh') returns 'shell'.
143
144 This serves two purposes:
145 1. Test the 'prefix' feature of _FindCommand
146 2. Validate that nobody has introduced another command that starts with
147 'sh', since it's expected that many people will use this to invoke the
148 shell.
149 """
150 # _FindCommand should give us a message that it has interpreted sh as shell.
Doug Andersonf0c73952011-01-18 13:46:07 -0800151
152 # Run the command and verify proper mocks were called...
153 self.mox.ReplayAll()
Doug Andersone91900d2011-01-26 11:37:17 -0800154 cmd_str = main._FindCommand('sh')
Doug Andersonf0c73952011-01-18 13:46:07 -0800155 self.mox.VerifyAll()
156
157 self.assertEqual(cmd_str, 'shell',
158 '_FindCommand("sh") should return "shell" back.')
159
160
161class TestFindSpec(unittest.TestCase):
Doug Andersona9b10902011-02-01 17:54:31 -0800162 """Test utils.FindSpec."""
Doug Andersonf0c73952011-01-18 13:46:07 -0800163
164 def setUp(self):
165 """Test initialization."""
166 # Create our mox and stub out function calls used by _FindSpec()...
167 self.mox = mox.Mox()
168 self.mox.StubOutWithMock(os, 'listdir')
169 self.mox.StubOutWithMock(os.path, 'isfile')
Doug Andersona9b10902011-02-01 17:54:31 -0800170 self.mox.StubOutWithMock(cros_lib, 'Die')
Doug Andersonf0c73952011-01-18 13:46:07 -0800171 self.mox.StubOutWithMock(text_menu, 'TextMenu')
172
173 def tearDown(self):
174 """Test cleanup."""
175 # Unset stubs...
176 self.mox.UnsetStubs()
177
178 def testInvalidSpec(self):
Doug Andersona9b10902011-02-01 17:54:31 -0800179 """Test that _FindSpec('bogusSpec') causes cros_lib.Die()."""
Doug Andersonf0c73952011-01-18 13:46:07 -0800180 # Pass this spec name...
181 spec_name = 'bogusSpec'
182
183 # We'll tell mox to say that these specs exist...
184 dir_list = ['x87-toadstool.spec', 'x87-luigi.SPeC', 'x88-princess.spec',
185 '_default']
186
187 # This spec doesn't represent any full path.
188 os.path.isfile(spec_name).AndReturn(False)
189
190 # This spec isn't found in our search path.
191 os.path.isfile(mox.Regex('^/.*%s.spec$' % spec_name)).MultipleTimes(
192 ).AndReturn(False)
193
194 # Give the fake directory listing...
195 os.listdir(mox.IsA(basestring)).MultipleTimes().AndReturn(dir_list)
196
Doug Andersona9b10902011-02-01 17:54:31 -0800197 # Should be a call to cros_lib.Die. We'll have it fake a _DeathException...
198 cros_lib.Die(mox.IsA(basestring)).AndRaise(_DeathException)
Doug Andersonf0c73952011-01-18 13:46:07 -0800199
200 # Run the command and verify proper mocks were called...
201 self.mox.ReplayAll()
Doug Andersona9b10902011-02-01 17:54:31 -0800202 self.assertRaises(_DeathException, utils.FindSpec, 'bogusSpec')
Doug Andersonf0c73952011-01-18 13:46:07 -0800203 self.mox.VerifyAll()
204
205 def testFullPath(self):
206 """Test that _FindSpec(full_path) returns full_path.
207
208 _FindSpec is defined so that if you pass a full file path to it, it
209 should just return that. It doesn't need to have any special suffix or
210 live in a spec folder.
211 """
212 # Pass this spec name...
213 spec_name = __file__
214
215 # Just say that this is a full path...
216 os.path.isfile(spec_name).AndReturn(True)
217
218 # Run the command and verify proper mocks were called...
219 self.mox.ReplayAll()
Doug Andersona9b10902011-02-01 17:54:31 -0800220 path = utils.FindSpec(spec_name)
Doug Andersonf0c73952011-01-18 13:46:07 -0800221 self.mox.VerifyAll()
222
223 self.assertEqual(path, spec_name,
224 '_FindSpec() should just return param if full path.')
225
226 def testExactSpecName(self):
227 """Test that _FindSpec(exact_spec_name) returns the path for the spec."""
228 # We'll search for this bogus spec; we'll use mox to pretend it exists in
229 # the search path.
230 spec_name = 'y87-luigi'
231
232 # This spec doesn't represent any full path
233 os.path.isfile(spec_name).AndReturn(False)
234
235 # When we look through the search path for this spec (with .spec at
236 # the end), we will consider the spec to be found.
237 os.path.isfile(mox.Regex('^/.*%s.spec$' % spec_name)).AndReturn(True)
238
239 # Run the command and verify proper mocks were called...
240 self.mox.ReplayAll()
Doug Andersona9b10902011-02-01 17:54:31 -0800241 spec_path = utils.FindSpec(spec_name)
Doug Andersonf0c73952011-01-18 13:46:07 -0800242 self.mox.VerifyAll()
243
244 self.assertTrue(re.search('^/.*%s.spec$' % spec_name, spec_path),
245 '_FindSpec() should have returned absolute path for spec.')
246
247 def testUniqueSpecName(self):
248 """Test that _FindSpec(unique_part_name) returns the path for the spec."""
249 # We'll search for this spec. Weird capitalization on purpose to test
250 # case sensitiveness.
251 spec_name = 'ToaDSTooL'
252
253 # We'll tell mox to say that these specs exist in the first directory...
254 dir_list = ['_default',
255 'x87-luigi.spec', 'x87-toadstool.SPeC', 'x88-princess.spec']
256
257 # We expect it to find this spec.
258 expected_result = 'x87-toadstool.SPeC'
259
260 # Self-checks for test code...
261 assert dir_list == sorted(dir_list)
262
263 # This spec doesn't represent any full path.
264 os.path.isfile(spec_name).AndReturn(False)
265
266 # This spec isn't found in our search path.
267 os.path.isfile(mox.Regex('^/.*%s.spec$' % spec_name)).MultipleTimes(
268 ).AndReturn(False)
269
270 # Return our directory listing.
271 # TODO(dianders): How to make first mocked call return dir_list and
272 # subsequent return []
273 os.listdir(mox.IsA(basestring)).AndReturn(dir_list)
274
275 os.path.isfile(mox.Regex('^/.*%s$' % expected_result)).AndReturn(True)
276
277 # Run the command and verify proper mocks were called...
278 self.mox.ReplayAll()
Doug Andersona9b10902011-02-01 17:54:31 -0800279 spec_path = utils.FindSpec(spec_name)
Doug Andersonf0c73952011-01-18 13:46:07 -0800280 self.mox.VerifyAll()
281
282 self.assertTrue(re.search('^/.*%s$' % expected_result, spec_path),
283 '_FindSpec("%s") incorrectly returned "%s".' %
284 (spec_name, spec_path))
285
286 def _TestBlankSpecName(self, menu_return):
287 """Helper for tests passing a blank spec name.
288
289 Args:
290 menu_return: This value is returned by TextMenu. Could be none or an
291 integer index into the dir_list of this function.
292 """
293 # We'll search for this spec.
294 spec_name = ''
295
296 # We'll tell mox to say that these specs exist in the first directory...
297 # ...only valid specs to make it easier to compare things.
298 dir_list = ['x87-luigi.spec', 'x87-toadstool.SPeC', 'x88-princess.spec']
299 num_specs = len(dir_list)
300
301 # Self-checks for test code...
302 assert menu_return < len(dir_list)
303 assert dir_list == sorted(dir_list)
304
305 # This spec doesn't represent any full path.
306 os.path.isfile(spec_name).AndReturn(False)
307
308 # Return our directory listing.
309 # TODO(dianders): How to make first mocked call return dir_list and
310 # subsequent return []
311 os.listdir(mox.IsA(basestring)).AndReturn(dir_list)
312
313 for i in xrange(num_specs):
314 os.path.isfile(mox.Regex('^/.*%s$' % dir_list[i])).AndReturn(True)
315
316 # We expect there to be 1 more item than we passed in, since we account
317 # for 'HOST'.
318 check_num_items_fn = lambda items: len(items) == (num_specs + 1)
319
320 # Add 1 to menu_return, since 'HOST' is first...
321 if menu_return is None:
322 adjusted_menu_return = menu_return
323 else:
324 adjusted_menu_return = menu_return + 1
325
326 # Should be one call to TextMenu, which will return menu_return.
327 text_menu.TextMenu(mox.And(mox.IsA(list), mox.Func(check_num_items_fn)),
328 mox.IsA(basestring)).AndReturn(adjusted_menu_return)
329
330 # Should die in response to the quit if directed to quit.
331 if menu_return is None:
Doug Andersona9b10902011-02-01 17:54:31 -0800332 cros_lib.Die(mox.IsA(basestring)).AndRaise(_DeathException)
Doug Andersonf0c73952011-01-18 13:46:07 -0800333
334 # Run the command and verify proper mocks were called...
335 self.mox.ReplayAll()
336 if menu_return is None:
Doug Andersona9b10902011-02-01 17:54:31 -0800337 self.assertRaises(_DeathException, utils.FindSpec, spec_name)
Doug Andersonf0c73952011-01-18 13:46:07 -0800338 else:
Doug Andersona9b10902011-02-01 17:54:31 -0800339 spec_path = utils.FindSpec(spec_name)
Doug Andersonf0c73952011-01-18 13:46:07 -0800340 self.mox.VerifyAll()
341
342 if menu_return is not None:
343 expected_result = dir_list[menu_return]
344 self.assertTrue(re.search('^/.*%s$' % expected_result, spec_path),
345 '_FindSpec("%s") incorrectly returned "%s".' %
346 (spec_name, spec_path))
347
348 def testBlankSpecNameWithQuit(self):
349 """Test that _FindSpec('') shows menu, mocking quit."""
350 self._TestBlankSpecName(None)
351
352 def testBlankSpecNameWithChoice0(self):
353 """Test that _FindSpec('') shows menu, mocking choice 0."""
354 self._TestBlankSpecName(0)
355
356 def testPartialSpecNameWithChoice0(self):
357 """Test that _FindSpec(non_unique_str) shows menu, mocking choice 0."""
358 # We'll search for this spec.
359 spec_name = 'x87'
360
361 # We'll tell mox to say that these specs exist in the first directory...
362 dir_list = ['_default',
363 'x87-luigi.spec', 'x87-toadstool.SPeC', 'x88-princess.spec']
364
365 # We expect 2 matches and should get back luigi as choice 0.
366 matches = ['x87-luigi.spec', 'x87-toadstool.SPeC']
367 num_match = len(matches)
368 expected_result = 'x87-luigi.spec'
369
370 # Self-checks for test code...
371 assert dir_list == sorted(dir_list)
372
373 # This spec doesn't represent any full path.
374 os.path.isfile(spec_name).AndReturn(False)
375
376 # This spec isn't found in our search path.
377 os.path.isfile(mox.Regex('^/.*%s.spec$' % spec_name)).MultipleTimes(
378 ).AndReturn(False)
379
380 # Return our directory listing.
381 # TODO(dianders): How to make first mocked call return dir_list and
382 # subsequent return []
383 os.listdir(mox.IsA(basestring)).AndReturn(dir_list)
384
385 for i in xrange(num_match):
386 os.path.isfile(mox.Regex('^/.*%s$' % matches[i])).AndReturn(True)
387
388 # Should be one call to TextMenu, which will return 0.
389 text_menu.TextMenu(mox.And(mox.IsA(list),
390 mox.Func(lambda items: len(items) == num_match)),
391 mox.IsA(basestring)).AndReturn(0)
392
393 # Run the command and verify proper mocks were called...
394 self.mox.ReplayAll()
Doug Andersona9b10902011-02-01 17:54:31 -0800395 spec_path = utils.FindSpec(spec_name)
Doug Andersonf0c73952011-01-18 13:46:07 -0800396 self.mox.VerifyAll()
397
398 self.assertTrue(re.search('^/.*%s$' % expected_result, spec_path),
399 '_FindSpec("%s") incorrectly returned "%s".' %
400 (spec_name, spec_path))
401
402
403if __name__ == '__main__':
Doug Andersone91900d2011-01-26 11:37:17 -0800404 doctest.testmod(main)
Doug Andersonf0c73952011-01-18 13:46:07 -0800405 unittest.main()