xref: /freebsd/contrib/kyua/utils/text/table_test.cpp (revision dd41de95a84d979615a2ef11df6850622bf6184e)
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
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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 
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