Skip to content

Commit 655090b

Browse files
authored
Update esql error message (#118277)
This change update esql comparison error message to also include expected and actual values in order to make it easier to spot the incorrect actual data.
1 parent 5997fc3 commit 655090b

File tree

1 file changed

+57
-19
lines changed
  • x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql

1 file changed

+57
-19
lines changed

x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvAssert.java

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@
3939
import static org.elasticsearch.xpack.esql.core.util.NumericUtils.unsignedLongAsNumber;
4040
import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.CARTESIAN;
4141
import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.GEO;
42+
import static org.hamcrest.MatcherAssert.assertThat;
4243
import static org.hamcrest.Matchers.instanceOf;
4344
import static org.junit.Assert.assertEquals;
44-
import static org.junit.Assert.assertThat;
4545
import static org.junit.Assert.fail;
4646

4747
public final class CsvAssert {
@@ -197,11 +197,7 @@ public static void assertData(
197197
for (int row = 0; row < expectedValues.size(); row++) {
198198
try {
199199
if (row >= actualValues.size()) {
200-
if (dataFailures.isEmpty()) {
201-
fail("Expected more data but no more entries found after [" + row + "]");
202-
} else {
203-
dataFailure(dataFailures, "Expected more data but no more entries found after [" + row + "]\n");
204-
}
200+
dataFailure("Expected more data but no more entries found after [" + row + "]", dataFailures, expected, actualValues);
205201
}
206202

207203
if (logger != null) {
@@ -250,13 +246,17 @@ public static void assertData(
250246
dataFailures.add(new DataFailure(row, column, transformedExpected, transformedActual));
251247
}
252248
if (dataFailures.size() > 10) {
253-
dataFailure(dataFailures);
249+
dataFailure("", dataFailures, expected, actualValues);
254250
}
255251
}
256252

257-
var delta = actualRow.size() - expectedRow.size();
258-
if (delta > 0) {
259-
fail("Plan has extra columns, returned [" + actualRow.size() + "], expected [" + expectedRow.size() + "]");
253+
if (actualRow.size() != expectedRow.size()) {
254+
dataFailure(
255+
"Plan has extra columns, returned [" + actualRow.size() + "], expected [" + expectedRow.size() + "]",
256+
dataFailures,
257+
expected,
258+
actualValues
259+
);
260260
}
261261
} catch (AssertionError ae) {
262262
if (logger != null && row + 1 < actualValues.size()) {
@@ -267,21 +267,59 @@ public static void assertData(
267267
}
268268
}
269269
if (dataFailures.isEmpty() == false) {
270-
dataFailure(dataFailures);
270+
dataFailure("", dataFailures, expected, actualValues);
271271
}
272272
if (expectedValues.size() < actualValues.size()) {
273-
fail(
274-
"Elasticsearch still has data after [" + expectedValues.size() + "] entries:\n" + row(actualValues, expectedValues.size())
275-
);
273+
dataFailure("Elasticsearch still has data after [" + expectedValues.size() + "] entries", dataFailures, expected, actualValues);
276274
}
277275
}
278276

279-
private static void dataFailure(List<DataFailure> dataFailures) {
280-
dataFailure(dataFailures, "");
277+
private static void dataFailure(
278+
String description,
279+
List<DataFailure> dataFailures,
280+
ExpectedResults expectedValues,
281+
List<List<Object>> actualValues
282+
) {
283+
var expected = pipeTable("Expected:", expectedValues.columnNames(), expectedValues.values(), 25);
284+
var actual = pipeTable("Actual:", expectedValues.columnNames(), actualValues, 25);
285+
fail(description + System.lineSeparator() + describeFailures(dataFailures) + actual + expected);
286+
}
287+
288+
private static String pipeTable(String description, List<String> headers, List<List<Object>> values, int maxRows) {
289+
int[] width = new int[headers.size()];
290+
for (int i = 0; i < width.length; i++) {
291+
width[i] = headers.get(i).length();
292+
for (List<Object> row : values) {
293+
width[i] = Math.max(width[i], String.valueOf(row.get(i)).length());
294+
}
295+
}
296+
297+
var result = new StringBuilder().append(System.lineSeparator()).append(description).append(System.lineSeparator());
298+
for (int c = 0; c < width.length; c++) {
299+
appendValue(result, headers.get(c), width[c]);
300+
}
301+
result.append('|').append(System.lineSeparator());
302+
for (int r = 0; r < Math.min(maxRows, values.size()); r++) {
303+
for (int c = 0; c < width.length; c++) {
304+
appendValue(result, values.get(r).get(c), width[c]);
305+
}
306+
result.append('|').append(System.lineSeparator());
307+
}
308+
if (values.size() > maxRows) {
309+
result.append("...").append(System.lineSeparator());
310+
}
311+
return result.toString();
312+
}
313+
314+
private static void appendValue(StringBuilder result, Object value, int width) {
315+
result.append('|').append(value);
316+
for (int i = 0; i < width - String.valueOf(value).length(); i++) {
317+
result.append(' ');
318+
}
281319
}
282320

283-
private static void dataFailure(List<DataFailure> dataFailures, String prefixError) {
284-
fail(prefixError + "Data mismatch:\n" + dataFailures.stream().map(f -> {
321+
private static String describeFailures(List<DataFailure> dataFailures) {
322+
return "Data mismatch:" + System.lineSeparator() + dataFailures.stream().map(f -> {
285323
Description description = new StringDescription();
286324
ListMatcher expected;
287325
if (f.expected instanceof List<?> e) {
@@ -299,7 +337,7 @@ private static void dataFailure(List<DataFailure> dataFailures, String prefixErr
299337
expected.describeMismatch(actualList, description);
300338
String prefix = "row " + f.row + " column " + f.column + ":";
301339
return prefix + description.toString().replace("\n", "\n" + prefix);
302-
}).collect(Collectors.joining("\n")));
340+
}).collect(Collectors.joining(System.lineSeparator()));
303341
}
304342

305343
private static Comparator<List<Object>> resultRowComparator(List<Type> types) {

0 commit comments

Comments
 (0)