1 // Copyright 2012 The Kyua Authors.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 // may be used to endorse or promote products derived from this software
15 // without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 #include "utils/text/table.hpp"
30
31 #include <algorithm>
32
33 #include <atf-c++.hpp>
34
35 #include "utils/text/operations.ipp"
36
37 namespace text = utils::text;
38
39
40 /// Performs a check on text::table_formatter.
41 ///
42 /// This is provided for test simplicity's sake. Having to match the result of
43 /// the formatting on a line by line basis would result in too verbose tests
44 /// (maybe not with C++11, but not using this yet).
45 ///
46 /// Because of the flattening of the formatted table into a string, we risk
47 /// misdetecting problems when the algorithm bundles newlines into the lines of
48 /// a table. This should not happen, and not accounting for this little detail
49 /// makes testing so much easier.
50 ///
51 /// \param expected Textual representation of the table, as a collection of
52 /// lines separated by newline characters.
53 /// \param formatter The formatter to use.
54 /// \param table The table to format.
55 static void
table_formatter_check(const std::string & expected,const text::table_formatter & formatter,const text::table & table)56 table_formatter_check(const std::string& expected,
57 const text::table_formatter& formatter,
58 const text::table& table)
59 {
60 ATF_REQUIRE_EQ(expected, text::join(formatter.format(table), "\n") + "\n");
61 }
62
63
64
65 ATF_TEST_CASE_WITHOUT_HEAD(table__ncolumns);
ATF_TEST_CASE_BODY(table__ncolumns)66 ATF_TEST_CASE_BODY(table__ncolumns)
67 {
68 ATF_REQUIRE_EQ(5, text::table(5).ncolumns());
69 ATF_REQUIRE_EQ(10, text::table(10).ncolumns());
70 }
71
72
73 ATF_TEST_CASE_WITHOUT_HEAD(table__column_width);
ATF_TEST_CASE_BODY(table__column_width)74 ATF_TEST_CASE_BODY(table__column_width)
75 {
76 text::table_row row1;
77 row1.push_back("1234");
78 row1.push_back("123456");
79 text::table_row row2;
80 row2.push_back("12");
81 row2.push_back("12345678");
82
83 text::table table(2);
84 table.add_row(row1);
85 table.add_row(row2);
86
87 ATF_REQUIRE_EQ(4, table.column_width(0));
88 ATF_REQUIRE_EQ(8, table.column_width(1));
89 }
90
91
92 ATF_TEST_CASE_WITHOUT_HEAD(table__column_widths);
ATF_TEST_CASE_BODY(table__column_widths)93 ATF_TEST_CASE_BODY(table__column_widths)
94 {
95 text::table_row row1;
96 row1.push_back("1234");
97 row1.push_back("123456");
98 text::table_row row2;
99 row2.push_back("12");
100 row2.push_back("12345678");
101
102 text::table table(2);
103 table.add_row(row1);
104 table.add_row(row2);
105
106 ATF_REQUIRE_EQ(4, table.column_widths()[0]);
107 ATF_REQUIRE_EQ(8, table.column_widths()[1]);
108 }
109
110
111 ATF_TEST_CASE_WITHOUT_HEAD(table__empty);
ATF_TEST_CASE_BODY(table__empty)112 ATF_TEST_CASE_BODY(table__empty)
113 {
114 text::table table(2);
115 ATF_REQUIRE(table.empty());
116 table.add_row(text::table_row(2));
117 ATF_REQUIRE(!table.empty());
118 }
119
120
121 ATF_TEST_CASE_WITHOUT_HEAD(table__iterate);
ATF_TEST_CASE_BODY(table__iterate)122 ATF_TEST_CASE_BODY(table__iterate)
123 {
124 text::table_row row1;
125 row1.push_back("foo");
126 text::table_row row2;
127 row2.push_back("bar");
128
129 text::table table(1);
130 table.add_row(row1);
131 table.add_row(row2);
132
133 text::table::const_iterator iter = table.begin();
134 ATF_REQUIRE(iter != table.end());
135 ATF_REQUIRE(row1 == *iter);
136 ++iter;
137 ATF_REQUIRE(iter != table.end());
138 ATF_REQUIRE(row2 == *iter);
139 ++iter;
140 ATF_REQUIRE(iter == table.end());
141 }
142
143
144 ATF_TEST_CASE_WITHOUT_HEAD(table_formatter__empty);
ATF_TEST_CASE_BODY(table_formatter__empty)145 ATF_TEST_CASE_BODY(table_formatter__empty)
146 {
147 ATF_REQUIRE(text::table_formatter().set_separator(" ")
148 .format(text::table(1)).empty());
149 ATF_REQUIRE(text::table_formatter().set_separator(" ")
150 .format(text::table(10)).empty());
151 }
152
153
154 ATF_TEST_CASE_WITHOUT_HEAD(table_formatter__defaults);
ATF_TEST_CASE_BODY(table_formatter__defaults)155 ATF_TEST_CASE_BODY(table_formatter__defaults)
156 {
157 text::table table(3);
158 {
159 text::table_row row;
160 row.push_back("First");
161 row.push_back("Second");
162 row.push_back("Third");
163 table.add_row(row);
164 }
165 {
166 text::table_row row;
167 row.push_back("Fourth with some text");
168 row.push_back("Fifth with some more text");
169 row.push_back("Sixth foo");
170 table.add_row(row);
171 }
172
173 table_formatter_check(
174 "First Second Third\n"
175 "Fourth with some textFifth with some more textSixth foo\n",
176 text::table_formatter(), table);
177 }
178
179
180 ATF_TEST_CASE_WITHOUT_HEAD(table_formatter__one_column__no_max_width);
ATF_TEST_CASE_BODY(table_formatter__one_column__no_max_width)181 ATF_TEST_CASE_BODY(table_formatter__one_column__no_max_width)
182 {
183 text::table table(1);
184 {
185 text::table_row row;
186 row.push_back("First row with some words");
187 table.add_row(row);
188 }
189 {
190 text::table_row row;
191 row.push_back("Second row with some words");
192 table.add_row(row);
193 }
194
195 table_formatter_check(
196 "First row with some words\n"
197 "Second row with some words\n",
198 text::table_formatter().set_separator(" | "), table);
199 }
200
201
202 ATF_TEST_CASE_WITHOUT_HEAD(table_formatter__one_column__explicit_width);
ATF_TEST_CASE_BODY(table_formatter__one_column__explicit_width)203 ATF_TEST_CASE_BODY(table_formatter__one_column__explicit_width)
204 {
205 text::table table(1);
206 {
207 text::table_row row;
208 row.push_back("First row with some words");
209 table.add_row(row);
210 }
211 {
212 text::table_row row;
213 row.push_back("Second row with some words");
214 table.add_row(row);
215 }
216
217 table_formatter_check(
218 "First row with some words\n"
219 "Second row with some words\n",
220 text::table_formatter().set_separator(" | ").set_column_width(0, 1024),
221 table);
222 }
223
224
225 ATF_TEST_CASE_WITHOUT_HEAD(table_formatter__one_column__max_width);
ATF_TEST_CASE_BODY(table_formatter__one_column__max_width)226 ATF_TEST_CASE_BODY(table_formatter__one_column__max_width)
227 {
228 text::table table(1);
229 {
230 text::table_row row;
231 row.push_back("First row with some words");
232 table.add_row(row);
233 }
234 {
235 text::table_row row;
236 row.push_back("Second row with some words");
237 table.add_row(row);
238 }
239
240 table_formatter_check(
241 "First row\nwith some\nwords\n"
242 "Second row\nwith some\nwords\n",
243 text::table_formatter().set_separator(" | ").set_table_width(11),
244 table);
245 }
246
247
248 ATF_TEST_CASE_WITHOUT_HEAD(table_formatter__many_columns__no_max_width);
ATF_TEST_CASE_BODY(table_formatter__many_columns__no_max_width)249 ATF_TEST_CASE_BODY(table_formatter__many_columns__no_max_width)
250 {
251 text::table table(3);
252 {
253 text::table_row row;
254 row.push_back("First");
255 row.push_back("Second");
256 row.push_back("Third");
257 table.add_row(row);
258 }
259 {
260 text::table_row row;
261 row.push_back("Fourth with some text");
262 row.push_back("Fifth with some more text");
263 row.push_back("Sixth foo");
264 table.add_row(row);
265 }
266
267 table_formatter_check(
268 "First | Second | Third\n"
269 "Fourth with some text | Fifth with some more text | Sixth foo\n",
270 text::table_formatter().set_separator(" | "), table);
271 }
272
273
274 ATF_TEST_CASE_WITHOUT_HEAD(table_formatter__many_columns__explicit_width);
ATF_TEST_CASE_BODY(table_formatter__many_columns__explicit_width)275 ATF_TEST_CASE_BODY(table_formatter__many_columns__explicit_width)
276 {
277 text::table table(3);
278 {
279 text::table_row row;
280 row.push_back("First");
281 row.push_back("Second");
282 row.push_back("Third");
283 table.add_row(row);
284 }
285 {
286 text::table_row row;
287 row.push_back("Fourth with some text");
288 row.push_back("Fifth with some more text");
289 row.push_back("Sixth foo");
290 table.add_row(row);
291 }
292
293 table_formatter_check(
294 "First | Second | Third\n"
295 "Fourth with some text | Fifth with some more text | Sixth foo\n",
296 text::table_formatter().set_separator(" | ").set_column_width(0, 23)
297 .set_column_width(1, 28), table);
298 }
299
300
301 ATF_TEST_CASE_WITHOUT_HEAD(table_formatter__many_columns__max_width);
ATF_TEST_CASE_BODY(table_formatter__many_columns__max_width)302 ATF_TEST_CASE_BODY(table_formatter__many_columns__max_width)
303 {
304 text::table table(3);
305 {
306 text::table_row row;
307 row.push_back("First");
308 row.push_back("Second");
309 row.push_back("Third");
310 table.add_row(row);
311 }
312 {
313 text::table_row row;
314 row.push_back("Fourth with some text");
315 row.push_back("Fifth with some more text");
316 row.push_back("Sixth foo");
317 table.add_row(row);
318 }
319
320 table_formatter_check(
321 "First | Second | Third\n"
322 "Fourth with some text | Fifth with | Sixth foo\n"
323 " | some more | \n"
324 " | text | \n",
325 text::table_formatter().set_separator(" | ").set_table_width(46)
326 .set_column_width(1, text::table_formatter::width_refill)
327 .set_column_width(0, text::table_formatter::width_auto), table);
328
329 table_formatter_check(
330 "First | Second | Third\n"
331 "Fourth with some text | Fifth with | Sixth foo\n"
332 " | some more | \n"
333 " | text | \n",
334 text::table_formatter().set_separator(" | ").set_table_width(48)
335 .set_column_width(1, text::table_formatter::width_refill)
336 .set_column_width(0, 23), table);
337 }
338
339
340 ATF_TEST_CASE_WITHOUT_HEAD(table_formatter__use_case__cli_help);
ATF_TEST_CASE_BODY(table_formatter__use_case__cli_help)341 ATF_TEST_CASE_BODY(table_formatter__use_case__cli_help)
342 {
343 text::table options_table(2);
344 {
345 text::table_row row;
346 row.push_back("-a a_value");
347 row.push_back("This is the description of the first flag");
348 options_table.add_row(row);
349 }
350 {
351 text::table_row row;
352 row.push_back("-b");
353 row.push_back("And this is the text for the second flag");
354 options_table.add_row(row);
355 }
356
357 text::table commands_table(2);
358 {
359 text::table_row row;
360 row.push_back("first");
361 row.push_back("This is the first command");
362 commands_table.add_row(row);
363 }
364 {
365 text::table_row row;
366 row.push_back("second");
367 row.push_back("And this is the second command");
368 commands_table.add_row(row);
369 }
370
371 const text::widths_vector::value_type first_width =
372 std::max(options_table.column_width(0), commands_table.column_width(0));
373
374 table_formatter_check(
375 "-a a_value This is the description\n"
376 " of the first flag\n"
377 "-b And this is the text for\n"
378 " the second flag\n",
379 text::table_formatter().set_separator(" ").set_table_width(36)
380 .set_column_width(0, first_width)
381 .set_column_width(1, text::table_formatter::width_refill),
382 options_table);
383
384 table_formatter_check(
385 "first This is the first\n"
386 " command\n"
387 "second And this is the second\n"
388 " command\n",
389 text::table_formatter().set_separator(" ").set_table_width(36)
390 .set_column_width(0, first_width)
391 .set_column_width(1, text::table_formatter::width_refill),
392 commands_table);
393 }
394
395
ATF_INIT_TEST_CASES(tcs)396 ATF_INIT_TEST_CASES(tcs)
397 {
398 ATF_ADD_TEST_CASE(tcs, table__ncolumns);
399 ATF_ADD_TEST_CASE(tcs, table__column_width);
400 ATF_ADD_TEST_CASE(tcs, table__column_widths);
401 ATF_ADD_TEST_CASE(tcs, table__empty);
402 ATF_ADD_TEST_CASE(tcs, table__iterate);
403
404 ATF_ADD_TEST_CASE(tcs, table_formatter__empty);
405 ATF_ADD_TEST_CASE(tcs, table_formatter__defaults);
406 ATF_ADD_TEST_CASE(tcs, table_formatter__one_column__no_max_width);
407 ATF_ADD_TEST_CASE(tcs, table_formatter__one_column__explicit_width);
408 ATF_ADD_TEST_CASE(tcs, table_formatter__one_column__max_width);
409 ATF_ADD_TEST_CASE(tcs, table_formatter__many_columns__no_max_width);
410 ATF_ADD_TEST_CASE(tcs, table_formatter__many_columns__explicit_width);
411 ATF_ADD_TEST_CASE(tcs, table_formatter__many_columns__max_width);
412 ATF_ADD_TEST_CASE(tcs, table_formatter__use_case__cli_help);
413 }
414