Skip to content

Commit

Permalink
Transpose table logic if column number is bigger than row number
Browse files Browse the repository at this point in the history
  • Loading branch information
HardNorth committed Jan 29, 2024
1 parent 725ecaf commit 3f1afb8
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 20 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## [Unreleased]
### Added
- Table size limit in `MarkdownUtils.formatDataTable(List, int)` method, by @HardNorth
- Transpose table logic if column number is bigger than row number in `MarkdownUtils.formatDataTable(List, int)` method, by @HardNorth
- `MarkdownUtils.formatDataTable(Map<String, String>)` method, by @HardNorth

## [5.2.1]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public class MarkdownUtils {
public static final String TRUNCATION_REPLACEMENT = "...";
public static final int PADDING_SPACES_NUM = 2;
public static final int MAX_TABLE_SIZE = 83;
public static final int MIN_COL_SIZE = 3;

/**
* Adds special prefix to make log message being processed as markdown
Expand All @@ -62,11 +63,36 @@ public static String asCode(String language, String script) {
return asMarkdown("```" + ofNullable(language).orElse("") + NEW_LINE + script + NEW_LINE + "```");
}

@Nonnull
private static List<Integer> calculateColSizes(@Nonnull List<Integer> colSizes, int maxTableSize) {
private static List<Integer> calculateColSizes(@Nonnull List<List<String>> table) {
int tableColNum = table.stream().mapToInt(List::size).max().orElse(-1);
List<Iterator<String>> iterList = table.stream().map(List::iterator).collect(Collectors.toList());
return IntStream.range(0, tableColNum)
.mapToObj(n -> iterList.stream().filter(Iterator::hasNext).map(Iterator::next).collect(Collectors.toList()))
.map(col -> col.stream().mapToInt(String::length).max().orElse(0))
.collect(Collectors.toList());
}

private static int calculateTableSize(@Nonnull List<Integer> colSizes) {
int colTableSize = colSizes.stream().reduce(Integer::sum).orElse(-1);
colTableSize += (PADDING_SPACES_NUM + TABLE_COLUMN_SEPARATOR.length()) * colSizes.size() - 1; // Inner columns grid
colTableSize += 2; // Outer table grid
return colTableSize;
}

private static <T> List<List<T>> transposeTable(@Nonnull List<List<T>> table) {
int tableColNum = table.stream().mapToInt(List::size).max().orElse(-1);
List<Iterator<T>> iterList = table.stream().map(List::iterator).collect(Collectors.toList());
return IntStream.range(0, tableColNum)
.mapToObj(n -> iterList.stream()
.filter(Iterator::hasNext)
.map(Iterator::next)
.collect(Collectors.toList()))
.collect(Collectors.toList());
}

@Nonnull
private static List<Integer> adjustColSizes(@Nonnull List<Integer> colSizes, int maxTableSize) {
int colTableSize = calculateTableSize(colSizes);
if (maxTableSize >= colTableSize) {
return colSizes;
}
Expand All @@ -79,16 +105,17 @@ private static List<Integer> calculateColSizes(@Nonnull List<Integer> colSizes,
for (int i = 0; i < sizeToShrink; i++) {
for (int j = 0; j < colsBySize.size(); j++) {
Pair<Integer, Integer> currentCol = colsBySize.get(j);
if (currentCol.getKey() <= MIN_COL_SIZE) {
continue;
}
Pair<Integer, Integer> nextCol = colsBySize.size() > j + 1 ? colsBySize.get(j + 1) : Pair.of(0, 0);
if (currentCol.getKey() >= nextCol.getKey()) {
colsBySize.set(j, Pair.of(currentCol.getKey() - 1, currentCol.getValue()));
break;
}
}
}
List<Integer> result = new ArrayList<>(colSizes);
colsBySize.forEach(col -> result.set(col.getValue(), col.getKey()));
return result;
return colsBySize.stream().sorted(Map.Entry.comparingByValue()).map(Pair::getKey).collect(Collectors.toList());
}

/**
Expand All @@ -100,25 +127,30 @@ private static List<Integer> calculateColSizes(@Nonnull List<Integer> colSizes,
*/
@Nonnull
public static String formatDataTable(@Nonnull final List<List<String>> table, int maxTableSize) {
List<Integer> colSizes = calculateColSizes(table);
boolean transpose = colSizes.size() > table.size() && calculateTableSize(colSizes) > maxTableSize;
List<List<String>> printTable = transpose ? transposeTable(table) : table;
if(transpose) {
colSizes = calculateColSizes(printTable);
}
colSizes = adjustColSizes(colSizes, maxTableSize);
int tableSize = calculateTableSize(colSizes);
boolean addPadding = tableSize <= maxTableSize;
boolean header = !transpose;
StringBuilder result = new StringBuilder();
int tableColNum = table.stream().mapToInt(List::size).max().orElse(-1);
List<Iterator<String>> iterList = table.stream().map(List::iterator).collect(Collectors.toList());
List<Integer> colSizes = IntStream.range(0, tableColNum)
.mapToObj(n -> iterList.stream().filter(Iterator::hasNext).map(Iterator::next).collect(Collectors.toList()))
.map(col -> col.stream().mapToInt(String::length).max().orElse(0))
.collect(Collectors.toList());
colSizes = calculateColSizes(colSizes, maxTableSize);

boolean header = true;
for (List<String> row : table) {
for (List<String> row : printTable) {
result.append(TABLE_INDENT).append(TABLE_COLUMN_SEPARATOR);
for (int i = 0; i < row.size(); i++) {
String cell = row.get(i);
int colSize = colSizes.get(i);
if (colSize < cell.length()) {
cell = cell.substring(0, colSize - TRUNCATION_REPLACEMENT.length()) + TRUNCATION_REPLACEMENT;
if (TRUNCATION_REPLACEMENT.length() < colSize) {
cell = cell.substring(0, colSize - TRUNCATION_REPLACEMENT.length()) + TRUNCATION_REPLACEMENT;
} else {
cell = cell.substring(0, colSize);
}
}
int padSize = colSize - cell.length() + PADDING_SPACES_NUM;
int padSize = colSize - cell.length() + (addPadding ? PADDING_SPACES_NUM : 0);
int lSpace = padSize / 2;
int rSpace = padSize - lSpace;
IntStream.range(0, lSpace).forEach(j -> result.append(ONE_SPACE));
Expand All @@ -131,7 +163,7 @@ public static String formatDataTable(@Nonnull final List<List<String>> table, in
result.append(NEW_LINE);
result.append(TABLE_INDENT).append(TABLE_COLUMN_SEPARATOR);
for (int i = 0; i < row.size(); i++) {
int maxSize = colSizes.get(i) + 2;
int maxSize = colSizes.get(i) + (addPadding ? PADDING_SPACES_NUM : 0);
IntStream.range(0, maxSize).forEach(j -> result.append(TABLE_ROW_SEPARATOR));
result.append(TABLE_COLUMN_SEPARATOR);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@

import org.junit.jupiter.api.Test;

import java.util.*;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import static com.epam.reportportal.utils.markdown.MarkdownUtils.*;
import static org.hamcrest.MatcherAssert.assertThat;
Expand Down Expand Up @@ -105,11 +108,37 @@ public void test_format_data_table_two_big_col() {

@Test
public void test_format_data_table_map() {
Map<String, String> table = new LinkedHashMap<String, String>(){{
Map<String, String> table = new LinkedHashMap<String, String>() {{
put("var_a", "2");
put("var_b", "2");
put("result", "4");
}};
assertThat(formatDataTable(table), equalTo(ONE_ROW_EXPECTED_TABLE));
}

//@formatter:off
public static final String MIN_ROW_WIDTH_EXPECTED_TABLE_TRANSPOSE =
TABLE_INDENT + "|var|2|\n"
+ TABLE_INDENT + "|var|2|\n"
+ TABLE_INDENT + "|res|4|";
//@formatter:on

@Test
public void test_format_data_table_min_size_transpose() {
List<List<String>> table = Arrays.asList(Arrays.asList("var_a", "var_b", "result"), Arrays.asList("2", "2", "4"));
assertThat(formatDataTable(table, 0), equalTo(MIN_ROW_WIDTH_EXPECTED_TABLE_TRANSPOSE));
}

//@formatter:off
public static final String MIN_ROW_WIDTH_EXPECTED_TABLE_NO_TRANSPOSE =
TABLE_INDENT + "|var|res|\n"
+ TABLE_INDENT + "|---|---|\n"
+ TABLE_INDENT + "|\u00A02\u00A0|\u00A04\u00A0|";
//@formatter:on

@Test
public void test_format_data_table_min_size_no_transpose() {
List<List<String>> table = Arrays.asList(Arrays.asList("var_a", "result"), Arrays.asList("2", "4"));
assertThat(formatDataTable(table, 0), equalTo(MIN_ROW_WIDTH_EXPECTED_TABLE_NO_TRANSPOSE));
}
}

0 comments on commit 3f1afb8

Please sign in to comment.