7e8cf97a1f734cf232335b80192941298c2a345a
[sdc/sdc-distribution-client.git] /
1 #!/usr/bin/env python
2 #
3 #  Licensed under the Apache License, Version 2.0 (the "License"); you may
4 #  not use this file except in compliance with the License. You may obtain
5 #  a copy of the License at
6 #
7 #       http://www.apache.org/licenses/LICENSE-2.0
8 #
9 #  Unless required by applicable law or agreed to in writing, software
10 #  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 #  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 #  License for the specific language governing permissions and limitations
13 #  under the License.
14
15 import mock
16 from six import StringIO
17 import os
18 import argparse
19
20 from cliff.formatters import table
21 from cliff.tests import test_columns
22
23
24 class args(object):
25     def __init__(self, max_width=0, print_empty=False):
26         if max_width > 0:
27             self.max_width = max_width
28         else:
29             # Envvar is only taken into account iff CLI parameter not given
30             self.max_width = int(os.environ.get('CLIFF_MAX_TERM_WIDTH', 0))
31         self.print_empty = print_empty
32
33
34 def _table_tester_helper(tags, data, extra_args=None):
35     """Get table output as a string, formatted according to
36     CLI arguments, environment variables and terminal size
37
38     tags - tuple of strings for data tags (column headers or fields)
39     data - tuple of strings for single data row
40          - list of tuples of strings for multiple rows of data
41     extra_args - an instance of class args
42                - a list of strings for CLI arguments
43     """
44     sf = table.TableFormatter()
45
46     if extra_args is None:
47         # Default to no CLI arguments
48         parsed_args = args()
49     elif type(extra_args) == args:
50         # Use the given CLI arguments
51         parsed_args = extra_args
52     else:
53         # Parse arguments as if passed on the command-line
54         parser = argparse.ArgumentParser(description='Testing...')
55         sf.add_argument_group(parser)
56         parsed_args = parser.parse_args(extra_args)
57
58     output = StringIO()
59     emitter = sf.emit_list if type(data) is list else sf.emit_one
60     emitter(tags, data, output, parsed_args)
61     return output.getvalue()
62
63
64 @mock.patch('cliff.utils.terminal_width')
65 def test_table_formatter(tw):
66     tw.return_value = 80
67     c = ('a', 'b', 'c', 'd')
68     d = ('A', 'B', 'C', 'test\rcarriage\r\nreturn')
69     expected = '''\
70 +-------+---------------+
71 | Field | Value         |
72 +-------+---------------+
73 | a     | A             |
74 | b     | B             |
75 | c     | C             |
76 | d     | test carriage |
77 |       | return        |
78 +-------+---------------+
79 '''
80     assert expected == _table_tester_helper(c, d)
81
82
83 # Multi-line output when width is restricted to 42 columns
84 expected_ml_val = '''\
85 +-------+--------------------------------+
86 | Field | Value                          |
87 +-------+--------------------------------+
88 | a     | A                              |
89 | b     | B                              |
90 | c     | C                              |
91 | d     | dddddddddddddddddddddddddddddd |
92 |       | dddddddddddddddddddddddddddddd |
93 |       | ddddddddddddddddd              |
94 +-------+--------------------------------+
95 '''
96
97 # Multi-line output when width is restricted to 80 columns
98 expected_ml_80_val = '''\
99 +-------+----------------------------------------------------------------------+
100 | Field | Value                                                                |
101 +-------+----------------------------------------------------------------------+
102 | a     | A                                                                    |
103 | b     | B                                                                    |
104 | c     | C                                                                    |
105 | d     | dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd |
106 |       | ddddddddd                                                            |
107 +-------+----------------------------------------------------------------------+
108 '''  # noqa
109
110 # Single-line output, for when no line length restriction apply
111 expected_sl_val = '''\
112 +-------+-------------------------------------------------------------------------------+
113 | Field | Value                                                                         |
114 +-------+-------------------------------------------------------------------------------+
115 | a     | A                                                                             |
116 | b     | B                                                                             |
117 | c     | C                                                                             |
118 | d     | ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd |
119 +-------+-------------------------------------------------------------------------------+
120 '''  # noqa
121
122
123 @mock.patch('cliff.utils.terminal_width')
124 def test_table_formatter_no_cli_param(tw):
125     tw.return_value = 80
126     c = ('a', 'b', 'c', 'd')
127     d = ('A', 'B', 'C', 'd' * 77)
128     assert expected_ml_80_val == _table_tester_helper(c, d, extra_args=args())
129
130
131 @mock.patch('cliff.utils.terminal_width')
132 def test_table_formatter_cli_param(tw):
133     tw.return_value = 80
134     c = ('a', 'b', 'c', 'd')
135     d = ('A', 'B', 'C', 'd' * 77)
136     assert (expected_ml_val ==
137             _table_tester_helper(c, d, extra_args=['--max-width', '42']))
138
139
140 @mock.patch('cliff.utils.terminal_width')
141 def test_table_formatter_no_cli_param_unlimited_tw(tw):
142     tw.return_value = 0
143     c = ('a', 'b', 'c', 'd')
144     d = ('A', 'B', 'C', 'd' * 77)
145     # output should not be wrapped to multiple lines
146     assert expected_sl_val == _table_tester_helper(c, d, extra_args=args())
147
148
149 @mock.patch('cliff.utils.terminal_width')
150 def test_table_formatter_cli_param_unlimited_tw(tw):
151     tw.return_value = 0
152     c = ('a', 'b', 'c', 'd')
153     d = ('A', 'B', 'C', 'd' * 77)
154     assert (expected_ml_val ==
155             _table_tester_helper(c, d, extra_args=['--max-width', '42']))
156
157
158 @mock.patch('cliff.utils.terminal_width')
159 @mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '666'})
160 def test_table_formatter_cli_param_envvar_big(tw):
161     tw.return_value = 80
162     c = ('a', 'b', 'c', 'd')
163     d = ('A', 'B', 'C', 'd' * 77)
164     assert (expected_ml_val ==
165             _table_tester_helper(c, d, extra_args=['--max-width', '42']))
166
167
168 @mock.patch('cliff.utils.terminal_width')
169 @mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '23'})
170 def test_table_formatter_cli_param_envvar_tiny(tw):
171     tw.return_value = 80
172     c = ('a', 'b', 'c', 'd')
173     d = ('A', 'B', 'C', 'd' * 77)
174     assert (expected_ml_val ==
175             _table_tester_helper(c, d, extra_args=['--max-width', '42']))
176
177
178 @mock.patch('cliff.utils.terminal_width')
179 def test_table_formatter_max_width(tw):
180     tw.return_value = 80
181     c = ('field_name', 'a_really_long_field_name')
182     d = ('the value', 'a value significantly longer than the field')
183     expected = '''\
184 +--------------------------+---------------------------------------------+
185 | Field                    | Value                                       |
186 +--------------------------+---------------------------------------------+
187 | field_name               | the value                                   |
188 | a_really_long_field_name | a value significantly longer than the field |
189 +--------------------------+---------------------------------------------+
190 '''
191     assert expected == _table_tester_helper(c, d)
192
193     # resize value column
194     tw.return_value = 70
195     expected = '''\
196 +--------------------------+-----------------------------------------+
197 | Field                    | Value                                   |
198 +--------------------------+-----------------------------------------+
199 | field_name               | the value                               |
200 | a_really_long_field_name | a value significantly longer than the   |
201 |                          | field                                   |
202 +--------------------------+-----------------------------------------+
203 '''
204     assert expected == _table_tester_helper(c, d)
205
206     # resize both columns
207     tw.return_value = 50
208     expected = '''\
209 +-----------------------+------------------------+
210 | Field                 | Value                  |
211 +-----------------------+------------------------+
212 | field_name            | the value              |
213 | a_really_long_field_n | a value significantly  |
214 | ame                   | longer than the field  |
215 +-----------------------+------------------------+
216 '''
217     assert expected == _table_tester_helper(c, d)
218
219     # resize all columns limited by min_width=16
220     tw.return_value = 10
221     expected = '''\
222 +------------------+------------------+
223 | Field            | Value            |
224 +------------------+------------------+
225 | field_name       | the value        |
226 | a_really_long_fi | a value          |
227 | eld_name         | significantly    |
228 |                  | longer than the  |
229 |                  | field            |
230 +------------------+------------------+
231 '''
232     assert expected == _table_tester_helper(c, d)
233
234
235 @mock.patch('cliff.utils.terminal_width')
236 def test_table_list_formatter(tw):
237     tw.return_value = 80
238     c = ('a', 'b', 'c')
239     d1 = ('A', 'B', 'C')
240     d2 = ('D', 'E', 'test\rcarriage\r\nreturn')
241     data = [d1, d2]
242     expected = '''\
243 +---+---+---------------+
244 | a | b | c             |
245 +---+---+---------------+
246 | A | B | C             |
247 | D | E | test carriage |
248 |   |   | return        |
249 +---+---+---------------+
250 '''
251     assert expected == _table_tester_helper(c, data)
252
253
254 @mock.patch('cliff.utils.terminal_width')
255 def test_table_formatter_formattable_column(tw):
256     tw.return_value = 0
257     c = ('a', 'b', 'c', 'd')
258     d = ('A', 'B', 'C', test_columns.FauxColumn(['the', 'value']))
259     expected = '''\
260 +-------+---------------------------------------------+
261 | Field | Value                                       |
262 +-------+---------------------------------------------+
263 | a     | A                                           |
264 | b     | B                                           |
265 | c     | C                                           |
266 | d     | I made this string myself: ['the', 'value'] |
267 +-------+---------------------------------------------+
268 '''
269     assert expected == _table_tester_helper(c, d)
270
271
272 _col_names = ('one', 'two', 'three')
273 _col_data = [(
274     'one one one one one',
275     'two two two two',
276     'three three')]
277
278 _expected_mv = {
279     80: '''\
280 +---------------------+-----------------+-------------+
281 | one                 | two             | three       |
282 +---------------------+-----------------+-------------+
283 | one one one one one | two two two two | three three |
284 +---------------------+-----------------+-------------+
285 ''',
286
287     50: '''\
288 +----------------+-----------------+-------------+
289 | one            | two             | three       |
290 +----------------+-----------------+-------------+
291 | one one one    | two two two two | three three |
292 | one one        |                 |             |
293 +----------------+-----------------+-------------+
294 ''',
295
296     47: '''\
297 +---------------+---------------+-------------+
298 | one           | two           | three       |
299 +---------------+---------------+-------------+
300 | one one one   | two two two   | three three |
301 | one one       | two           |             |
302 +---------------+---------------+-------------+
303 ''',
304
305     45: '''\
306 +--------------+--------------+-------------+
307 | one          | two          | three       |
308 +--------------+--------------+-------------+
309 | one one one  | two two two  | three three |
310 | one one      | two          |             |
311 +--------------+--------------+-------------+
312 ''',
313
314     40: '''\
315 +------------+------------+------------+
316 | one        | two        | three      |
317 +------------+------------+------------+
318 | one one    | two two    | three      |
319 | one one    | two two    | three      |
320 | one        |            |            |
321 +------------+------------+------------+
322 ''',
323
324     10: '''\
325 +----------+----------+----------+
326 | one      | two      | three    |
327 +----------+----------+----------+
328 | one one  | two two  | three    |
329 | one one  | two two  | three    |
330 | one      |          |          |
331 +----------+----------+----------+
332 ''',
333 }
334
335
336 @mock.patch('cliff.utils.terminal_width')
337 def test_table_list_formatter_formattable_column(tw):
338     tw.return_value = 80
339     c = ('a', 'b', 'c')
340     d1 = ('A', 'B', test_columns.FauxColumn(['the', 'value']))
341     data = [d1]
342     expected = '''\
343 +---+---+---------------------------------------------+
344 | a | b | c                                           |
345 +---+---+---------------------------------------------+
346 | A | B | I made this string myself: ['the', 'value'] |
347 +---+---+---------------------------------------------+
348 '''
349     assert expected == _table_tester_helper(c, data)
350
351
352 @mock.patch('cliff.utils.terminal_width')
353 def test_table_list_formatter_max_width(tw):
354     # no resize
355     l = tw.return_value = 80
356     assert _expected_mv[l] == _table_tester_helper(_col_names, _col_data)
357
358     # resize 1 column
359     l = tw.return_value = 50
360     actual = _table_tester_helper(_col_names, _col_data)
361     assert _expected_mv[l] == actual
362     assert len(actual.splitlines()[0]) == l
363
364     # resize 2 columns
365     l = tw.return_value = 45
366     actual = _table_tester_helper(_col_names, _col_data)
367     assert _expected_mv[l] == actual
368     assert len(actual.splitlines()[0]) == l
369
370     # resize all columns
371     l = tw.return_value = 40
372     actual = _table_tester_helper(_col_names, _col_data)
373     assert _expected_mv[l] == actual
374     assert len(actual.splitlines()[0]) == l
375
376     # resize all columns limited by min_width=8
377     l = tw.return_value = 10
378     actual = _table_tester_helper(_col_names, _col_data)
379     assert _expected_mv[l] == actual
380     # 3 columns each 8 wide, plus table spacing and borders
381     expected_width = 11 * 3 + 1
382     assert len(actual.splitlines()[0]) == expected_width
383
384
385 # Force a wide terminal by overriding its width with envvar
386 @mock.patch('cliff.utils.terminal_width')
387 @mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '666'})
388 def test_table_list_formatter_max_width_and_envvar_max(tw):
389     # no resize
390     tw.return_value = 80
391     assert _expected_mv[80] == _table_tester_helper(_col_names, _col_data)
392
393     # resize 1 column
394     tw.return_value = 50
395     assert _expected_mv[80] == _table_tester_helper(_col_names, _col_data)
396
397     # resize 2 columns
398     tw.return_value = 45
399     assert _expected_mv[80] == _table_tester_helper(_col_names, _col_data)
400
401     # resize all columns
402     tw.return_value = 40
403     assert _expected_mv[80] == _table_tester_helper(_col_names, _col_data)
404
405     # resize all columns limited by min_width=8
406     tw.return_value = 10
407     assert _expected_mv[80] == _table_tester_helper(_col_names, _col_data)
408
409
410 # Force a narrow terminal by overriding its width with envvar
411 @mock.patch('cliff.utils.terminal_width')
412 @mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '47'})
413 def test_table_list_formatter_max_width_and_envvar_mid(tw):
414     # no resize
415     tw.return_value = 80
416     assert _expected_mv[47] == _table_tester_helper(_col_names, _col_data)
417
418     # resize 1 column
419     tw.return_value = 50
420     actual = _table_tester_helper(_col_names, _col_data)
421     assert _expected_mv[47] == actual
422     assert len(actual.splitlines()[0]) == 47
423
424     # resize 2 columns
425     tw.return_value = 45
426     actual = _table_tester_helper(_col_names, _col_data)
427     assert _expected_mv[47] == actual
428     assert len(actual.splitlines()[0]) == 47
429
430     # resize all columns
431     tw.return_value = 40
432     actual = _table_tester_helper(_col_names, _col_data)
433     assert _expected_mv[47] == actual
434     assert len(actual.splitlines()[0]) == 47
435
436     # resize all columns limited by min_width=8
437     tw.return_value = 10
438     actual = _table_tester_helper(_col_names, _col_data)
439     assert _expected_mv[47] == actual
440     assert len(actual.splitlines()[0]) == 47
441
442
443 @mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '80'})
444 def test_table_list_formatter_env_maxwidth_noresize():
445     # no resize
446     assert _expected_mv[80] == _table_tester_helper(_col_names, _col_data)
447
448
449 @mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '50'})
450 def test_table_list_formatter_env_maxwidth_resize_one():
451     # resize 1 column
452     actual = _table_tester_helper(_col_names, _col_data)
453     assert _expected_mv[50] == actual
454     assert len(actual.splitlines()[0]) == 50
455
456
457 @mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '45'})
458 def test_table_list_formatter_env_maxwidth_resize_two():
459     # resize 2 columns
460     actual = _table_tester_helper(_col_names, _col_data)
461     assert _expected_mv[45] == actual
462     assert len(actual.splitlines()[0]) == 45
463
464
465 @mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '40'})
466 def test_table_list_formatter_env_maxwidth_resize_all():
467     # resize all columns
468     actual = _table_tester_helper(_col_names, _col_data)
469     assert _expected_mv[40] == actual
470     assert len(actual.splitlines()[0]) == 40
471
472
473 @mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '8'})
474 def test_table_list_formatter_env_maxwidth_resize_all_tiny():
475     # resize all columns limited by min_width=8
476     actual = _table_tester_helper(_col_names, _col_data)
477     assert _expected_mv[10] == actual
478     # 3 columns each 8 wide, plus table spacing and borders
479     expected_width = 11 * 3 + 1
480     assert len(actual.splitlines()[0]) == expected_width
481
482
483 @mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '42'})
484 def test_table_list_formatter_env_maxwidth_args_big():
485     assert _expected_mv[80] == _table_tester_helper(_col_names, _col_data,
486                                                     extra_args=args(666))
487
488
489 @mock.patch.dict(os.environ, {'CLIFF_MAX_TERM_WIDTH': '42'})
490 def test_table_list_formatter_env_maxwidth_args_tiny():
491     assert _expected_mv[40] == _table_tester_helper(_col_names, _col_data,
492                                                     extra_args=args(40))
493
494
495 @mock.patch('cliff.utils.terminal_width')
496 def test_table_list_formatter_empty(tw):
497     tw.return_value = 80
498     c = ('a', 'b', 'c')
499     data = []
500     expected = '\n'
501     assert expected == _table_tester_helper(c, data)
502
503
504 @mock.patch('cliff.utils.terminal_width')
505 def test_table_list_formatter_empty_table(tw):
506     tw.return_value = 80
507     c = ('a', 'b', 'c')
508     data = []
509     expected = '''\
510 +---+---+---+
511 | a | b | c |
512 +---+---+---+
513 +---+---+---+
514 '''
515     assert expected == _table_tester_helper(c, data,
516                                             extra_args=['--print-empty'])
517
518
519 def test_field_widths():
520     tf = table.TableFormatter
521     assert {
522         'a': 1,
523         'b': 2,
524         'c': 3,
525         'd': 10
526     } == tf._field_widths(
527         ('a', 'b', 'c', 'd'),
528         '+---+----+-----+------------+')
529
530
531 def test_field_widths_zero():
532     tf = table.TableFormatter
533     assert {
534         'a': 0,
535         'b': 0,
536         'c': 0
537     } == tf._field_widths(
538         ('a', 'b', 'c'),
539         '+--+-++')
540
541
542 def test_width_info():
543     tf = table.TableFormatter
544     assert (49, 4) == (tf._width_info(80, 10))
545     assert (76, 76) == (tf._width_info(80, 1))
546     assert (79, 0) == (tf._width_info(80, 0))
547     assert (0, 0) == (tf._width_info(0, 80))