=UTF-8
8 | encoding/README.md=UTF-8
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 John C Sinclair
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # java-console-table a ConsoleTable for Java
2 |
3 | Copyright (c) John C Sinclair 2021
4 |
5 | 
6 |
7 | A `ConsoleTable` formats a table of rows and columns into a
8 | single `String`, which can be printed on the console with a monospaced font.
9 |
10 | Example code:
11 |
12 | ```java
13 | ConsoleTable table = new ConsoleTable();
14 | table.setHeaders("-City", "'Lat", "Longitude");
15 | table.addRow("Paris", 48.86,2.34);
16 | table.addRow("New York", 40.74, -73.99);
17 | table.addRow("London", 51.52, -0.13);
18 | table.addRow("Brisbane", -27.47, 153.03);
19 | System.out.print(table);
20 |
21 | System.out.print(table.withStyle(Styles.BASIC));
22 | ```
23 |
24 | Console output:
25 |
26 | ```
27 | ┌──────────┬────────┬───────────┐
28 | │ City │ Lat │ Longitude │
29 | ├──────────┼────────┼───────────┤
30 | │ Paris │ 48.86 │ 2.34 │
31 | │ New York │ 40.74 │ -73.99 │
32 | │ London │ 51.52 │ -0.13 │
33 | │ Brisbane │ -27.47 │ 153.03 │
34 | └──────────┴────────┴───────────┘
35 | +----------+--------+-----------+
36 | | City | Lat | Longitude |
37 | +----------+--------+-----------+
38 | | Paris | 48.86 | 2.34 |
39 | | New York | 40.74 | -73.99 |
40 | | London | 51.52 | -0.13 |
41 | | Brisbane | -27.47 | 153.03 |
42 | +----------+--------+-----------+
43 | ```
44 |
45 |
46 | ## Features
47 |
48 | ConsoleTable makes it easy to build stylish tables , which can be printed into a single string with all formats preserved.
49 | The core features are:
50 | - Never have to work out the width of a column, `ConsoleTable` does it for you.
51 | - Be forgiving of input data and handle nulls and missing columns.
52 | - Display an optional header row.
53 | - Display borders and lines with a predefined or user defined `Style`
54 | - Uses the `toString()` method to print any Object
55 | - Accepts table data as `Object[][]` or `List` or `List>`.
56 | - Uses fluent style method chaining. `Table.of(headers,data).withStyle(Styles.SQL)`
57 | - A column can be `Aligned` either `LEFT`, `CENTRE` or `RIGHT`.
58 | - `ColumnFormat` defaults to `RIGHT`, you can set a column header to make it `LEFT` or `CENTRE`
59 | - You can add a string Header, start with a `-` and it will be aligned `LEFT`, with a `'` it will be `CENTRE`
60 |
61 |
62 |
63 | #### Convert `Object[][]` to `ConsoleTable`
64 | If you already have ```Object[][] data```, you can print it on the console as a formatted table instantly:
65 |
66 | ```java
67 | ConsoleTable table = new ConsoleTable(data);
68 | System.out.print(table); // Note: table.toString() is called implicitly
69 | ```
70 |
71 | ## Quick Start
72 |
73 | * To get a quick demonstration, run ConsoleTable.java, the main() method prints out some samples.
74 | * To find out what Styles are available, run Styles.java, the main() method prints a sample of each predefined Style.
75 | * To display monospaced box-drawing characters in the Eclipse console, in Run | Run Configurations... , in the Common tab, set Encoding to Other UTF-8 or set the Project | Properties | Text File Encoding to UTF-8, so that it is inherited automatically by the Run Configurations.
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/src/com/johncsinclair/consoletable/ColumnFormat.java:
--------------------------------------------------------------------------------
1 | package com.johncsinclair.consoletable;
2 |
3 | /**
4 | * Format settings for a column in a {@link ConsoleTable}. Use a ColumnFormat
in {@link ConsoleTable#setHeaders}.
5 | *
6 | * @author Copyright (c) John C Sinclair 2021
7 | *
8 | */
9 | public class ColumnFormat {
10 |
11 | /**
12 | * A {@link ConsoleTable} column can be aligned LEFT, CENTRE or RIGHT.
13 | */
14 | public enum Aligned { LEFT, CENTRE, RIGHT };
15 |
16 | private String columnHeading;
17 | private Aligned alignment = Aligned.RIGHT;
18 |
19 | /**
20 | * @param columnHeading The heading for the column. By default the column will be right aligned,
21 | * if columnHeading starts with -
the column will be left aligned,
22 | * if columnHeading starts with '
the column will be centred.
23 | */
24 | public ColumnFormat(String columnHeading) {
25 | final char firstChar = columnHeading.charAt(0);
26 | if(firstChar == '-' || firstChar == '\'') {
27 | columnHeading = columnHeading.substring(1);
28 | this.alignment = firstChar == '-' ? Aligned.LEFT : Aligned.CENTRE;
29 | }
30 | this.columnHeading = columnHeading;
31 | }
32 |
33 | /**
34 | * @param columnHeading The heading for the column.
35 | * @param alignment The alignment for the column.
36 | */
37 | public ColumnFormat(String columnHeading, Aligned alignment) {
38 | this(columnHeading);
39 | this.alignment = alignment;
40 | }
41 |
42 | public Aligned getAlignment() {
43 | return alignment;
44 | }
45 |
46 | @Override
47 | public String toString() {
48 | return columnHeading;
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/com/johncsinclair/consoletable/ConsoleTable.java:
--------------------------------------------------------------------------------
1 | package com.johncsinclair.consoletable;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Collections;
5 | import java.util.List;
6 |
7 | import com.johncsinclair.consoletable.Style.Row;
8 | import com.johncsinclair.consoletable.Style.Column;
9 | import com.johncsinclair.consoletable.ColumnFormat.Aligned;
10 |
11 |
12 | /**
13 | * A {@code ConsoleTable} represents a table of rows and columns to be formatted into a
14 | * single {@code String}, which can be further printed on the console in a monospaced font.
15 | *
16 | * For example:
17 | *
18 | * Pet Age
19 | * --- ---
20 | * Cat 5
21 | * Dog 10
22 | *
23 | *
24 | * I started with CommandLineTable and added null handling, fluency, ColumnFormats and customisable Styles and tests.
25 | *
26 | * @author Copyright (c) John C Sinclair 2021
27 | */
28 | public class ConsoleTable {
29 |
30 | private static final Object[] NULL_OBJECT_ARRAY = (Object[])null;
31 | private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
32 | private Style style = Styles.LIGHT;
33 |
34 | private Object[] headers;
35 | private List rows = new ArrayList<>();
36 |
37 | private Aligned alignment = Aligned.RIGHT;
38 | private boolean showVerticalLines = true;
39 | private boolean withRowLines = false;
40 | private String leftColumnPadding = " ";
41 | private String rightColumnPadding = " ";
42 |
43 | private int rowWidth;
44 |
45 | /**
46 | * Constructor for empty table. The column headers can be set with setHeaders and data rows can be added with addRow.
47 | */
48 | public ConsoleTable() {
49 | withVerticalLines(true);
50 | }
51 |
52 | /**
53 | * Constructor for table of List with no headers.
54 | * @param data List of Object[] representing rows of columns.
55 | */
56 | public ConsoleTable(final List extends Object[]> data) {
57 | this();
58 | final Object[] emptyObjectArray = {};
59 | setHeaders(emptyObjectArray);
60 | rows.addAll(data);
61 | }
62 |
63 | /**
64 | * Constructor for List table with headers
65 | * @param headers array of Object representing table headers
66 | */
67 | public ConsoleTable(final Object[] headers, final List extends Object[]> data) {
68 | this(data);
69 | setHeaders(headers);
70 | }
71 |
72 | /**
73 | * Constructor for Object[][] table with no headers
74 | * @param headers_ - arrays of Strings representing table headers
75 | */
76 | public ConsoleTable(final Object[][] data) {
77 | this();
78 | for(Object[] row : data) {
79 | rows.add(row);
80 | }
81 | }
82 |
83 | /**
84 | * Constructor for Object[][] table with no headers
85 | * @param headers_ - arrays of Strings representing table headers
86 | */
87 | public ConsoleTable(final Object[] headers, final Object[][] data) {
88 | this(data);
89 | setHeaders(headers);
90 | }
91 |
92 | //TODO test this
93 | /**
94 | * Constructor for Object[][] table with no headers
95 | * @param headers_ - arrays of Strings representing table headers
96 | */
97 | public ConsoleTable(final Iterable headers, final Iterable> data) {
98 |
99 | for(T t : headers) {
100 | System.out.println(t);
101 | }
102 |
103 | for(Iterable row : data) {
104 | for( U column : row ) {
105 | System.out.printf("%s ", column);
106 | }
107 | System.out.println();
108 | }
109 |
110 |
111 | setHeaders(headers);
112 | throw new UnsupportedOperationException("TODO");
113 | }
114 |
115 | /**
116 | * Constructor for Object[][] table with no headers
117 | * @param headers_ - arrays of Strings representing table headers
118 | */
119 | public ConsoleTable(List headerList, List> rowList) {
120 | this();
121 |
122 | setHeaders( headerList.toArray(new Object[0]) );
123 |
124 | for(List row : rowList) {
125 | Object[] newRow = row.toArray();
126 | rows.add(newRow);
127 | }
128 |
129 | }
130 |
131 | /**
132 | * Constructor for table with headers
133 | * @param headers Strings representing table headers
134 | */
135 | public ConsoleTable(final String ... headers) {
136 | this();
137 | setHeaders(headers);
138 | }
139 |
140 |
141 |
142 | public ConsoleTable withStyle(Style style) {
143 | this.style = style;
144 | this.leftColumnPadding = style.getPadding(Column.LEFT);
145 | this.rightColumnPadding = style.getPadding(Column.RIGHT);
146 | return this;
147 | }
148 |
149 | public ConsoleTable withAlignment(Aligned aligned) {
150 | this.alignment = aligned;
151 | return this;
152 | }
153 |
154 | public ConsoleTable withVerticalLines(boolean showVerticalLines) {
155 | this.showVerticalLines = showVerticalLines;
156 | return this;
157 | }
158 |
159 | public ConsoleTable withColumnPadding(String leftColumnPadding, String rightColumnPadding) {
160 | this.leftColumnPadding = leftColumnPadding;
161 | this.rightColumnPadding = rightColumnPadding;
162 | return this;
163 | }
164 |
165 | public ConsoleTable withColumnPadding(String padding) {
166 | return this.withColumnPadding(padding, padding);
167 | }
168 |
169 | public ConsoleTable withRowLines(boolean showRowLines) {
170 | this.withRowLines = showRowLines;
171 | return this;
172 | }
173 |
174 | public ConsoleTable withRowLines() {
175 | this.withRowLines = true;
176 | return this;
177 | }
178 |
179 | /**
180 | * display a row of column headings at the top of the table
181 | *
182 | * @param headers The headings for the columns. By default a column will be right aligned, if it starts with -
the column will be left aligned, if it starts with '
the column will be centred.
183 | */
184 | public ConsoleTable setHeaders(Object... headers) {
185 |
186 | // if a String
starts with "-", make it left aligned, like String.format("%-s")
187 | // replace any String
headers starting with "-" with a Left aligned format, like String.format("%-9s")
188 | // have to copy the array to avoid an ArrayStoreException
189 |
190 | if( headers == null) {
191 | headers = EMPTY_OBJECT_ARRAY;
192 | }
193 |
194 | Object[] newHeaders = new Object[headers.length];
195 |
196 | for(int i = 0; i < headers.length; i++) {
197 | Object columnHeading = headers[i];
198 | if( columnHeading != null && columnHeading instanceof String && ((String) columnHeading).length() > 0 ) {
199 | char firstChar = ((String) columnHeading).charAt(0);
200 | if(firstChar == '-' || firstChar == '\'') {
201 | ColumnFormat columnFormat = new ColumnFormat( (String)columnHeading );
202 | columnHeading = columnFormat;
203 | }
204 | }
205 | newHeaders[i] = columnHeading;
206 | }
207 | this.headers = (newHeaders.length == 0) ? null : newHeaders;
208 |
209 | return this;
210 | }
211 |
212 | /**
213 | * display a row of column headings at the top of the table
214 | *
215 | * @param headers The headings for the columns. By default a column will be right aligned, if it starts with -
the column will be left aligned, if it starts with '
the column will be centred.
216 | * @return
217 | */
218 | public ConsoleTable setHeaders(String... headers) {
219 | Object[] objects = headers;
220 | setHeaders(objects);
221 | return this;
222 | }
223 |
224 |
225 | /**
226 | * Add a row of data
227 | */
228 | public void addRow(Object... cells) {
229 | if(cells == null) {
230 | addRow();
231 | return;
232 | }
233 | rows.add(cells);
234 | }
235 |
236 | /**
237 | * Add a row of data
238 | */
239 | public void addRow(String[] cells) {
240 | addRow( (Object[])cells );
241 | }
242 |
243 | /**
244 | * Add a row of data
245 | * @param
246 | */
247 | public void addRow(List cells) {
248 | if( cells == null ) {
249 | addRow();
250 | }
251 | else {
252 | addRow( cells.toArray() );
253 | }
254 | }
255 |
256 | /**
257 | * Add an empty row, all columns in the row will be empty.
258 | */
259 | public void addRow() {
260 | rows.add(NULL_OBJECT_ARRAY );
261 | }
262 |
263 | /**
264 | * Appends all of the elements in moreRows
to the end of the rows in this ConsoleTable.
265 | * @param moreRows
266 | */
267 | public void addAll(Iterable extends Object[]> moreRows) {
268 | for(Object[] row : moreRows) {
269 | if( row != null ) {
270 | rows.add( row );
271 | }
272 | else {
273 | rows.add( NULL_OBJECT_ARRAY );
274 | }
275 | }
276 | }
277 |
278 |
279 | /**
280 | * Returns a multi-line String
containing the formatted rows and columns of the table.
281 | */
282 | @Override
283 | public String toString() {
284 | return render();
285 | }
286 |
287 | private String render() {
288 |
289 | int[] maxWidths = calculateMaxWidths();
290 |
291 | rowWidth = calculateRowWidth(maxWidths);
292 |
293 | int renderedLineCount = rows.size();
294 | if(withRowLines) {
295 | renderedLineCount = renderedLineCount * 2;
296 | }
297 | if (headers != null) {
298 | renderedLineCount++;
299 | }
300 | StringBuffer buf = new StringBuffer(rowWidth * renderedLineCount); // TODO tableWidth()+1);
301 |
302 | buf.append(renderRow(Row.TOP, maxWidths, null));
303 |
304 | if (headers != null) {
305 | buf.append(renderRow(Row.HDRDATA, maxWidths, headers));
306 | buf.append(renderRow(Row.HDRLINE, maxWidths, null));
307 | }
308 |
309 | for (int i = 0; i < rows.size(); i++) {
310 | Object[] row = rows.get(i);
311 | buf.append(renderRow(Row.ROWDATA, maxWidths, row));
312 | if( i != renderedLineCount - 1 && withRowLines ) {
313 | buf.append(renderRow(Row.ROWLINE, maxWidths, null));
314 | }
315 | }
316 |
317 | buf.append(renderRow(Row.BOTTOM, maxWidths, null));
318 |
319 | return buf.toString();
320 | }
321 |
322 | private int calculateRowWidth(int[] columnWidths) {
323 |
324 | int rowWidth = 0;
325 | Row rowType = Row.ROWDATA;
326 |
327 | if(showVerticalLines) {
328 | rowWidth += style.getPattern(rowType, Column.LEFT).length();
329 | }
330 | for (int i = 0; i < columnWidths.length; i++) {
331 |
332 | String joinSep = showVerticalLines ? style.getPattern(rowType, Column.COLLINE) : " ";
333 | boolean isLastCell = i == columnWidths.length - 1;
334 |
335 | if(showVerticalLines)
336 | rowWidth += leftColumnPadding.length();
337 |
338 | rowWidth += columnWidths[i];
339 |
340 | if(showVerticalLines)
341 | rowWidth += rightColumnPadding.length();
342 | if(!isLastCell) {
343 | rowWidth += joinSep.length();
344 | }
345 | }
346 | if(showVerticalLines) {
347 | rowWidth += style.getPattern(rowType, Column.RIGHT).length();
348 | }
349 | rowWidth += "\n".length();
350 |
351 | return rowWidth;
352 | }
353 |
354 | public int[] calculateMaxWidths() {
355 |
356 | // instead of throwing exception, be permissive, and if header and data widths are not equal then display blanks at the end of header or data.
357 |
358 | List maxWidths = new ArrayList<>();
359 |
360 |
361 | if(headers != null) {
362 | for (int i = 0; i < headers.length; i++) {
363 | if( i > maxWidths.size() - 1 ) {
364 | maxWidths.add(0);
365 | }
366 | maxWidths.set(i, Math.max(maxWidths.get(i), headers[i] == null ? 0 : headers[i].toString().codePointCount(0, headers[i].toString().length()) ));
367 | }
368 | }
369 |
370 | for (Object[] cells : rows) {
371 | if(cells != null) {
372 | for (int i = 0; i < cells.length; i++) {
373 | if( i > maxWidths.size() - 1 ) {
374 | maxWidths.add(0);
375 | }
376 | maxWidths.set(i, Math.max(maxWidths.get(i), cells[i] == null ? 0 : cells[i].toString().codePointCount(0, cells[i].toString().length()) ));
377 | }
378 | }
379 | }
380 | return maxWidths.stream().mapToInt(Integer::intValue).toArray();
381 | }
382 |
383 | private String renderRow(Row rowType, int[] columnWidths, Object[] cells ) {
384 | if(style.getPattern(rowType, Column.LEFT) == null) {
385 | return "";
386 | }
387 |
388 | StringBuffer buf = new StringBuffer(rowWidth);
389 | if(showVerticalLines) {
390 | buf.append(style.getPattern(rowType, Column.LEFT));
391 | }
392 | for (int i = 0; i < columnWidths.length; i++) {
393 |
394 | int columnWidth = columnWidths[i];
395 | String cellString = null;
396 | String leftCellPadding = leftColumnPadding;
397 | String rightCellPadding = rightColumnPadding;
398 |
399 | Aligned columnAlign = alignment;
400 |
401 | if(rowType == Row.HDRDATA || rowType == Row.ROWDATA ) {
402 | String cell = (cells == null || i > cells.length -1 || cells[i] == null) ? "" : cells[i].toString();
403 |
404 | if(headers != null && i < headers.length && headers[i] != null && headers[i] instanceof ColumnFormat) {
405 | columnAlign = ((ColumnFormat)headers[i]).getAlignment();
406 | if(columnAlign == Aligned.CENTRE) {
407 | // left pad cell
so that it is centred
408 | int cellWidth = cell.codePointCount(0, cell.length());
409 | int leftPadWidth = (columnWidth - cellWidth+1) / 2;
410 | String padFormat = "%" + (leftPadWidth+cellWidth) + "s";
411 | cell = String.format(padFormat, cell);
412 | }
413 | }
414 |
415 | String formatString = "%"+(columnAlign == Aligned.RIGHT ? "" : "-")+columnWidth+"s";
416 | cellString = (columnWidth == 0) ? "" : String.format(formatString, cell);
417 | }
418 | else { // this is a rule line between the rows of the table
419 |
420 | String ruleString = style.getPattern(rowType, Column.COLDATA);
421 | columnWidth = leftCellPadding.length() + columnWidth + rightCellPadding.length();
422 | cellString = String.join("", Collections.nCopies(columnWidth, ruleString)).substring(0,columnWidth);
423 |
424 | leftCellPadding = "";
425 | rightCellPadding = "";
426 | }
427 |
428 | String joinSep = showVerticalLines ? style.getPattern(rowType, Column.COLLINE) : " ";
429 | boolean isLastCell = i == columnWidths.length - 1;
430 |
431 | buf.append(leftCellPadding);
432 | buf.append(cellString);
433 | buf.append(rightCellPadding);
434 |
435 | if(!isLastCell) {
436 | buf.append(joinSep);
437 | }
438 | }
439 | if(showVerticalLines) {
440 | buf.append(style.getPattern(rowType, Column.RIGHT));
441 | }
442 | buf.append("\n");
443 |
444 | return buf.toString();
445 | }
446 |
447 |
448 | public static void main(String[] args) {
449 |
450 | ConsoleTable table = new ConsoleTable();
451 | table.setHeaders("-City", "'Lat", "Longitude");
452 | table.addRow("Paris", 48.86,2.34);
453 | table.addRow("New York", 40.74, -73.99);
454 | table.addRow("London", 51.52, -0.13);
455 | table.addRow("Brisbane", -27.47, 153.03);
456 | System.out.println(table);
457 | System.out.println(table.withStyle(Styles.BASIC));
458 |
459 | //example code
460 | ConsoleTable example = new ConsoleTable();
461 | example.setHeaders("One", "Two", "Three"); //optional - if not used then there will be no header and no header line
462 | example.addRow(new java.math.BigDecimal("98.76"), "broccoli", "flexible");
463 | example.addRow(new java.math.BigDecimal("1.23"), "announcement", "reflection");
464 | example.addRow(new java.math.BigDecimal("1234.45"), null, java.time.LocalDateTime.now() );
465 | example.addRow( java.math.BigDecimal.ZERO, "pleasant", "wild");
466 |
467 | System.out.println("Example 1 - Default");
468 | System.out.println(example);
469 |
470 | System.out.println("Example 2 - Minimal");
471 | System.out.println(example.withStyle(Styles.MINIMAL).withAlignment(Aligned.LEFT));
472 |
473 | System.out.println("Example 3 - Minimal, with no Vertical Lines");
474 | example.withAlignment(Aligned.RIGHT);
475 | example.withVerticalLines(false);//if false (default) then no vertical lines are shown
476 | System.out.println(example);
477 |
478 | System.out.println("Example with row lines");
479 | ConsoleTable petTable = new ConsoleTable().withRowLines(true).withStyle(Styles.BASIC);
480 | petTable.setHeaders("Pet", "Age", "'Sex");
481 | petTable.addRow("Ant", 1, "M");
482 | petTable.addRow("Bat", 4, "F");
483 | petTable.addRow("Cat", 10, "F");
484 | petTable.addRow("Dog", 5, "M");
485 | System.out.println(petTable);
486 |
487 | String[] petHeaders = { "Pet", "Age", "'Sex" };
488 | Object[][] petData = {
489 | { "Cat", 10, "F" },
490 | { "Dog", 5, "M"}
491 | };
492 | ConsoleTable petShopTable = new ConsoleTable(petHeaders, petData).withStyle(Styles.BASIC);
493 | System.out.println(petShopTable);
494 |
495 | System.out.println("Example with a custom Style");
496 | class DoubleStyle implements Style {
497 | String[][] tablePattern = new String[][] {
498 | /* LEFT COLDATA COLLINE RIGHT */
499 | /* UMN */
500 | /* TOP */ {"x", "=", "x", "x" },
501 | /* HDRDATA */ {":", "H", ":", ":" },
502 | /* HDRLINE*/ {"x", "-", "x", "x" },
503 | /* ROWDATA */ {":", "D", ":", ":" },
504 | /* ROWLINE*/ {":", "-", ".", ":" },
505 | /* BOTTOM */ {"x", "=", "x", "x" } };
506 |
507 | @Override
508 | public String getPattern(Row row, Column column) {
509 | if(tablePattern[row.ordinal()] == null) {
510 | return null;
511 | } else {
512 | return tablePattern[row.ordinal()][column.ordinal()];
513 | }
514 | }
515 |
516 | public String[][] getTable() {
517 | return tablePattern;
518 | }
519 | }
520 |
521 | DoubleStyle doubleStyle = new DoubleStyle();
522 |
523 | ConsoleTable six = new ConsoleTable((doubleStyle).getTable()).withStyle(doubleStyle);
524 | six.setHeaders(new ColumnFormat("Left",Aligned.CENTRE),new ColumnFormat("Cell",Aligned.CENTRE),new ColumnFormat("Line",Aligned.CENTRE),new ColumnFormat("Right",Aligned.CENTRE));
525 | System.out.print(six);
526 |
527 | ConsoleTable styleDump = Styles.dumpStyle(doubleStyle);
528 | styleDump.withStyle(doubleStyle);
529 | System.out.print(styleDump);
530 |
531 | System.out.println("Example Alignment");
532 | ConsoleTable alignmentsTable = new ConsoleTable().withStyle(Styles.BASIC);
533 | alignmentsTable.setHeaders("-Width", new ColumnFormat("Left",Aligned.LEFT), new ColumnFormat("Centre",Aligned.CENTRE), new ColumnFormat("Right",Aligned.RIGHT));
534 | alignmentsTable.addRow("Short", "a", "1", "x");
535 | alignmentsTable.addRow("Medium", "b2", "22", "yy");
536 | alignmentsTable.addRow("Medium", "b23", "223", "yy3");
537 | alignmentsTable.addRow("Medium", "b234", "2234", "yy34");
538 | alignmentsTable.addRow("Longest", "c12345", "c234567", "z12345");
539 | System.out.print(alignmentsTable);
540 |
541 | ConsoleTable styleExample = new ConsoleTable().withStyle(Styles.LIGHT);
542 | styleExample.setHeaders("Header", "Header");
543 | styleExample.addRow("Cell","b2");
544 | styleExample.addRow("a3", "b3");
545 | System.out.print(styleExample);
546 |
547 | String[] zooHeaders = { "-Animal", "Cost", "'Sex" };
548 | Object[][] zooData = {
549 | { "Cat", new java.math.BigDecimal("10.00"), "F" },
550 | { "Zebra", new java.math.BigDecimal("5678.99"), "M"}
551 | };
552 |
553 | ConsoleTable zooTable = new ConsoleTable(zooHeaders, zooData).withStyle(Styles.PLAIN).withColumnPadding("", "");
554 | System.out.println(zooTable);
555 |
556 |
557 | }
558 |
559 |
560 | }
--------------------------------------------------------------------------------
/src/com/johncsinclair/consoletable/Style.java:
--------------------------------------------------------------------------------
1 | package com.johncsinclair.consoletable;
2 |
3 | /**
4 | * Describe the String
s that style the appearance of the lines and junctions of a {@link ConsoleTable}.
5 | *
6 | * LEFT COLLINE RIGHT
7 | * COLDATA COLDATA
8 | * TOP +--------+--------+
9 | * HDRDATA | Header | Header |
10 | * HDRLINE +--------+--------+
11 | * ROWDATA | Data | Data |
12 | * ROWLINE +--------+--------+
13 | * ROWDATA | Data | Data |
14 | * BOTTOM +--------+--------+
15 | *
16 | *
17 | * @author Copyright (c) John C Sinclair 2021
18 | *
19 | */
20 | public interface Style {
21 |
22 | /**
23 | * The types of rows that style the appearance of a {@link ConsoleTable}
24 | */
25 | public enum Row { TOP, HDRDATA, HDRLINE, ROWDATA, ROWLINE, BOTTOM }; // T HD HL RD RL B
26 |
27 | /**
28 | * The types of columns that style the appearance of a {@link ConsoleTable}
29 | */
30 | public enum Column { LEFT, COLDATA, COLLINE, RIGHT }; // L CD CL R
31 |
32 | /**
33 | * return the String
to display in the position in the table at the given row
and column
34 | *
35 | * @param row
36 | * @param column
37 | * @return the string to display at the given position of the ConsoleTable style, or null if the row
is not displayed for the style.
38 | */
39 | public String getPattern(Row row, Column column);
40 |
41 | /**
42 | * return the String
to display for either LEFT or RIGHT data column padding for this Style, by default a space.
43 | *
44 | * @param column
45 | * @return the string to display at the given side of each column for padding
46 | */
47 | public default String getPadding(Column column)
48 | {
49 | return " ";
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/com/johncsinclair/consoletable/Styles.java:
--------------------------------------------------------------------------------
1 | package com.johncsinclair.consoletable;
2 |
3 | import java.time.DayOfWeek;
4 | import java.time.format.TextStyle;
5 | import java.util.Locale;
6 |
7 |
8 | /**
9 | * Pre-configured {@link Style} for {@link ConsoleTable}.
10 | *
11 | * The Style of the table includes the outer border lines, the lines between the rows and the columns
12 | *
13 | * Example
14 | *
15 | * Pet Age
16 | * --- ---
17 | * Cat 5
18 | * Dog 10
19 | *
20 | *
21 | * @author Copyright (c) John C Sinclair 2021
22 | */
23 |
24 | public enum Styles implements Style {
25 |
26 | /**
27 | * A plain style with a header line.
28 | *
29 | * Example
30 | *
31 | * Pet Age
32 | * --- ---
33 | * Cat 5
34 | * Dog 10
35 | *
36 | */
37 | PLAIN (
38 | new String[][] {
39 | null,
40 | {"" , "H", " ", "" },
41 | {"" , "-", " ", "" },
42 | {"" , "1", " ", "" },
43 | null,
44 | null }
45 | ),
46 | /**
47 | * A minimal style with a dashed header line
48 | *
49 | * Example
50 | *
51 | * Pet Age
52 | * --- ---
53 | * Cat 5
54 | * Dog 10
55 | *
56 | */
57 | SQL (
58 | new String[][] {
59 | null,
60 | {"" , "H", " ", "" },
61 | {"" , "-", " ", "" },
62 | {"" , "1", " ", "" },
63 | null,
64 | null,
65 | {"" ,null,null, "" } }
66 | ),
67 | /**
68 | * A minimal table with no borders and no cell padding
69 | *
70 | * Example
71 | *
72 | * Pet Age
73 | * Cat 5
74 | * Dog 10
75 | *
76 | */
77 | MINIMAL (
78 | new String[][] {
79 | null,
80 | {"" , "H", " ", "" },
81 | null,
82 | {"" , "1", " ", "" },
83 | null,
84 | null,
85 | {"" ,null,null, "" } }
86 | ),
87 |
88 | /**
89 | * A minimal table with no vertical lines
90 | */
91 | NO_LINES (
92 | new String[][] {
93 | /* TOP */ null,
94 | /* HDRDATA*/ {"" , "H", "", "" },
95 | /* HDRLINE*/ null,
96 | /* ROWDATA*/ {"" , "1", "", "" },
97 | /* ROWLINE*/ null,
98 | /* BOTTOM */ null }
99 | ),
100 |
101 | /**
102 | * A simple border.
103 | */
104 | BORDER (
105 | new String[][] {
106 | /* LEFT COLDATA COLLINE RIGHT */
107 | /* TOP */ {"┌─", "─", "─", "─┐"},
108 | /* HDRDATA*/ {"│ ", "H", " ", " │"},
109 | /* HDRLINE*/ {"│ ", "─", " ", " │"},
110 | /* ROWDATA*/ {"│ ", "1", " ", " │"},
111 | /* ROWLINE*/ {"│ ", " ", " ", " │"},
112 | /* BOTTOM */ {"└─", "─", "─", "─┘"},
113 | /* PADDING*/ {"" ,null,null, "" } }
114 | ),
115 |
116 | /**
117 | * For a paper in a scientific research journal. No vertical lines.
118 | *
119 | * @see APA Style - Table Setup - American Psychological Association
120 | */
121 | SCIENTIFIC (
122 | new String[][] {
123 | /* LEFT COLDATA COLLINE RIGHT */
124 | /* TOP */ {"─", "─", "─", "─"},
125 | /* HDRDATA*/ {" ", "H", " ", " "},
126 | /* HDRLINE*/ {"─", "─", "─", "─"},
127 | /* ROWDATA*/ {" ", "D", " ", " "},
128 | /* ROWLINE*/ {" ", " ", " ", " "},
129 | /* BOTTOM */ {"─", "─", "─", "─"} }
130 | ),
131 | /**
132 | * javadoc testing2
133 | */
134 | BASIC (
135 | new String[][] {
136 | /* LEFT COLDATA COLLINE RIGHT */
137 | /* TOP */ {"+", "-", "+", "+"},
138 | /* HDRDATA*/ {"|", "H", "|", "|"},
139 | /* HDRLINE*/ {"+", "-", "+", "+"},
140 | /* ROWDATA*/ {"|", "1", "|", "|"},
141 | /* ROWLINE*/ {"+", "-", "+", "+"},
142 | /* BOTTOM */ {"+", "-", "+", "+"} }
143 | ),
144 |
145 | /**
146 | * A simple table.
147 | *
148 | * Example
149 | *
150 | * .─┬─.
151 | * │H│H│
152 | * ├─+─┤
153 | * │1│2│
154 | * ├─+─┤
155 | * │3│4│
156 | * .─┴─.
157 | *
158 | */
159 | SIMPLE (
160 | new String[][] {
161 | /* LEFT COLDATA COLLINE RIGHT */
162 | /* TOP */ {"·", "-", "-", "·"},
163 | /* HDRDATA*/ {"|", "H", "|", "|"},
164 | /* HDRLINE*/ {"|", "-", "+", "|"},
165 | /* ROWDATA*/ {"|", "1", "|", "|"},
166 | /* ROWLINE*/ {"|", "-", "+", "|"},
167 | /* BOTTOM */ {"·", "-", "-", "·"} }
168 | ),
169 |
170 | // BULLETS (
171 | // new String[][] {
172 | // /* LEFT COLDATA COLLINE RIGHT */
173 | // /* TOP */ {"•", " • ", "•", "•"},
174 | // /* HDRDATA*/ {"•", "H", "•", "•"},
175 | // /* HDRLINE*/ {"•", " • ", "•", "•"},
176 | // /* ROWDATA*/ {"•", "1", "•", "•"},
177 | // /* ROWLINE*/ {"•", " • ", "•", "•"},
178 | // /* BOTTOM */ {"•", " • ", "•", "•"} }
179 | // ),
180 |
181 | DOTS (
182 | new String[][] {
183 | /* LEFT COLDATA COLLINE RIGHT */
184 | /* TOP */ {".", ".", ".", "."},
185 | /* HDRDATA*/ {":", "H", ":", ":"},
186 | /* HDRLINE*/ {":", ".", ":", ":"},
187 | /* ROWDATA*/ {":", "1", ":", ":"},
188 | /* ROWLINE*/ {":", ".", ":", ":"},
189 | /* BOTTOM */ {":", ".", ":", ":"} }
190 | ),
191 |
192 | // U+00B7 · MIDDLE DOT · is not a full stop .
193 | MIDDLE_DOTS (
194 | new String[][] {
195 | /* LEFT COLDATA COLLINE RIGHT */
196 | /* TOP */ {"·", "·", "·", "·"},
197 | /* HDRDATA*/ {":", "H", ":", ":"},
198 | /* HDRLINE*/ {":", "·", ":", ":"},
199 | /* ROWDATA*/ {":", "1", ":", ":"},
200 | /* ROWLINE*/ {":", "·", ":", ":"},
201 | /* BOTTOM */ {"·", "·", "·", "·"} }
202 | ),
203 |
204 | DASHES (
205 | new String[][] {
206 | /* LEFT COLDATA COLLINE RIGHT */
207 | /* TOP */ {" ", "_", " ", " "},
208 | /* HDRDATA*/ {"|", "H", "|", "|"},
209 | /* HDRLINE*/ {"|", "_", "|", "|"},
210 | /* ROWDATA*/ {"|", "1", "|", "|"},
211 | /* ROWLINE*/ {"|", "_", "|", "|"},
212 | /* BOTTOM */ {"|", "_", "|", "|"} }
213 | ),
214 |
215 | STARS (
216 | new String[][] {
217 | /* LEFT COLDATA COLLINE RIGHT */
218 | /* TOP */ {"*", ".", "*", "*"},
219 | /* HDRDATA*/ {":", "H", ":", ":"},
220 | /* HDRLINE*/ {":", ".", "*", ":"},
221 | /* ROWDATA*/ {":", "1", ":", ":"},
222 | /* ROWLINE*/ {":", ".", "*", ":"},
223 | /* BOTTOM */ {"*", ".", "*", "*"} }
224 | ),
225 |
226 | /**
227 | * A light continuous border using Unicode box drawing characters.
228 | *
229 | * ┌─┬┐
230 | * │H││
231 | * ├─┼┤
232 | * │D││
233 | * ├─┼┤
234 | * └─┴┘
235 | *
236 | */
237 | LIGHT (
238 | new String[][] {
239 | /* LEFT COLDATA COLLINE RIGHT */
240 | /* TOP */ {"┌", "─", "┬", "┐"},
241 | /* HDRDATA*/ {"│", "H", "│", "│"},
242 | /* HDRLINE*/ {"├", "─", "┼", "┤"},
243 | /* ROWDATA*/ {"│", "1", "│", "│"},
244 | /* ROWLINE*/ {"├", "─", "┼", "┤"},
245 | /* BOTTOM */ {"└", "─", "┴", "┘"} }
246 | ),
247 |
248 | DASHED ( new String[][] {
249 | /* LEFT COLDATA COLLINE RIGHT */
250 | /* TOP */ {"┌", "╌", "┬", "┐"},
251 | /* HDRDATA*/ {"┆", "H", "┆", "┆"},
252 | /* HDRLINE*/ {"┆", "╌", "┆", "┆"},
253 | /* ROWDATA*/ {"┆", "1", "┆", "┆"},
254 | /* ROWLINE*/ {"┆", "╌", "┆", "┆"},
255 | /* BOTTOM */ {"└", "╌", "┴", "┘"} }
256 | ),
257 |
258 | ROUNDED ( new String[][] {
259 | /* LEFT COLDATA COLLINE RIGHT */
260 | /* TOP */ {"╭", "─", "┬", "╮"},
261 | /* HDRDATA*/ {"│", "H", "│", "│"},
262 | /* HDRLINE*/ {"├", "─", "┼", "┤"},
263 | /* ROWDATA*/ {"│", "1", "│", "│"},
264 | /* ROWLINE*/ {"├", "─", "┼", "┤"},
265 | /* BOTTOM */ {"╰", "─", "┴", "╯"} }
266 | ),
267 |
268 | HEAVY ( new String[][] {
269 | /* LEFT COLDATA COLLINE RIGHT */
270 | /* TOP */ {"┏", "━", "┳", "┓"},
271 | /* HDRDATA*/ {"┃", "H", "┃", "┃"},
272 | /* HDRLINE*/ {"┣", "━", "╋", "┫"},
273 | /* ROWDATA*/ {"┃", "1", "┃", "┃"},
274 | /* ROWLINE*/ {"┣", "━", "╋", "┫"},
275 | /* BOTTOM */ {"┗", "━", "┻", "┛"} }
276 | ),
277 |
278 | HEAVY_BORDER ( new String[][] {
279 | /* LEFT COLDATA COLLINE RIGHT */
280 | /* TOP */ {"┏", "━", "┯", "┓"},
281 | /* HDRDATA*/ {"┃", "H", "│", "┃"},
282 | /* HDRLINE*/ {"┣", "━", "┿", "┫"},
283 | /* ROWDATA*/ {"┃", "1", "│", "┃"},
284 | /* ROWLINE*/ {"┠", "─", "┼", "┨"},
285 | /* BOTTOM */ {"┗", "━", "┷", "┛"} }
286 | ),
287 |
288 | LIGHT_HEADER ( new String[][] {
289 | /* LEFT COLDATA COLLINE RIGHT */
290 | /* TOP */ {"┏", "━", "┯", "┓"},
291 | /* HDRDATA*/ {"┃", "H", "│", "┃"},
292 | /* HDRLINE*/ {"┠", "─", "┼", "┨"},
293 | /* ROWDATA*/ {"┃", "1", "│", "┃"},
294 | /* ROWLINE*/ {"┠", "─", "┼", "┨"},
295 | /* BOTTOM */ {"┗", "━", "┷", "┛"} }
296 | ),
297 |
298 | DOUBLE_BORDER ( new String[][] {
299 | /* LEFT COLDATA COLLINE RIGHT */
300 | /* TOP */ {"╔", "═", "╤", "╗"},
301 | /* HDRDATA*/ {"║", "H", "│", "║"},
302 | /* HDRLINE*/ {"╠", "═", "╪", "╣"},
303 | /* ROWDATA*/ {"║", "1", "│", "║"},
304 | /* ROWLINE*/ {"╟", "─", "┼", "╢"},
305 | /* BOTTOM */ {"╚", "═", "╧", "╝"} }
306 | ),
307 |
308 | DOUBLED ( new String[][] {
309 | /* LEFT COLDATA COLLINE RIGHT */
310 | /* TOP */ {"┌", "─", "┐┌", "┐"},
311 | /* HDRDATA*/ {"│", "H", "││", "│"},
312 | /* HDRLINE*/ {"├", "─", "┤├", "┤"},
313 | /* ROWDATA*/ {"│", "1", "││", "│"},
314 | /* ROWLINE*/ {"├", "─", "┤├", "┤"},
315 | /* BOTTOM */ {"└", "─", "┘└", "┘"} }
316 | ),
317 |
318 | COMPACT ( new String[]{
319 | "┌─┬┐", // T
320 | "│H││", // HD
321 | "├─┼┤", // HL
322 | "│D││", // RD
323 | "├─┼┤", // RL
324 | "└─┴┘"} // B
325 | );
326 |
327 |
328 | private String[][] tablePattern;
329 |
330 | private Styles (String[][] tablePattern){
331 | this.tablePattern = tablePattern;
332 | }
333 |
334 | private Styles (String[] compactPattern){
335 | String[][] pattern = new String[Row.values().length][Column.values().length];
336 | for(Row row : Row.values()) {
337 | // TODO - handle null row
338 | for(Column column : Column.values()) {
339 | pattern[row.ordinal()][column.ordinal()] = String.valueOf( compactPattern[row.ordinal()].charAt(column.ordinal()) );
340 | }
341 | }
342 | this.tablePattern = pattern;
343 | }
344 |
345 | @Override
346 | public String getPattern(Row row, Column column) {
347 |
348 | // TODO if row.ordinal() > tablePattern[].length throw a helpful exception for a Style developer. ( or col.ordinal() )
349 |
350 | if(tablePattern[row.ordinal()] == null) {
351 | return null;
352 | } else {
353 | return tablePattern[row.ordinal()][column.ordinal()];
354 | }
355 | }
356 |
357 | /**
358 | * return the String
to display for either LEFT or RIGHT column padding for this Style
359 | *
360 | * @param row
361 | * @param column
362 | * @return null if the row
is not displayed, otherwise the string to display at the given position of the ConsoleTable style
363 | */
364 | @Override
365 | public String getPadding(Column column)
366 | {
367 | if(column == Column.LEFT || column == Column.RIGHT) {
368 | if( tablePattern.length > Row.BOTTOM.ordinal()+1) {
369 | return tablePattern[Row.BOTTOM.ordinal()+1][column.ordinal()];
370 | }
371 | else {
372 | return " ";
373 | }
374 | }
375 | else {
376 | throw new IllegalArgumentException();
377 | }
378 | }
379 |
380 |
381 |
382 |
383 | public static void main(String[] args) {
384 |
385 | ConsoleTable petTable = new ConsoleTable();
386 | petTable.setHeaders("Pet", "Age", "'Sex");
387 | petTable.addRow("Ant", 1, "M");
388 | petTable.addRow("Bat", 4, "F");
389 | petTable.addRow("Cat", 10, "F");
390 | petTable.addRow("Dog", 5, "M");
391 |
392 | System.out.println("Example of all Styles");
393 | petTable.withVerticalLines(true);
394 | petTable.withColumnPadding("", "");
395 | for(Styles sample : Styles.values()) {
396 | System.out.printf("withStyle(Styles.%s)\n",sample.toString());
397 | System.out.print(petTable.withStyle(sample));
398 | System.out.println();
399 | }
400 |
401 |
402 |
403 |
404 | for(Style sample : Styles.values()) {
405 | ConsoleTable sampleDump = dumpStyle(sample);
406 | sampleDump.withStyle(sample);
407 | System.out.format("withStyle(Styles.%s)\n",sample.toString());
408 | System.out.print(sampleDump);
409 | System.out.println();
410 | }
411 |
412 |
413 | ConsoleTable tinySample = new ConsoleTable().withRowLines(false);
414 | tinySample.setHeaders("H", "H");
415 | tinySample.addRow(1, "a");
416 | tinySample.addRow(2, "b");
417 |
418 |
419 | System.out.println("Example of all Styles");
420 | for(Styles sample : Styles.values()) {
421 | System.out.printf("withStyle(Styles.%s)\n",sample.toString());
422 | System.out.print(tinySample.withStyle(sample));
423 | System.out.println();
424 | }
425 |
426 | for(Styles sample : Styles.values()) {
427 | System.out.printf("withStyle(Styles.%s)\n",sample.toString());
428 | ConsoleTable dayTable = new ConsoleTable();
429 | dayTable.setHeaders("Enum","English", "French", "German");
430 | for( DayOfWeek dayOfWeek : DayOfWeek.values()) {
431 | dayTable.addRow( dayOfWeek, dayOfWeek.getDisplayName(TextStyle.FULL, Locale.ENGLISH),
432 | dayOfWeek.getDisplayName(TextStyle.FULL, Locale.FRENCH), dayOfWeek.getDisplayName(TextStyle.FULL, Locale.GERMAN),
433 | (dayOfWeek.getValue()-1)*20);
434 | }
435 | System.out.print(dayTable.withStyle(sample));
436 | System.out.println();
437 | }
438 |
439 | }
440 |
441 | /**
442 | * return a {@link ConsoleTable} illustrating the rows and columns that make up the given {@link Style}.
443 | *
444 | * @param dumpStyle
445 | * @return
446 | */
447 | public static ConsoleTable dumpStyle(Style dumpStyle) {
448 |
449 | String padding = null;
450 | String leftPadding = dumpStyle.getPadding(Column.LEFT);
451 | String rightPadding = dumpStyle.getPadding(Column.RIGHT);
452 | if( ! ( leftPadding.equals(" ") && rightPadding.equals(" ") ) ) {
453 | padding = "padding('"+leftPadding+"','"+rightPadding+"')";
454 | System.out.println(padding);
455 | }
456 |
457 | String[] styleHeaders = new String[Column.values().length+1];
458 | String[][] styleData = new String[Row.values().length][Column.values().length+1];
459 |
460 | for( Column column : Column.values() ) {
461 | styleHeaders[column.ordinal()+1] = "'"+column.name();
462 | }
463 | for( Row row : Row.values() ) {
464 | styleData[row.ordinal()][0] = row.name();
465 | for( Column column : Column.values() ) {
466 | String pattern = dumpStyle.getPattern(row, column);
467 | if(pattern == null) {
468 | if(column == Column.LEFT) {
469 | pattern = "null";
470 | }
471 | else {
472 | pattern = "";
473 | }
474 | }
475 | else if( pattern.equals("")) {
476 | pattern = "''";
477 | }
478 | else if( !pattern.trim().equals(pattern)) {
479 | pattern = "'" + pattern +"'";
480 | }
481 | styleData[row.ordinal()][column.ordinal()+1] = pattern;
482 | }
483 | }
484 | return new ConsoleTable(styleHeaders, styleData);
485 | }
486 |
487 | }
--------------------------------------------------------------------------------
/test/com/johncsinclair/consoletable/ConsoleTableTest.java:
--------------------------------------------------------------------------------
1 | package com.johncsinclair.consoletable;
2 |
3 | import static org.junit.jupiter.api.Assertions.*;
4 |
5 | import java.math.BigDecimal;
6 | import java.time.LocalDate;
7 | import java.util.Arrays;
8 | import java.util.List;
9 |
10 | import org.junit.jupiter.api.Test;
11 |
12 | import com.johncsinclair.consoletable.ColumnFormat.Aligned;
13 |
14 |
15 | /**
16 | * JUnit 5 Tests for ConsoleTable
17 | *
18 | * To display monospaced box-drawing characters, In Eclipse, in Run | Run Configurations... , in the Common tab, set Encoding to Other UTF-8,
19 | * or set the Project | Properties | Text File Encoding to UTF-8, so that it is inherited automatically by the Run Configurations.
20 | *
21 | * @see How to make eclipse junit stacktrace use non-proportional font?
22 | *
23 | * @author Copyright (c) John C Sinclair 2021
24 | */
25 |
26 | class ConsoleTableTest {
27 |
28 | @Test
29 | void testExample1() {
30 | ConsoleTable table = new ConsoleTable();
31 | table.setHeaders("One", "Two", "Three"); //optional - if not used then there will be no header and horizontal lines
32 | table.addRow(new java.math.BigDecimal("98.76"), "broccoli", "flexible");
33 | table.addRow(new java.math.BigDecimal("1.23"), "announcement", "reflection");
34 | table.addRow(new java.math.BigDecimal("1234.45"), null, java.time.LocalDateTime.parse("2020-12-24T14:15:16.987") );
35 | table.addRow( java.math.BigDecimal.ZERO, "pleasant", "wild");
36 |
37 | String expected =
38 | "┌─────────┬──────────────┬─────────────────────────┐"+"\n"+
39 | "│ One │ Two │ Three │"+"\n"+
40 | "├─────────┼──────────────┼─────────────────────────┤"+"\n"+
41 | "│ 98.76 │ broccoli │ flexible │"+"\n"+
42 | "│ 1.23 │ announcement │ reflection │"+"\n"+
43 | "│ 1234.45 │ │ 2020-12-24T14:15:16.987 │"+"\n"+
44 | "│ 0 │ pleasant │ wild │"+"\n"+
45 | "└─────────┴──────────────┴─────────────────────────┘"+"\n";
46 | assertLinesMatch( Arrays.asList(expected.split("\n")),
47 | Arrays.asList(table.toString().split("\n")), "four");
48 | }
49 |
50 | @Test
51 | void testStylePositions() {
52 | class UniqueStyle implements Style {
53 | // a different character in every position to check each is correct
54 | String[][] tablePattern = new String[][] {
55 | /* LEFT CD CL RIGHT */
56 | /* TOP */ {"┌", "^", "T", "┐"},
57 | /* HDRDATA */ {"1", "F", ":", "H"},
58 | /* HDRLINE*/ {"J", "-", "+", "M"},
59 | /* ROWDATA */ {"l", "O", "!", "r"},
60 | /* ROWLINE*/ {"R", ".", "U", "V"},
61 | /* BOTTOM */ {"└", "v", "t", "┘"}
62 | };
63 |
64 | @Override
65 | public String getPattern(Row row, Column column) {
66 | if(tablePattern[row.ordinal()] == null) {
67 | return null;
68 | } else {
69 | return tablePattern[row.ordinal()][column.ordinal()];
70 | }
71 | }
72 | }
73 | Style testStyle = new UniqueStyle();
74 | ConsoleTable table = new ConsoleTable().withStyle(testStyle);
75 | table.setHeaders("One", "Two", "Three");//optional - if not used then there will be no header and horizontal lines
76 | table.addRow(new java.math.BigDecimal("98.76"), "broccoli", "flexible");
77 | table.addRow(new java.math.BigDecimal("1.23"), "announcement", "reflection");
78 | table.addRow(new java.math.BigDecimal("1234.45"), null, java.time.LocalDateTime.parse("2020-12-24T14:15:16.987") );
79 | table.addRow( java.math.BigDecimal.ZERO, "pleasant", "wild");
80 |
81 | String expected =
82 | "┌^^^^^^^^^T^^^^^^^^^^^^^^T^^^^^^^^^^^^^^^^^^^^^^^^^┐"+"\n"+
83 | "1 One : Two : Three H"+"\n"+
84 | "J---------+--------------+-------------------------M"+"\n"+
85 | "l 98.76 ! broccoli ! flexible r"+"\n"+
86 | "l 1.23 ! announcement ! reflection r"+"\n"+
87 | "l 1234.45 ! ! 2020-12-24T14:15:16.987 r"+"\n"+
88 | "l 0 ! pleasant ! wild r"+"\n"+
89 | "└vvvvvvvvvtvvvvvvvvvvvvvvtvvvvvvvvvvvvvvvvvvvvvvvvv┘"+"\n";
90 |
91 | assertLinesMatch( Arrays.asList(expected.split("\n")),
92 | Arrays.asList(table.toString().split("\n")), "four");
93 | }
94 |
95 | @Test
96 | void testWideStylePositions() {
97 | class UniqueWide implements Style {
98 | // a different multi character String in every position to check each is correct
99 | String[][] tablePattern = new String[][] {
100 | /* LEFT COLDATA COLLINE RIGHT */
101 | /* UMN */
102 | /* TOP */ {"x┌", "^-", "wT", "z┐"},
103 | /* HDRDATA */ {"x1", "HD", "w:", "zH"},
104 | /* HDRLINE*/ {"xJ", "-─", "w+", "zM"},
105 | /* ROWDATA */ {"xl", "DA", "w!", "zr"},
106 | /* ROWLINE*/ {"xR", ".,", "wU", "zV"},
107 | /* BOTTOM */ {"x└", "v-", "wt", "z┘"}
108 | };
109 |
110 | @Override
111 | public String getPattern(Row row, Column column) {
112 | if(tablePattern[row.ordinal()] == null) {
113 | return null;
114 | } else {
115 | return tablePattern[row.ordinal()][column.ordinal()];
116 | }
117 | }
118 | }
119 | Style uniqueWide = new UniqueWide();
120 | ConsoleTable table = new ConsoleTable().withStyle(uniqueWide);
121 | table.setHeaders("One", "Two", "Three");//optional - if not used then there will be no header and horizontal lines
122 | table.addRow(new java.math.BigDecimal("98.76"), "broccoli", "flexible");
123 | table.addRow(new java.math.BigDecimal("1.23"), "announcement", "reflection");
124 | table.addRow(new java.math.BigDecimal("1234.45"), null, java.time.LocalDateTime.parse("2020-12-24T14:15:16.987") );
125 | table.addRow( java.math.BigDecimal.ZERO, "pleasant", "wild");
126 |
127 | String expected =
128 | "x┌^-^-^-^-^wT^-^-^-^-^-^-^-wT^-^-^-^-^-^-^-^-^-^-^-^-^z┐"+"\n"+
129 | "x1 One w: Two w: Three zH"+"\n"+
130 | "xJ-─-─-─-─-w+-─-─-─-─-─-─-─w+-─-─-─-─-─-─-─-─-─-─-─-─-zM"+"\n"+
131 | "xl 98.76 w! broccoli w! flexible zr"+"\n"+
132 | "xl 1.23 w! announcement w! reflection zr"+"\n"+
133 | "xl 1234.45 w! w! 2020-12-24T14:15:16.987 zr"+"\n"+
134 | "xl 0 w! pleasant w! wild zr"+"\n"+
135 | "x└v-v-v-v-vwtv-v-v-v-v-v-v-wtv-v-v-v-v-v-v-v-v-v-v-v-vz┘"+"\n";
136 |
137 | assertLinesMatch( Arrays.asList(expected.split("\n")),
138 | Arrays.asList(table.toString().split("\n")), "four");
139 | }
140 |
141 | @Test
142 | void testCompactStyle() {
143 | /** a compact implementation of {@link Style} for single character lines and junctions
144 | *
145 | * @author John Sinclair 2020-02-06
146 | */
147 | class CompactLight implements Style {
148 | String[] compactPattern = {
149 | "┌─┬┐", // T
150 | "│H││", // HD
151 | "├─┼┤", // HL
152 | "│D││", // RD
153 | "├─┼┤", // RL
154 | "└─┴┘"};// B
155 |
156 | @Override
157 | public String getPattern(Row row, Column column) {
158 | if(compactPattern[row.ordinal()] != null) {
159 | return String.valueOf( compactPattern[ row.ordinal() ].charAt( column.ordinal() ) );
160 | }
161 | return null;
162 |
163 | }
164 | }
165 |
166 | ConsoleTable table = new ConsoleTable().withRowLines();
167 | table.setHeaders("One", "Two", "Three");
168 | table.addRow(new java.math.BigDecimal("98.76"), "broccoli", "flexible");
169 | table.addRow(new java.math.BigDecimal("1.23"), "announcement", "reflection");
170 | table.addRow(new java.math.BigDecimal("1234.45"), null, java.time.LocalDateTime.parse("2020-12-24T14:15:16.987") );
171 | table.addRow( java.math.BigDecimal.ZERO, "pleasant", "wild");
172 |
173 | String actual = table.withStyle(new CompactLight()).toString();
174 | String expected = table.withStyle(Styles.LIGHT).toString();
175 |
176 | assertLinesMatch( Arrays.asList(expected.split("\n")),
177 | Arrays.asList(actual.split("\n")), "CompactLight Style");
178 | }
179 |
180 | @Test
181 | void testNull() {
182 | ConsoleTable emptyTable = new ConsoleTable().withStyle(Styles.HEAVY_BORDER);
183 |
184 | assertEquals(
185 | "┏┓\n"+
186 | "┗┛\n", emptyTable.toString());
187 | }
188 |
189 | @Test
190 | void testNullHeaders() {
191 | ConsoleTable emptyTable = new ConsoleTable().withStyle(Styles.HEAVY);
192 | emptyTable.setHeaders(null);
193 |
194 | assertEquals(
195 | "┏┓"+"\n"+
196 | "┗┛"+"\n", emptyTable.toString());
197 | }
198 |
199 | @Test
200 | void testNullHeadersCast() {
201 | ConsoleTable emptyTable = new ConsoleTable().withStyle(Styles.LIGHT);
202 | emptyTable.setHeaders((Object[])null);
203 |
204 | assertEquals(
205 | "┌┐"+"\n"+
206 | "└┘"+"\n", emptyTable.toString());
207 | }
208 |
209 | @Test
210 | void testTwoNullHeaders() {
211 | ConsoleTable emptyTable = new ConsoleTable().withStyle(Styles.BASIC).withColumnPadding("");
212 | emptyTable.setHeaders((Object[])null, (Object[])null);
213 |
214 | assertEquals(
215 | "+++"+"\n"+
216 | "|||"+"\n"+
217 | "+++"+"\n"+
218 | "+++"+"\n", emptyTable.toString());
219 | }
220 |
221 | @Test
222 | void testEmptyHeaders() {
223 | ConsoleTable emptyTable = new ConsoleTable().withStyle(Styles.HEAVY_BORDER);
224 | emptyTable.setHeaders();
225 |
226 | assertEquals(
227 | "┏┓"+"\n"+
228 | "┗┛"+"\n", emptyTable.toString());
229 | }
230 |
231 | @Test
232 | void testNullRow() {
233 | ConsoleTable emptyTable = new ConsoleTable().withStyle(Styles.HEAVY_BORDER).withColumnPadding("","");;
234 | emptyTable.addRow();
235 |
236 | assertEquals(
237 | "┏┓"+"\n"+
238 | "┃┃"+"\n"+
239 | "┗┛"+"\n", emptyTable.toString());
240 | }
241 |
242 | @Test
243 | void testNullColumnRow() {
244 | ConsoleTable table = new ConsoleTable().withStyle(Styles.BASIC).withColumnPadding("","");
245 | table.addRow("a",null,"pq");
246 | table.addRow("b","", "rs");
247 |
248 | // if a column has no heading and no data then max width is 0 and it should have a width of 0
249 | String expected =
250 | "+-++--+"+"\n"+
251 | "|a||pq|"+"\n"+
252 | "|b||rs|"+"\n"+
253 | "+-++--+"+"\n";
254 | assertLinesMatch( Arrays.asList(expected.split("\n")),
255 | Arrays.asList(table.toString().split("\n")), "if a column has no heading and no data then max width is 0 and it should have a width of 0");
256 |
257 | }
258 |
259 | @Test
260 | void testAddRowEmpty() {
261 | ConsoleTable table = new ConsoleTable().withStyle(Styles.LIGHT).withColumnPadding("");
262 | table.addRow();
263 |
264 | String expected =
265 | "┌┐"+"\n"+
266 | "││"+"\n"+
267 | "└┘"+"\n";
268 | assertLinesMatch( Arrays.asList(expected.split("\n")),
269 | Arrays.asList(table.toString().split("\n")), "if a column has no heading and no data then max width is 0 and it should have a width of 0");
270 |
271 | }
272 |
273 | @Test
274 | void testAddRowNullCastObjectArray() {
275 | ConsoleTable table = new ConsoleTable().withStyle(Styles.LIGHT).withColumnPadding("");
276 | table.addRow( (Object[])null );
277 |
278 | String expected =
279 | "┌┐"+"\n"+
280 | "││"+"\n"+
281 | "└┘"+"\n";
282 |
283 | assertLinesMatch( Arrays.asList(expected.split("\n")),
284 | Arrays.asList(table.toString().split("\n")), "if a column has no heading and no data then max width is 0 and it should have a width of 0");
285 | }
286 |
287 | @Test
288 | void testAddRowNullCastObject() {
289 | ConsoleTable table = new ConsoleTable().withStyle(Styles.LIGHT).withColumnPadding("");
290 | table.addRow( (Object)null );
291 |
292 | String expected =
293 | "┌┐"+"\n"+
294 | "││"+"\n"+
295 | "└┘"+"\n";
296 |
297 | assertLinesMatch( Arrays.asList(expected.split("\n")),
298 | Arrays.asList(table.toString().split("\n")), "if a column has no heading and no data then max width is 0 and it should have a width of 0");
299 | }
300 |
301 | @Test
302 | void testAddRowNullCastList() {
303 | ConsoleTable table = new ConsoleTable().withStyle(Styles.LIGHT).withColumnPadding("");
304 | table.addRow( (List)null );
305 |
306 | String expected =
307 | "┌┐"+"\n"+
308 | "││"+"\n"+
309 | "└┘"+"\n";
310 |
311 | assertLinesMatch( Arrays.asList(expected.split("\n")),
312 | Arrays.asList(table.toString().split("\n")), "if a column has no heading and no data then max width is 0 and it should have a width of 0");
313 | }
314 |
315 | @Test
316 | void testAddRowEmptyString() {
317 | ConsoleTable table = new ConsoleTable().withStyle(Styles.LIGHT).withColumnPadding("");
318 | table.addRow( "" );
319 |
320 | String expected =
321 | "┌┐"+"\n"+
322 | "││"+"\n"+
323 | "└┘"+"\n";
324 |
325 | assertLinesMatch( Arrays.asList(expected.split("\n")),
326 | Arrays.asList(table.toString().split("\n")), "if a column has no heading and no data then max width is 0 and it should have a width of 0");
327 | }
328 |
329 | @Test
330 | void testOneHeader() {
331 | ConsoleTable table = new ConsoleTable().withStyle(Styles.HEAVY_BORDER);
332 | table.setHeaders("hdr");
333 |
334 | assertEquals(
335 | "┏━━━━━┓"+"\n"+
336 | "┃ hdr ┃"+"\n"+
337 | "┣━━━━━┫"+"\n"+
338 | "┗━━━━━┛"+"\n", table.toString());
339 | }
340 |
341 | @Test
342 | void testOneByOne() {
343 | ConsoleTable table = new ConsoleTable().withStyle(Styles.HEAVY_BORDER);
344 | table.addRow("1x1");
345 |
346 | assertEquals(
347 | "┏━━━━━┓"+"\n"+
348 | "┃ 1x1 ┃"+"\n"+
349 | "┗━━━━━┛"+"\n", table.toString());
350 | }
351 |
352 | @Test
353 | void testTwoByTwo() {
354 | ConsoleTable twoByTwo = new ConsoleTable().withStyle(Styles.HEAVY_BORDER).withColumnPadding(",.",".,");
355 | twoByTwo.addRow("1a", "1b");
356 | twoByTwo.addRow("2a", "2b");
357 |
358 | assertEquals(
359 | "┏━━━━━━┯━━━━━━┓"+"\n"+
360 | "┃,.1a.,│,.1b.,┃"+"\n"+
361 | "┃,.2a.,│,.2b.,┃"+"\n"+
362 | "┗━━━━━━┷━━━━━━┛"+"\n",
363 | twoByTwo.toString(), "TwoByTwo with double padding");
364 |
365 |
366 | // MyAssert.assertLinesEqual(
367 | String expected =
368 | "┏━━━━━━┯━━━━━━┓"+"\n"+
369 | "┃,.1a.,│,.1b.,┃"+"\n"+
370 | "┃,.2a.,│,.2b.,┃"+"\n"+
371 | "┗━━━━━━┷━━━━━━┛"+"\n";
372 |
373 | assertLinesMatch( Arrays.asList(expected.split("\n")),
374 | Arrays.asList(twoByTwo.toString().split("\n")), "TwoByTwo with double padding");
375 |
376 | }
377 |
378 | @Test
379 | void testThreeByThree() {
380 | ConsoleTable threeByThree = new ConsoleTable().withStyle(Styles.HEAVY_BORDER);
381 | threeByThree.setHeaders("a1");
382 | threeByThree.addRow("a2","b2");
383 | threeByThree.addRow("a3", "b3", "c3");
384 |
385 | String expected =
386 | "┏━━━━┯━━━━┯━━━━┓"+"\n"+
387 | "┃ a1 │ │ ┃"+"\n"+
388 | "┣━━━━┿━━━━┿━━━━┫"+"\n"+
389 | "┃ a2 │ b2 │ ┃"+"\n"+
390 | "┃ a3 │ b3 │ c3 ┃"+"\n"+
391 | "┗━━━━┷━━━━┷━━━━┛"+"\n";
392 |
393 | assertLinesMatch( Arrays.asList(expected.split("\n")),
394 | Arrays.asList(threeByThree.toString().split("\n")), "test three by three with empty headers and cells");
395 |
396 | }
397 |
398 | @Test
399 | void testFourByFourAndColumnFormat() {
400 | ConsoleTable four = new ConsoleTable().withStyle(Styles.HEAVY_BORDER);
401 | four.setHeaders("a1", new ColumnFormat("a2", Aligned.LEFT), "a3");
402 | four.addRow("a2", "b2");
403 | four.addRow();
404 | four.addRow("widea3", "wideb3", "widec3");
405 |
406 | String expected =
407 | "┏━━━━━━━━┯━━━━━━━━┯━━━━━━━━┓"+"\n"+
408 | "┃ a1 │ a2 │ a3 ┃"+"\n"+
409 | "┣━━━━━━━━┿━━━━━━━━┿━━━━━━━━┫"+"\n"+
410 | "┃ a2 │ b2 │ ┃"+"\n"+
411 | "┃ │ │ ┃"+"\n"+
412 | "┃ widea3 │ wideb3 │ widec3 ┃"+"\n"+
413 | "┗━━━━━━━━┷━━━━━━━━┷━━━━━━━━┛"+"\n";
414 | assertLinesMatch( Arrays.asList(expected.split("\n")),
415 | Arrays.asList(four.toString().split("\n")), "test four by four with empty rows and ColumnFormat");
416 | // assertArraysEqual( expected.split("\n"),
417 | // four.toString().split("\n"), "four");
418 | }
419 |
420 |
421 | @Test
422 | void testCustomStyle() {
423 |
424 | class DoubleStyle implements Style {
425 | private String[][] tablePattern = new String[][] {
426 | /* LEFT COLDATA COLLINE RIGHT */
427 | /* UMN */
428 | /* TOP */ {"x", "=", "x", "x" },
429 | /* HDRDATA */ {":", "Hdr", ":", ":" },
430 | /* HDRLINE*/ {"x", "=", "x", "x" },
431 | /* ROWDATA */ {":", "Data", ":", ":" },
432 | /* ROWLINE*/ {":", "-", ".", ":" },
433 | /* BOTTOM */ {"x", "=", "x", "x" } };
434 |
435 | public String getPattern(Row row, Column column) {
436 | if(tablePattern[row.ordinal()] == null) {
437 | return null;
438 | } else {
439 | return tablePattern[row.ordinal()][column.ordinal()];
440 | }
441 | }
442 |
443 | public String[][] getTable() {
444 | return tablePattern;
445 | }
446 | }
447 |
448 | DoubleStyle doubleStyle = new DoubleStyle();
449 | ConsoleTable six = new ConsoleTable((doubleStyle).getTable()).withStyle(doubleStyle);
450 | six.setHeaders(new ColumnFormat("Left",Aligned.CENTRE),new ColumnFormat("Cell",Aligned.CENTRE),new ColumnFormat("Line",Aligned.CENTRE),new ColumnFormat("Right",Aligned.CENTRE));
451 |
452 | String expected =
453 | "x======x======x======x=======x"+"\n"+
454 | ": Left : Cell : Line : Right :"+"\n"+
455 | "x======x======x======x=======x"+"\n"+
456 | ": x : = : x : x :"+"\n"+
457 | ": : : Hdr : : : : :"+"\n"+
458 | ": x : = : x : x :"+"\n"+
459 | ": : : Data : : : : :"+"\n"+
460 | ": : : - : . : : :"+"\n"+
461 | ": x : = : x : x :"+"\n"+
462 | "x======x======x======x=======x"+"\n";
463 | assertLinesMatch( Arrays.asList(expected.split("\n")),
464 | Arrays.asList(six.toString().split("\n")), "test custom style with pattern table");
465 |
466 | ConsoleTable seven = new ConsoleTable().withStyle(doubleStyle).setHeaders("-Date","'Temperature");
467 | seven.addRow(LocalDate.parse("2021-12-25"), "21°C");
468 |
469 | String expectedOutput =
470 | "x============x=============x"+"\n"+
471 | ": Date : Temperature :"+"\n"+
472 | "x============x=============x"+"\n"+
473 | ": 2021-12-25 : 21°C :"+"\n"+
474 | "x============x=============x"+"\n";
475 | assertLinesMatch( Arrays.asList(expectedOutput.split("\n")),
476 | Arrays.asList(seven.toString().split("\n")), "test custom style with real world data");
477 | }
478 |
479 | @Test
480 | void testAlignments() {
481 | ConsoleTable alignmentsTable = new ConsoleTable().withStyle(Styles.BASIC);
482 | alignmentsTable.setHeaders("-Test", new ColumnFormat("Left",Aligned.LEFT), "'Centre", new ColumnFormat("Right",Aligned.RIGHT));
483 | alignmentsTable.addRow("Short", "a", "1", "x");
484 | alignmentsTable.addRow("Medium", "b2", "22", "yy");
485 | alignmentsTable.addRow("Medium", "c23", "223", "yy3");
486 | // alignmentsTable.addRow("Medium", "c234", "2234", "yy34");
487 | alignmentsTable.addRow("Longest", "d23456", "e2345678", "z12345");
488 |
489 | String expected =
490 | "+---------+--------+----------+--------+"+"\n"+
491 | "| Test | Left | Centre | Right |"+"\n"+
492 | "+---------+--------+----------+--------+"+"\n"+
493 | "| Short | a | 1 | x |"+"\n"+
494 | "| Medium | b2 | 22 | yy |"+"\n"+
495 | "| Medium | c23 | 223 | yy3 |"+"\n"+
496 | "| Longest | d23456 | e2345678 | z12345 |"+"\n"+
497 | "+---------+--------+----------+--------+"+"\n";
498 | assertLinesMatch( Arrays.asList(expected.split("\n")),
499 | Arrays.asList(alignmentsTable.toString().split("\n")), "test Alignments");
500 |
501 | }
502 |
503 | @Test
504 | void testAlignmentOnly() {
505 | ConsoleTable alignmentsTable = new ConsoleTable().withStyle(Styles.BASIC);
506 | alignmentsTable.setHeaders("'", "-Left", "'Centre", "Right");
507 | alignmentsTable.addRow("Low", "a", "1", "x");
508 | alignmentsTable.addRow("Large", "b2", "22", "yy");
509 | alignmentsTable.addRow("Extreme", "d23456", "e2345678", "z12345");
510 |
511 | String expected =
512 | "+---------+--------+----------+--------+"+"\n"+
513 | "| | Left | Centre | Right |"+"\n"+
514 | "+---------+--------+----------+--------+"+"\n"+
515 | "| Low | a | 1 | x |"+"\n"+
516 | "| Large | b2 | 22 | yy |"+"\n"+
517 | "| Extreme | d23456 | e2345678 | z12345 |"+"\n"+
518 | "+---------+--------+----------+--------+"+"\n";
519 | assertLinesMatch( Arrays.asList(expected.split("\n")),
520 | Arrays.asList(alignmentsTable.toString().split("\n")), "test Alignments");
521 |
522 | }
523 |
524 |
525 | @Test
526 | void testArrayHeaderData() {
527 | String[] petHeaders = { "-Pet", "Age", "'Sex" };
528 | Object[][] petData = {
529 | { "Cat", 10, "F" },
530 | { "Dog", 5, "M"}
531 | };
532 | ConsoleTable petShopTable = new ConsoleTable(petHeaders, petData).withStyle(Styles.BASIC);
533 |
534 | String expected =
535 | "+-----+-----+-----+"+"\n"+
536 | "| Pet | Age | Sex |"+"\n"+
537 | "+-----+-----+-----+"+"\n"+
538 | "| Cat | 10 | F |"+"\n"+
539 | "| Dog | 5 | M |"+"\n"+
540 | "+-----+-----+-----+"+"\n";
541 | assertLinesMatch( Arrays.asList(expected.split("\n")),
542 | Arrays.asList(petShopTable.toString().split("\n")), "test new(Array, Array)");
543 |
544 | }
545 |
546 | @Test
547 | void testPaddingInStyles() {
548 | ConsoleTable zooTable = new ConsoleTable(
549 | new String[] { "-Animal", "Cost", "'Sex" },
550 | new Object[][] {
551 | { "Cat", new BigDecimal("10.00"), "F" },
552 | { "Zebra", new BigDecimal("5678.99"), "M"}
553 | }).withStyle(Styles.SQL);
554 |
555 | String expected =
556 | "Animal Cost Sex"+"\n"+
557 | "------ ------- ---"+"\n"+
558 | "Cat 10.00 F "+"\n"+
559 | "Zebra 5678.99 M "+"\n";
560 |
561 | assertLinesMatch( Arrays.asList(expected.split("\n")),
562 | Arrays.asList(zooTable.toString().split("\n")), "test new(Array, Array)");
563 |
564 | }
565 |
566 | @Test
567 | void testSimplestStyle() {
568 |
569 | class Simple implements Style {
570 |
571 | public String getPattern(Row row, Column column) {
572 | if(row == Row.HDRDATA || row == Row.ROWDATA ) {
573 | if( column == Column.COLLINE )
574 | return " ";
575 | else
576 | return "";
577 | }
578 | else
579 | return null;
580 | }
581 |
582 | public String getPadding(Column column) {
583 | return "";
584 | }
585 | }
586 |
587 | ConsoleTable simple = new ConsoleTable().withStyle(new Simple());
588 | simple.setHeaders("Pet","Cost");
589 | simple.addRow("Rusty", 100);
590 | simple.addRow("Red", 42);
591 |
592 | String expected =
593 | " Pet Cost"+"\n"+
594 | "Rusty 100"+"\n"+
595 | " Red 42"+"\n";
596 |
597 | assertLinesMatch( Arrays.asList(expected.split("\n")),
598 | Arrays.asList(simple.toString().split("\n")), "test super simple Style");
599 |
600 |
601 |
602 | }
603 |
604 | @Test
605 | void testSimplerStyle() {
606 |
607 | class Simple implements Style {
608 | public String getPattern(Row row, Column column) {
609 | return ".";
610 | }
611 | }
612 |
613 | ConsoleTable simple = new ConsoleTable().withStyle(new Simple());
614 | simple.setHeaders("Pet","Cost");
615 | simple.addRow("Rusty", 100);
616 | simple.addRow("Red", 42);
617 |
618 | System.out.print(simple);
619 | // TODO assert
620 |
621 |
622 | }
623 |
624 | @Test
625 | void testListHeaderData() {
626 | List petHeaders = Arrays.asList( "-Pet", "Age", "'Sex" );
627 | List> petData = Arrays.asList(
628 | Arrays.asList( "Cat", 10, "F" ),
629 | Arrays.asList( "Dog", 5, "M" )
630 | );
631 | ConsoleTable petShopTable = new ConsoleTable(petHeaders, petData).withStyle(Styles.BASIC);
632 |
633 | String expected =
634 | "+-----+-----+-----+"+"\n"+
635 | "| Pet | Age | Sex |"+"\n"+
636 | "+-----+-----+-----+"+"\n"+
637 | "| Cat | 10 | F |"+"\n"+
638 | "| Dog | 5 | M |"+"\n"+
639 | "+-----+-----+-----+"+"\n";
640 | assertLinesMatch( Arrays.asList(expected.split("\n")),
641 | Arrays.asList(petShopTable.toString().split("\n")), "test new(Array, Array)");
642 |
643 | ConsoleTable table = new ConsoleTable();
644 | table.setHeaders("Header", "Header");
645 | table.addRow("Cell","b2");
646 | table.addRow("a3", "b3");
647 | System.out.print(table);
648 | }
649 |
650 | }
651 |
652 |
653 |
--------------------------------------------------------------------------------