#!/usr/bin/env python3 # Copyright 2016 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Unittests for the shell module.""" import difflib import os import sys import unittest _path = os.path.realpath(__file__ + '/../..') if sys.path[0] != _path: sys.path.insert(0, _path) del _path # We have to import our local modules after the sys.path tweak. We can't use # relative imports because this is an executable program, not a module. # pylint: disable=wrong-import-position import rh.shell class DiffTestCase(unittest.TestCase): """Helper that includes diff output when failing.""" def setUp(self): self.differ = difflib.Differ() def _assertEqual(self, func, test_input, test_output, result): """Like assertEqual but with built in diff support.""" diff = '\n'.join(list(self.differ.compare([test_output], [result]))) msg = ('Expected %s to translate %r to %r, but got %r\n%s' % (func, test_input, test_output, result, diff)) self.assertEqual(test_output, result, msg) def _testData(self, functor, tests, check_type=True): """Process a dict of test data.""" for test_output, test_input in tests.items(): result = functor(test_input) self._assertEqual(functor.__name__, test_input, test_output, result) if check_type: # Also make sure the result is a string, otherwise the %r # output will include a "u" prefix and that is not good for # logging. self.assertEqual(type(test_output), str) class ShellQuoteTest(DiffTestCase): """Test the shell_quote & shell_unquote functions.""" def testShellQuote(self): """Basic ShellQuote tests.""" # Dict of expected output strings to input lists. tests_quote = { "''": '', 'a': u'a', "'a b c'": u'a b c', "'a\tb'": 'a\tb', "'/a$file'": '/a$file', "'/a#file'": '/a#file', """'b"c'""": 'b"c', "'a@()b'": 'a@()b', 'j%k': 'j%k', r'''"s'a\$va\\rs"''': r"s'a$va\rs", r'''"\\'\\\""''': r'''\'\"''', r'''"'\\\$"''': r"""'\$""", } # Expected input output specific to ShellUnquote. This string cannot # be produced by ShellQuote but is still a valid bash escaped string. tests_unquote = { r'''\$''': r'''"\\$"''', } def aux(s): return rh.shell.shell_unquote(rh.shell.shell_quote(s)) self._testData(rh.shell.shell_quote, tests_quote) self._testData(rh.shell.shell_unquote, tests_unquote) # Test that the operations are reversible. self._testData(aux, {k: k for k in tests_quote.values()}, False) self._testData(aux, {k: k for k in tests_quote}, False) class CmdToStrTest(DiffTestCase): """Test the cmd_to_str function.""" def testCmdToStr(self): # Dict of expected output strings to input lists. tests = { r"a b": ['a', 'b'], r"'a b' c": ['a b', 'c'], r'''a "b'c"''': ['a', "b'c"], r'''a "/'\$b" 'a b c' "xy'z"''': [u'a', "/'$b", 'a b c', "xy'z"], '': [], } self._testData(rh.shell.cmd_to_str, tests) class BooleanShellTest(unittest.TestCase): """Test the boolean_shell_value function.""" def testFull(self): """Verify nputs work as expected""" for v in (None,): self.assertTrue(rh.shell.boolean_shell_value(v, True)) self.assertFalse(rh.shell.boolean_shell_value(v, False)) for v in (1234, '', 'akldjsf', '"'): self.assertRaises(ValueError, rh.shell.boolean_shell_value, v, True) for v in ('yes', 'YES', 'YeS', 'y', 'Y', '1', 'true', 'True', 'TRUE',): self.assertTrue(rh.shell.boolean_shell_value(v, True)) self.assertTrue(rh.shell.boolean_shell_value(v, False)) for v in ('no', 'NO', 'nO', 'n', 'N', '0', 'false', 'False', 'FALSE',): self.assertFalse(rh.shell.boolean_shell_value(v, True)) self.assertFalse(rh.shell.boolean_shell_value(v, False)) if __name__ == '__main__': unittest.main()