1#!/usr/bin/env python3
2# -*- coding:utf-8 -*-
3# Copyright 2019 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""Unittests for the utils module."""
18
19from __future__ import print_function
20
21import datetime
22import os
23import sys
24import unittest
25
26_path = os.path.realpath(__file__ + '/../..')
27if sys.path[0] != _path:
28    sys.path.insert(0, _path)
29del _path
30
31# We have to import our local modules after the sys.path tweak.  We can't use
32# relative imports because this is an executable program, not a module.
33# pylint: disable=wrong-import-position
34import rh
35import rh.utils
36
37
38class TimeDeltaStrTests(unittest.TestCase):
39    """Verify behavior of timedelta_str object."""
40
41    def test_same(self):
42        """Check timedelta of 0 seconds."""
43        delta = datetime.timedelta(0)
44        self.assertEqual('0.000s', rh.utils.timedelta_str(delta))
45
46    def test_millisecondss(self):
47        """Check timedelta of milliseconds."""
48        delta = datetime.timedelta(seconds=0.123456)
49        self.assertEqual('0.123s', rh.utils.timedelta_str(delta))
50
51    def test_seconds(self):
52        """Check timedelta of seconds."""
53        delta = datetime.timedelta(seconds=12.3)
54        self.assertEqual('12.300s', rh.utils.timedelta_str(delta))
55
56    def test_minutes(self):
57        """Check timedelta of minutes."""
58        delta = datetime.timedelta(seconds=72.3)
59        self.assertEqual('1m12.300s', rh.utils.timedelta_str(delta))
60
61    def test_hours(self):
62        """Check timedelta of hours."""
63        delta = datetime.timedelta(seconds=4000.3)
64        self.assertEqual('1h6m40.300s', rh.utils.timedelta_str(delta))
65
66
67class CompletedProcessTests(unittest.TestCase):
68    """Verify behavior of CompletedProcess object."""
69
70    def test_empty_cmdstr(self):
71        """Check cmdstr with an empty command."""
72        result = rh.utils.CompletedProcess(args=[])
73        self.assertEqual('', result.cmdstr)
74
75    def test_basic_cmdstr(self):
76        """Check cmdstr with a basic command command."""
77        result = rh.utils.CompletedProcess(args=['ls', 'a b'])
78        self.assertEqual("ls 'a b'", result.cmdstr)
79
80    def test_str(self):
81        """Check str() handling."""
82        # We don't enforce much, just that it doesn't crash.
83        result = rh.utils.CompletedProcess()
84        self.assertNotEqual('', str(result))
85        result = rh.utils.CompletedProcess(args=[])
86        self.assertNotEqual('', str(result))
87
88    def test_repr(self):
89        """Check repr() handling."""
90        # We don't enforce much, just that it doesn't crash.
91        result = rh.utils.CompletedProcess()
92        self.assertNotEqual('', repr(result))
93        result = rh.utils.CompletedProcess(args=[])
94        self.assertNotEqual('', repr(result))
95
96
97class CalledProcessErrorTests(unittest.TestCase):
98    """Verify behavior of CalledProcessError object."""
99
100    def test_basic(self):
101        """Basic test we can create a normal instance."""
102        rh.utils.CalledProcessError(0, ['mycmd'])
103        rh.utils.CalledProcessError(1, ['mycmd'], exception=Exception('bad'))
104
105    def test_stringify(self):
106        """Check stringify() handling."""
107        # We don't assert much so we leave flexibility in changing format.
108        err = rh.utils.CalledProcessError(0, ['mycmd'])
109        self.assertIn('mycmd', err.stringify())
110        err = rh.utils.CalledProcessError(
111            0, ['mycmd'], exception=Exception('bad'))
112        self.assertIn('mycmd', err.stringify())
113
114    def test_str(self):
115        """Check str() handling."""
116        # We don't assert much so we leave flexibility in changing format.
117        err = rh.utils.CalledProcessError(0, ['mycmd'])
118        self.assertIn('mycmd', str(err))
119        err = rh.utils.CalledProcessError(
120            0, ['mycmd'], exception=Exception('bad'))
121        self.assertIn('mycmd', str(err))
122
123    def test_repr(self):
124        """Check repr() handling."""
125        # We don't assert much so we leave flexibility in changing format.
126        err = rh.utils.CalledProcessError(0, ['mycmd'])
127        self.assertNotEqual('', repr(err))
128        err = rh.utils.CalledProcessError(
129            0, ['mycmd'], exception=Exception('bad'))
130        self.assertNotEqual('', repr(err))
131
132
133class RunCommandTests(unittest.TestCase):
134    """Verify behavior of run helper."""
135
136    def test_basic(self):
137        """Simple basic test."""
138        ret = rh.utils.run(['true'])
139        self.assertEqual('true', ret.cmdstr)
140        self.assertIsNone(ret.stdout)
141        self.assertIsNone(ret.stderr)
142
143    def test_stdout_capture(self):
144        """Verify output capturing works."""
145        ret = rh.utils.run(['echo', 'hi'], redirect_stdout=True)
146        self.assertEqual('hi\n', ret.stdout)
147        self.assertIsNone(ret.stderr)
148
149    def test_stderr_capture(self):
150        """Verify stderr capturing works."""
151        ret = rh.utils.run(['sh', '-c', 'echo hi >&2'], redirect_stderr=True)
152        self.assertIsNone(ret.stdout)
153        self.assertEqual('hi\n', ret.stderr)
154
155    def test_stdout_utf8(self):
156        """Verify reading UTF-8 data works."""
157        ret = rh.utils.run(['printf', r'\xc3\x9f'], redirect_stdout=True)
158        self.assertEqual(u'ß', ret.stdout)
159        self.assertIsNone(ret.stderr)
160
161    def test_stdin_utf8(self):
162        """Verify writing UTF-8 data works."""
163        ret = rh.utils.run(['cat'], redirect_stdout=True, input=u'ß')
164        self.assertEqual(u'ß', ret.stdout)
165        self.assertIsNone(ret.stderr)
166
167
168if __name__ == '__main__':
169    unittest.main()
170