blob: 4b34db5e50232ed8c0a24529135cf639a861c9d6 [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')
54 self.mox.StubOutWithMock(cros_lib, 'Info')
Doug Andersonf0c73952011-01-18 13:46:07 -080055 self.mox.StubOutWithMock(text_menu, 'TextMenu')
56
57 def tearDown(self):
58 """Test cleanup."""
59 # Unset stubs...
60 self.mox.UnsetStubs()
61
62 def testInvalidCommand(self):
Doug Andersona9b10902011-02-01 17:54:31 -080063 """Test that _FindCommand('implode') causes cros_lib.Die()."""
64 # Should be a call to cros_lib.Die. We'll have it fake a _DeathException...
65 cros_lib.Die(mox.IsA(basestring)).AndRaise(_DeathException)
Doug Andersonf0c73952011-01-18 13:46:07 -080066
67 # Run the command and verify proper mocks were called...
68 self.mox.ReplayAll()
Doug Andersone91900d2011-01-26 11:37:17 -080069 self.assertRaises(_DeathException, main._FindCommand, 'implode')
Doug Andersonf0c73952011-01-18 13:46:07 -080070 self.mox.VerifyAll()
71
72 def testBlankCommandWithQuit(self):
73 """Test that _FindCommand('') shows menu, mocking quit.
74
75 This tests the case that the user quit out of the menu without choosing
76 anything.
77 """
78 # Should be one call to TextMenu, which will return None for quit.
79 text_menu.TextMenu(mox.IsA(list),
80 mox.IsA(basestring),
81 menu_width=0).AndReturn(None)
82
83 # Should die in response to the quit.
Doug Andersona9b10902011-02-01 17:54:31 -080084 cros_lib.Die(mox.IsA(basestring)).AndRaise(_DeathException)
Doug Andersonf0c73952011-01-18 13:46:07 -080085
86 # Run the command and verify proper mocks were called...
87 self.mox.ReplayAll()
Doug Andersone91900d2011-01-26 11:37:17 -080088 self.assertRaises(_DeathException, main._FindCommand, '')
Doug Andersonf0c73952011-01-18 13:46:07 -080089 self.mox.VerifyAll()
90
91 def testBlankCommandWithChoice0(self):
92 """Test that _FindCommand('') shows menu, mocking choice 0.
93
94 This tests the case that the user chose choice 0 for the menu.
95 """
96 # Should be one call to TextMenu, which will return item 0.
97 text_menu.TextMenu(mox.IsA(list),
98 mox.IsA(basestring),
99 menu_width=0).AndReturn(0)
100
101 # Run the command and verify proper mocks were called...
102 self.mox.ReplayAll()
Doug Andersone91900d2011-01-26 11:37:17 -0800103 cmd_str = main._FindCommand('')
Doug Andersonf0c73952011-01-18 13:46:07 -0800104 self.mox.VerifyAll()
105
106 self.assertTrue(isinstance(cmd_str, basestring),
107 '_FindCommand should return a string')
108 self.assertTrue(bool(cmd_str),
109 '_FindCommand should not return a blank string')
110
111 def _TestExactCommand(self, cmd_to_find):
112 """Helper for tests that try to find an exact match.
113
114 Args:
115 cmd_to_find: The name of the command to find, like 'Build', ...
116 """
117 # Expect no mocks to be called...
118
119 # Run the command and verify proper mocks were called...
120 self.mox.ReplayAll()
Doug Andersone91900d2011-01-26 11:37:17 -0800121 cmd_str = main._FindCommand(cmd_to_find)
Doug Andersonf0c73952011-01-18 13:46:07 -0800122 self.mox.VerifyAll()
123
124 self.assertEqual(cmd_str, cmd_to_find.lower(),
125 '_FindCommand("%s") should return "%s" back.' %
126 (cmd_to_find, cmd_to_find.lower()))
127
128 def testCaseSensitiveBuild(self):
129 """Test that _FindCommand('build') returns 'build'.
130
131 The command matching should be case sensitive.
132 """
133 self._TestExactCommand('build')
134
135 def testCaseInsensitiveBuild(self):
136 """Test that _FindCommand('BUiLD') returns 'build'.
137
138 The command matching should be case insensitive.
139 """
140 self._TestExactCommand('BUiLD')
141
142 def testShCommand(self):
143 """Test that _FindCommand('sh') returns 'shell'.
144
145 This serves two purposes:
146 1. Test the 'prefix' feature of _FindCommand
147 2. Validate that nobody has introduced another command that starts with
148 'sh', since it's expected that many people will use this to invoke the
149 shell.
150 """
151 # _FindCommand should give us a message that it has interpreted sh as shell.
Doug Andersona9b10902011-02-01 17:54:31 -0800152 cros_lib.Info(mox.IsA(basestring))
Doug Andersonf0c73952011-01-18 13:46:07 -0800153
154 # Run the command and verify proper mocks were called...
155 self.mox.ReplayAll()
Doug Andersone91900d2011-01-26 11:37:17 -0800156 cmd_str = main._FindCommand('sh')
Doug Andersonf0c73952011-01-18 13:46:07 -0800157 self.mox.VerifyAll()
158
159 self.assertEqual(cmd_str, 'shell',
160 '_FindCommand("sh") should return "shell" back.')
161
162
163class TestFindSpec(unittest.TestCase):
Doug Andersona9b10902011-02-01 17:54:31 -0800164 """Test utils.FindSpec."""
Doug Andersonf0c73952011-01-18 13:46:07 -0800165
166 def setUp(self):
167 """Test initialization."""
168 # Create our mox and stub out function calls used by _FindSpec()...
169 self.mox = mox.Mox()
170 self.mox.StubOutWithMock(os, 'listdir')
171 self.mox.StubOutWithMock(os.path, 'isfile')
Doug Andersona9b10902011-02-01 17:54:31 -0800172 self.mox.StubOutWithMock(cros_lib, 'Die')
173 self.mox.StubOutWithMock(cros_lib, 'Info')
Doug Andersonf0c73952011-01-18 13:46:07 -0800174 self.mox.StubOutWithMock(text_menu, 'TextMenu')
175
176 def tearDown(self):
177 """Test cleanup."""
178 # Unset stubs...
179 self.mox.UnsetStubs()
180
181 def testInvalidSpec(self):
Doug Andersona9b10902011-02-01 17:54:31 -0800182 """Test that _FindSpec('bogusSpec') causes cros_lib.Die()."""
Doug Andersonf0c73952011-01-18 13:46:07 -0800183 # Pass this spec name...
184 spec_name = 'bogusSpec'
185
186 # We'll tell mox to say that these specs exist...
187 dir_list = ['x87-toadstool.spec', 'x87-luigi.SPeC', 'x88-princess.spec',
188 '_default']
189
190 # This spec doesn't represent any full path.
191 os.path.isfile(spec_name).AndReturn(False)
192
193 # This spec isn't found in our search path.
194 os.path.isfile(mox.Regex('^/.*%s.spec$' % spec_name)).MultipleTimes(
195 ).AndReturn(False)
196
197 # Give the fake directory listing...
198 os.listdir(mox.IsA(basestring)).MultipleTimes().AndReturn(dir_list)
199
Doug Andersona9b10902011-02-01 17:54:31 -0800200 # Should be a call to cros_lib.Die. We'll have it fake a _DeathException...
201 cros_lib.Die(mox.IsA(basestring)).AndRaise(_DeathException)
Doug Andersonf0c73952011-01-18 13:46:07 -0800202
203 # Run the command and verify proper mocks were called...
204 self.mox.ReplayAll()
Doug Andersona9b10902011-02-01 17:54:31 -0800205 self.assertRaises(_DeathException, utils.FindSpec, 'bogusSpec')
Doug Andersonf0c73952011-01-18 13:46:07 -0800206 self.mox.VerifyAll()
207
208 def testFullPath(self):
209 """Test that _FindSpec(full_path) returns full_path.
210
211 _FindSpec is defined so that if you pass a full file path to it, it
212 should just return that. It doesn't need to have any special suffix or
213 live in a spec folder.
214 """
215 # Pass this spec name...
216 spec_name = __file__
217
218 # Just say that this is a full path...
219 os.path.isfile(spec_name).AndReturn(True)
220
221 # Run the command and verify proper mocks were called...
222 self.mox.ReplayAll()
Doug Andersona9b10902011-02-01 17:54:31 -0800223 path = utils.FindSpec(spec_name)
Doug Andersonf0c73952011-01-18 13:46:07 -0800224 self.mox.VerifyAll()
225
226 self.assertEqual(path, spec_name,
227 '_FindSpec() should just return param if full path.')
228
229 def testExactSpecName(self):
230 """Test that _FindSpec(exact_spec_name) returns the path for the spec."""
231 # We'll search for this bogus spec; we'll use mox to pretend it exists in
232 # the search path.
233 spec_name = 'y87-luigi'
234
235 # This spec doesn't represent any full path
236 os.path.isfile(spec_name).AndReturn(False)
237
238 # When we look through the search path for this spec (with .spec at
239 # the end), we will consider the spec to be found.
240 os.path.isfile(mox.Regex('^/.*%s.spec$' % spec_name)).AndReturn(True)
241
242 # Run the command and verify proper mocks were called...
243 self.mox.ReplayAll()
Doug Andersona9b10902011-02-01 17:54:31 -0800244 spec_path = utils.FindSpec(spec_name)
Doug Andersonf0c73952011-01-18 13:46:07 -0800245 self.mox.VerifyAll()
246
247 self.assertTrue(re.search('^/.*%s.spec$' % spec_name, spec_path),
248 '_FindSpec() should have returned absolute path for spec.')
249
250 def testUniqueSpecName(self):
251 """Test that _FindSpec(unique_part_name) returns the path for the spec."""
252 # We'll search for this spec. Weird capitalization on purpose to test
253 # case sensitiveness.
254 spec_name = 'ToaDSTooL'
255
256 # We'll tell mox to say that these specs exist in the first directory...
257 dir_list = ['_default',
258 'x87-luigi.spec', 'x87-toadstool.SPeC', 'x88-princess.spec']
259
260 # We expect it to find this spec.
261 expected_result = 'x87-toadstool.SPeC'
262
263 # Self-checks for test code...
264 assert dir_list == sorted(dir_list)
265
266 # This spec doesn't represent any full path.
267 os.path.isfile(spec_name).AndReturn(False)
268
269 # This spec isn't found in our search path.
270 os.path.isfile(mox.Regex('^/.*%s.spec$' % spec_name)).MultipleTimes(
271 ).AndReturn(False)
272
273 # Return our directory listing.
274 # TODO(dianders): How to make first mocked call return dir_list and
275 # subsequent return []
276 os.listdir(mox.IsA(basestring)).AndReturn(dir_list)
277
278 os.path.isfile(mox.Regex('^/.*%s$' % expected_result)).AndReturn(True)
279
280 # Run the command and verify proper mocks were called...
281 self.mox.ReplayAll()
Doug Andersona9b10902011-02-01 17:54:31 -0800282 spec_path = utils.FindSpec(spec_name)
Doug Andersonf0c73952011-01-18 13:46:07 -0800283 self.mox.VerifyAll()
284
285 self.assertTrue(re.search('^/.*%s$' % expected_result, spec_path),
286 '_FindSpec("%s") incorrectly returned "%s".' %
287 (spec_name, spec_path))
288
289 def _TestBlankSpecName(self, menu_return):
290 """Helper for tests passing a blank spec name.
291
292 Args:
293 menu_return: This value is returned by TextMenu. Could be none or an
294 integer index into the dir_list of this function.
295 """
296 # We'll search for this spec.
297 spec_name = ''
298
299 # We'll tell mox to say that these specs exist in the first directory...
300 # ...only valid specs to make it easier to compare things.
301 dir_list = ['x87-luigi.spec', 'x87-toadstool.SPeC', 'x88-princess.spec']
302 num_specs = len(dir_list)
303
304 # Self-checks for test code...
305 assert menu_return < len(dir_list)
306 assert dir_list == sorted(dir_list)
307
308 # This spec doesn't represent any full path.
309 os.path.isfile(spec_name).AndReturn(False)
310
311 # Return our directory listing.
312 # TODO(dianders): How to make first mocked call return dir_list and
313 # subsequent return []
314 os.listdir(mox.IsA(basestring)).AndReturn(dir_list)
315
316 for i in xrange(num_specs):
317 os.path.isfile(mox.Regex('^/.*%s$' % dir_list[i])).AndReturn(True)
318
319 # We expect there to be 1 more item than we passed in, since we account
320 # for 'HOST'.
321 check_num_items_fn = lambda items: len(items) == (num_specs + 1)
322
323 # Add 1 to menu_return, since 'HOST' is first...
324 if menu_return is None:
325 adjusted_menu_return = menu_return
326 else:
327 adjusted_menu_return = menu_return + 1
328
329 # Should be one call to TextMenu, which will return menu_return.
330 text_menu.TextMenu(mox.And(mox.IsA(list), mox.Func(check_num_items_fn)),
331 mox.IsA(basestring)).AndReturn(adjusted_menu_return)
332
333 # Should die in response to the quit if directed to quit.
334 if menu_return is None:
Doug Andersona9b10902011-02-01 17:54:31 -0800335 cros_lib.Die(mox.IsA(basestring)).AndRaise(_DeathException)
Doug Andersonf0c73952011-01-18 13:46:07 -0800336
337 # Run the command and verify proper mocks were called...
338 self.mox.ReplayAll()
339 if menu_return is None:
Doug Andersona9b10902011-02-01 17:54:31 -0800340 self.assertRaises(_DeathException, utils.FindSpec, spec_name)
Doug Andersonf0c73952011-01-18 13:46:07 -0800341 else:
Doug Andersona9b10902011-02-01 17:54:31 -0800342 spec_path = utils.FindSpec(spec_name)
Doug Andersonf0c73952011-01-18 13:46:07 -0800343 self.mox.VerifyAll()
344
345 if menu_return is not None:
346 expected_result = dir_list[menu_return]
347 self.assertTrue(re.search('^/.*%s$' % expected_result, spec_path),
348 '_FindSpec("%s") incorrectly returned "%s".' %
349 (spec_name, spec_path))
350
351 def testBlankSpecNameWithQuit(self):
352 """Test that _FindSpec('') shows menu, mocking quit."""
353 self._TestBlankSpecName(None)
354
355 def testBlankSpecNameWithChoice0(self):
356 """Test that _FindSpec('') shows menu, mocking choice 0."""
357 self._TestBlankSpecName(0)
358
359 def testPartialSpecNameWithChoice0(self):
360 """Test that _FindSpec(non_unique_str) shows menu, mocking choice 0."""
361 # We'll search for this spec.
362 spec_name = 'x87'
363
364 # We'll tell mox to say that these specs exist in the first directory...
365 dir_list = ['_default',
366 'x87-luigi.spec', 'x87-toadstool.SPeC', 'x88-princess.spec']
367
368 # We expect 2 matches and should get back luigi as choice 0.
369 matches = ['x87-luigi.spec', 'x87-toadstool.SPeC']
370 num_match = len(matches)
371 expected_result = 'x87-luigi.spec'
372
373 # Self-checks for test code...
374 assert dir_list == sorted(dir_list)
375
376 # This spec doesn't represent any full path.
377 os.path.isfile(spec_name).AndReturn(False)
378
379 # This spec isn't found in our search path.
380 os.path.isfile(mox.Regex('^/.*%s.spec$' % spec_name)).MultipleTimes(
381 ).AndReturn(False)
382
383 # Return our directory listing.
384 # TODO(dianders): How to make first mocked call return dir_list and
385 # subsequent return []
386 os.listdir(mox.IsA(basestring)).AndReturn(dir_list)
387
388 for i in xrange(num_match):
389 os.path.isfile(mox.Regex('^/.*%s$' % matches[i])).AndReturn(True)
390
391 # Should be one call to TextMenu, which will return 0.
392 text_menu.TextMenu(mox.And(mox.IsA(list),
393 mox.Func(lambda items: len(items) == num_match)),
394 mox.IsA(basestring)).AndReturn(0)
395
396 # Run the command and verify proper mocks were called...
397 self.mox.ReplayAll()
Doug Andersona9b10902011-02-01 17:54:31 -0800398 spec_path = utils.FindSpec(spec_name)
Doug Andersonf0c73952011-01-18 13:46:07 -0800399 self.mox.VerifyAll()
400
401 self.assertTrue(re.search('^/.*%s$' % expected_result, spec_path),
402 '_FindSpec("%s") incorrectly returned "%s".' %
403 (spec_name, spec_path))
404
405
406if __name__ == '__main__':
Doug Andersone91900d2011-01-26 11:37:17 -0800407 doctest.testmod(main)
Doug Andersonf0c73952011-01-18 13:46:07 -0800408 unittest.main()