Skip to content

Commit 82f2aab

Browse files
committed
Added unit tests for column options.
1 parent 0d2aeb1 commit 82f2aab

File tree

2 files changed

+250
-6
lines changed

2 files changed

+250
-6
lines changed

examples/columns.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -121,19 +121,16 @@ def int2word(num, separator="-"):
121121
tf.Column('Num 1', attrib='get_field3'),
122122
tf.Column('Num 2', attrib='field4'),
123123
tf.Column('Multiplied', attrib=None, obj_formatter=multiply))
124-
125-
126124
print("First; Truncate Front\n"
127125
"Second: cell align right, cell padding=5")
128126
print(tf.generate_table(rows, columns))
129127

128+
130129
columns = (tf.Column('First', width=20, attrib='field1', wrap_mode=tf.WrapMode.TRUNCATE_MIDDLE),
131130
tf.Column('Second', attrib='field2'),
132131
tf.Column('Num 1', attrib='get_field3'),
133132
tf.Column('Num 2', attrib='field4', cell_valign=tf.ColumnAlignment.AlignBottom),
134133
tf.Column('Multiplied', attrib=None, obj_formatter=multiply))
135-
136-
137134
print("First: Truncate Middle\nNum 2: cell align bottom")
138135
print(tf.generate_table(rows, columns))
139136

@@ -143,7 +140,5 @@ def int2word(num, separator="-"):
143140
tf.Column('Num 1', attrib='get_field3'),
144141
tf.Column('Num 2', attrib='field4', formatter=int2word),
145142
tf.Column('Multiplied', attrib=None, obj_formatter=multiply))
146-
147-
148143
print("First: Truncate Hard\nNum 2: Field formatter")
149144
print(tf.generate_table(rows, columns))

tests/test_columns.py

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
# coding=utf-8
2+
"""
3+
Unit testing the variety of column customizations available
4+
"""
5+
import pytest
6+
7+
import tableformatter as tf
8+
9+
# Make the test results reproducible regardless of what color libraries are installed
10+
tf.TableColors.set_color_library('none')
11+
tf.set_default_grid(tf.AlternatingRowGrid('', ''))
12+
13+
14+
class MyRowObject(object):
15+
"""Simple object to demonstrate using a list of objects with TableFormatter"""
16+
def __init__(self, field1: str, field2: str, field3: int, field4: int):
17+
self.field1 = field1
18+
self.field2 = field2
19+
self._field3 = field3
20+
self.field4 = field4
21+
22+
def get_field3(self):
23+
"""Demonstrates accessing object functions"""
24+
return self._field3
25+
26+
27+
def multiply(row_obj: MyRowObject):
28+
"""Demonstrates an object formatter function"""
29+
return str(row_obj.get_field3() * row_obj.field4)
30+
31+
32+
def int2word(num, separator="-"):
33+
"""Demonstrates a field formatter function
34+
From: https://codereview.stackexchange.com/questions/156590/create-the-english-word-for-a-number
35+
"""
36+
ones_and_teens = {0: "Zero", 1: 'One', 2: 'Two', 3: 'Three',
37+
4: 'Four', 5: 'Five', 6: 'Six', 7: 'Seven',
38+
8: 'Eight', 9: 'Nine', 10: 'Ten', 11: 'Eleven',
39+
12: 'Twelve', 13: 'Thirteen', 14: 'Fourteen',
40+
15: 'Fifteen', 16: 'Sixteen', 17: 'Seventeen',
41+
18: 'Eighteen', 19: 'Nineteen'}
42+
twenty2ninety = {2: 'Twenty', 3: 'Thirty', 4: 'Forty', 5: 'Fifty',
43+
6: 'Sixty', 7: 'Seventy', 8: 'Eighty', 9: 'Ninety', 0: ""}
44+
45+
if 0 <= num < 19:
46+
return ones_and_teens[num]
47+
elif 20 <= num <= 99:
48+
tens, below_ten = divmod(num, 10)
49+
if below_ten > 0:
50+
words = twenty2ninety[tens] + separator + \
51+
ones_and_teens[below_ten].lower()
52+
else:
53+
words = twenty2ninety[tens]
54+
return words
55+
56+
elif 100 <= num <= 999:
57+
hundreds, below_hundred = divmod(num, 100)
58+
tens, below_ten = divmod(below_hundred, 10)
59+
if below_hundred == 0:
60+
words = ones_and_teens[hundreds] + separator + "hundred"
61+
elif below_ten == 0:
62+
words = ones_and_teens[hundreds] + separator + \
63+
"hundred" + separator + twenty2ninety[tens].lower()
64+
else:
65+
if tens > 0:
66+
words = ones_and_teens[hundreds] + separator + "hundred" + separator + twenty2ninety[
67+
tens].lower() + separator + ones_and_teens[below_ten].lower()
68+
else:
69+
words = ones_and_teens[
70+
hundreds] + separator + "hundred" + separator + ones_and_teens[below_ten].lower()
71+
return words
72+
73+
else:
74+
print("num out of range")
75+
76+
77+
@pytest.fixture
78+
def obj_rows():
79+
rows = [MyRowObject('Longer text that will trigger the column wrapping', 'A2', 5, 56),
80+
MyRowObject('B1', 'B2\nB2\nB2', 23, 8),
81+
MyRowObject('C1', 'C2', 4, 9),
82+
MyRowObject('D1', 'D2', 7, 5)]
83+
return rows
84+
85+
86+
def test_wrapped_object_formatter(obj_rows):
87+
columns = (tf.Column('First', width=20, attrib='field1'),
88+
tf.Column('Second', attrib='field2'),
89+
tf.Column('Num 1', width=3, attrib='get_field3'),
90+
tf.Column('Num 2', attrib='field4'),
91+
tf.Column('Multiplied', obj_formatter=multiply))
92+
table = tf.generate_table(obj_rows, columns)
93+
expected = '''
94+
╔══════════════════════╤════════╤═════╤═══════╤════════════╗
95+
║ │ │ Num │ │ ║
96+
║ First │ Second │ 1 │ Num 2 │ Multiplied ║
97+
╠══════════════════════╪════════╪═════╪═══════╪════════════╣
98+
║ Longer text that │ A2 │ 5 │ 56 │ 280 ║
99+
║ will trigger the │ │ │ │ ║
100+
║ column wrapping │ │ │ │ ║
101+
║ B1 │ B2 │ 23 │ 8 │ 184 ║
102+
║ │ B2 │ │ │ ║
103+
║ │ B2 │ │ │ ║
104+
║ C1 │ C2 │ 4 │ 9 │ 36 ║
105+
║ D1 │ D2 │ 7 │ 5 │ 35 ║
106+
╚══════════════════════╧════════╧═════╧═══════╧════════════╝
107+
'''.lstrip('\n')
108+
assert table == expected
109+
110+
111+
def test_wrapped_indent_center_header(obj_rows):
112+
columns = (tf.Column('First', width=20, attrib='field1', wrap_mode=tf.WrapMode.WRAP_WITH_INDENT),
113+
tf.Column('Second', attrib='field2'),
114+
tf.Column('Num 1', width=3, attrib='get_field3', header_halign=tf.ColumnAlignment.AlignCenter),
115+
tf.Column('Num 2', attrib='field4'),
116+
tf.Column('Multiplied', attrib=None, obj_formatter=multiply))
117+
table = tf.generate_table(obj_rows, columns)
118+
expected = '''
119+
╔══════════════════════╤════════╤═════╤═══════╤════════════╗
120+
║ │ │ Num │ │ ║
121+
║ First │ Second │ 1 │ Num 2 │ Multiplied ║
122+
╠══════════════════════╪════════╪═════╪═══════╪════════════╣
123+
║ Longer text that │ A2 │ 5 │ 56 │ 280 ║
124+
║ » will trigger the │ │ │ │ ║
125+
║ » column wrapping │ │ │ │ ║
126+
║ B1 │ B2 │ 23 │ 8 │ 184 ║
127+
║ │ B2 │ │ │ ║
128+
║ │ B2 │ │ │ ║
129+
║ C1 │ C2 │ 4 │ 9 │ 36 ║
130+
║ D1 │ D2 │ 7 │ 5 │ 35 ║
131+
╚══════════════════════╧════════╧═════╧═══════╧════════════╝
132+
'''.lstrip('\n')
133+
assert table == expected
134+
135+
136+
def test_wrapped_custom_indent_header_right_header_top(obj_rows):
137+
columns = (tf.Column('First', width=20, attrib='field1', wrap_mode=tf.WrapMode.WRAP_WITH_INDENT,
138+
wrap_prefix='>>> '),
139+
tf.Column('Second', attrib='field2', cell_halign=tf.ColumnAlignment.AlignCenter),
140+
tf.Column('Num 1', width=3, attrib='get_field3', header_halign=tf.ColumnAlignment.AlignRight),
141+
tf.Column('Num 2', attrib='field4', header_valign=tf.ColumnAlignment.AlignTop),
142+
tf.Column('Multiplied', attrib=None, obj_formatter=multiply))
143+
table = tf.generate_table(obj_rows, columns)
144+
expected = '''
145+
╔══════════════════════╤════════╤═════╤═══════╤════════════╗
146+
║ │ │ Num │ Num 2 │ ║
147+
║ First │ Second │ 1 │ │ Multiplied ║
148+
╠══════════════════════╪════════╪═════╪═══════╪════════════╣
149+
║ Longer text that │ A2 │ 5 │ 56 │ 280 ║
150+
║ >>> will trigger the │ │ │ │ ║
151+
║ >>> column wrapping │ │ │ │ ║
152+
║ B1 │ B2 │ 23 │ 8 │ 184 ║
153+
║ │ B2 │ │ │ ║
154+
║ │ B2 │ │ │ ║
155+
║ C1 │ C2 │ 4 │ 9 │ 36 ║
156+
║ D1 │ D2 │ 7 │ 5 │ 35 ║
157+
╚══════════════════════╧════════╧═════╧═══════╧════════════╝
158+
'''.lstrip('\n')
159+
assert table == expected
160+
161+
162+
def test_truncate_end_custom_padding(obj_rows):
163+
columns = (tf.Column('First', width=20, attrib='field1', wrap_mode=tf.WrapMode.TRUNCATE_END),
164+
tf.Column('Second', attrib='field2', cell_padding=3),
165+
tf.Column('Num 1', width=3, attrib='get_field3'),
166+
tf.Column('Num 2', attrib='field4'),
167+
tf.Column('Multiplied', attrib=None, obj_formatter=multiply))
168+
table = tf.generate_table(obj_rows, columns)
169+
expected = '''
170+
╔══════════════════════╤════════════╤═════╤═══════╤════════════╗
171+
║ │ │ Num │ │ ║
172+
║ First │ Second │ 1 │ Num 2 │ Multiplied ║
173+
╠══════════════════════╪════════════╪═════╪═══════╪════════════╣
174+
║ Longer text that wi… │ A2 │ 5 │ 56 │ 280 ║
175+
║ B1 │ B2 │ 23 │ 8 │ 184 ║
176+
║ │ B2 │ │ │ ║
177+
║ │ B2 │ │ │ ║
178+
║ C1 │ C2 │ 4 │ 9 │ 36 ║
179+
║ D1 │ D2 │ 7 │ 5 │ 35 ║
180+
╚══════════════════════╧════════════╧═════╧═══════╧════════════╝
181+
'''.lstrip('\n')
182+
assert table == expected
183+
184+
185+
def test_truncate_front_custom_padding_cell_align_right(obj_rows):
186+
columns = (tf.Column('First', width=20, attrib='field1', wrap_mode=tf.WrapMode.TRUNCATE_FRONT),
187+
tf.Column('Second', attrib='field2', cell_padding=5, cell_halign=tf.ColumnAlignment.AlignRight),
188+
tf.Column('Num 1', attrib='get_field3'),
189+
tf.Column('Num 2', attrib='field4'),
190+
tf.Column('Multiplied', attrib=None, obj_formatter=multiply))
191+
table = tf.generate_table(obj_rows, columns)
192+
expected = '''
193+
╔══════════════════════╤════════════════╤═══════╤═══════╤════════════╗
194+
║ First │ Second │ Num 1 │ Num 2 │ Multiplied ║
195+
╠══════════════════════╪════════════════╪═══════╪═══════╪════════════╣
196+
║ …the column wrapping │ A2 │ 5 │ 56 │ 280 ║
197+
║ B1 │ B2 │ 23 │ 8 │ 184 ║
198+
║ │ B2 │ │ │ ║
199+
║ │ B2 │ │ │ ║
200+
║ C1 │ C2 │ 4 │ 9 │ 36 ║
201+
║ D1 │ D2 │ 7 │ 5 │ 35 ║
202+
╚══════════════════════╧════════════════╧═══════╧═══════╧════════════╝
203+
'''.lstrip('\n')
204+
assert table == expected
205+
206+
207+
def test_truncate_middle_cell_align_bottom(obj_rows):
208+
columns = (tf.Column('First', width=20, attrib='field1', wrap_mode=tf.WrapMode.TRUNCATE_MIDDLE),
209+
tf.Column('Second', attrib='field2'),
210+
tf.Column('Num 1', attrib='get_field3'),
211+
tf.Column('Num 2', attrib='field4', cell_valign=tf.ColumnAlignment.AlignBottom),
212+
tf.Column('Multiplied', attrib=None, obj_formatter=multiply))
213+
table = tf.generate_table(obj_rows, columns)
214+
expected = '''
215+
╔══════════════════════╤════════╤═══════╤═══════╤════════════╗
216+
║ First │ Second │ Num 1 │ Num 2 │ Multiplied ║
217+
╠══════════════════════╪════════╪═══════╪═══════╪════════════╣
218+
║ Longer t … wrapping │ A2 │ 5 │ 56 │ 280 ║
219+
║ B1 │ B2 │ 23 │ │ 184 ║
220+
║ │ B2 │ │ │ ║
221+
║ │ B2 │ │ 8 │ ║
222+
║ C1 │ C2 │ 4 │ 9 │ 36 ║
223+
║ D1 │ D2 │ 7 │ 5 │ 35 ║
224+
╚══════════════════════╧════════╧═══════╧═══════╧════════════╝
225+
'''.lstrip('\n')
226+
assert table == expected
227+
228+
229+
def test_truncate_hard_field_formatter(obj_rows):
230+
columns = (tf.Column('First', width=20, attrib='field1', wrap_mode=tf.WrapMode.TRUNCATE_HARD),
231+
tf.Column('Second', attrib='field2'),
232+
tf.Column('Num 1', attrib='get_field3'),
233+
tf.Column('Num 2', attrib='field4', formatter=int2word),
234+
tf.Column('Multiplied', attrib=None, obj_formatter=multiply))
235+
table = tf.generate_table(obj_rows, columns)
236+
expected = '''
237+
╔══════════════════════╤════════╤═══════╤═══════════╤════════════╗
238+
║ First │ Second │ Num 1 │ Num 2 │ Multiplied ║
239+
╠══════════════════════╪════════╪═══════╪═══════════╪════════════╣
240+
║ Longer text that wil │ A2 │ 5 │ Fifty-six │ 280 ║
241+
║ B1 │ B2 │ 23 │ Eight │ 184 ║
242+
║ │ B2 │ │ │ ║
243+
║ │ B2 │ │ │ ║
244+
║ C1 │ C2 │ 4 │ Nine │ 36 ║
245+
║ D1 │ D2 │ 7 │ Five │ 35 ║
246+
╚══════════════════════╧════════╧═══════╧═══════════╧════════════╝
247+
'''.lstrip('\n')
248+
assert table == expected
249+

0 commit comments

Comments
 (0)