diff --git a/dependencies.md b/dependencies.md index ae77bbc..0f416b1 100644 --- a/dependencies.md +++ b/dependencies.md @@ -21,31 +21,26 @@ ## Plugin Dependencies -| Dependency | License | -| ------------------------------------------------------- | --------------------------------------------- | -| [SonarQube Scanner for Maven][12] | [GNU LGPL 3][13] | -| [Apache Maven Compiler Plugin][14] | [Apache-2.0][15] | -| [Apache Maven Enforcer Plugin][16] | [Apache-2.0][15] | -| [Maven Flatten Plugin][17] | [Apache Software Licenese][15] | -| [org.sonatype.ossindex.maven:ossindex-maven-plugin][18] | [ASL2][7] | -| [Maven Surefire Plugin][19] | [Apache-2.0][15] | -| [Versions Maven Plugin][20] | [Apache License, Version 2.0][15] | -| [duplicate-finder-maven-plugin Maven Mojo][21] | [Apache License 2.0][22] | -| [Apache Maven Deploy Plugin][23] | [Apache-2.0][15] | -| [Apache Maven GPG Plugin][24] | [Apache-2.0][15] | -| [Apache Maven Source Plugin][25] | [Apache License, Version 2.0][15] | -| [Apache Maven Javadoc Plugin][26] | [Apache-2.0][15] | -| [Nexus Staging Maven Plugin][27] | [Eclipse Public License][28] | -| [Maven Failsafe Plugin][29] | [Apache-2.0][15] | -| [JaCoCo :: Maven Plugin][30] | [Eclipse Public License 2.0][31] | -| [error-code-crawler-maven-plugin][32] | [MIT License][33] | -| [Reproducible Build Maven Plugin][34] | [Apache 2.0][7] | -| [Project keeper maven plugin][35] | [The MIT License][36] | -| [Maven Clean Plugin][37] | [The Apache Software License, Version 2.0][7] | -| [Maven Resources Plugin][38] | [The Apache Software License, Version 2.0][7] | -| [Maven JAR Plugin][39] | [The Apache Software License, Version 2.0][7] | -| [Maven Install Plugin][40] | [The Apache Software License, Version 2.0][7] | -| [Maven Site Plugin 3][41] | [The Apache Software License, Version 2.0][7] | +| Dependency | License | +| ------------------------------------------------------- | --------------------------------- | +| [SonarQube Scanner for Maven][12] | [GNU LGPL 3][13] | +| [Apache Maven Compiler Plugin][14] | [Apache-2.0][15] | +| [Apache Maven Enforcer Plugin][16] | [Apache-2.0][15] | +| [Maven Flatten Plugin][17] | [Apache Software Licenese][15] | +| [org.sonatype.ossindex.maven:ossindex-maven-plugin][18] | [ASL2][7] | +| [Maven Surefire Plugin][19] | [Apache-2.0][15] | +| [Versions Maven Plugin][20] | [Apache License, Version 2.0][15] | +| [duplicate-finder-maven-plugin Maven Mojo][21] | [Apache License 2.0][22] | +| [Apache Maven Deploy Plugin][23] | [Apache-2.0][15] | +| [Apache Maven GPG Plugin][24] | [Apache-2.0][15] | +| [Apache Maven Source Plugin][25] | [Apache License, Version 2.0][15] | +| [Apache Maven Javadoc Plugin][26] | [Apache-2.0][15] | +| [Nexus Staging Maven Plugin][27] | [Eclipse Public License][28] | +| [Maven Failsafe Plugin][29] | [Apache-2.0][15] | +| [JaCoCo :: Maven Plugin][30] | [Eclipse Public License 2.0][31] | +| [error-code-crawler-maven-plugin][32] | [MIT License][33] | +| [Reproducible Build Maven Plugin][34] | [Apache 2.0][7] | +| [Project keeper maven plugin][35] | [The MIT License][36] | [0]: http://hamcrest.org/JavaHamcrest/ [1]: http://opensource.org/licenses/BSD-3-Clause @@ -84,8 +79,3 @@ [34]: http://zlika.github.io/reproducible-build-maven-plugin [35]: https://github.com/exasol/project-keeper/ [36]: https://github.com/exasol/project-keeper/blob/main/LICENSE -[37]: http://maven.apache.org/plugins/maven-clean-plugin/ -[38]: http://maven.apache.org/plugins/maven-resources-plugin/ -[39]: http://maven.apache.org/plugins/maven-jar-plugin/ -[40]: http://maven.apache.org/plugins/maven-install-plugin/ -[41]: http://maven.apache.org/plugins/maven-site-plugin/ diff --git a/doc/changes/changelog.md b/doc/changes/changelog.md index 1bbdc76..76780ba 100644 --- a/doc/changes/changelog.md +++ b/doc/changes/changelog.md @@ -1,5 +1,6 @@ # Changes +* [1.6.2](changes_1.6.2.md) * [1.6.1](changes_1.6.1.md) * [1.6.0](changes_1.6.0.md) * [1.5.3](changes_1.5.3.md) diff --git a/doc/changes/changes_1.6.2.md b/doc/changes/changes_1.6.2.md new file mode 100644 index 0000000..71f2ce7 --- /dev/null +++ b/doc/changes/changes_1.6.2.md @@ -0,0 +1,28 @@ +# Matcher for SQL Result Sets 1.6.2, released 2023-10-27 + +Code name: Fix expectation with too many columns + +## Summary + +We fixed an issue where expecting more columns than are actually in the result set would throw an `ArrayIndexOutOfBoundsException`. + +## Features + +* #44: Fixed `ArrayIndexOutOfBoundsException` when expecting more columns than are in the result set. + +## Dependency Updates + +### Test Dependency Updates + +* Updated `org.testcontainers:jdbc:1.19.0` to `1.19.1` +* Updated `org.testcontainers:junit-jupiter:1.19.0` to `1.19.1` + +### Plugin Dependency Updates + +* Updated `com.exasol:error-code-crawler-maven-plugin:1.3.0` to `1.3.1` +* Updated `com.exasol:project-keeper-maven-plugin:2.9.12` to `2.9.14` +* Updated `org.apache.maven.plugins:maven-enforcer-plugin:3.4.0` to `3.4.1` +* Updated `org.apache.maven.plugins:maven-javadoc-plugin:3.5.0` to `3.6.0` +* Updated `org.codehaus.mojo:versions-maven-plugin:2.16.0` to `2.16.1` +* Updated `org.jacoco:jacoco-maven-plugin:0.8.10` to `0.8.11` +* Updated `org.sonarsource.scanner.maven:sonar-maven-plugin:3.9.1.2184` to `3.10.0.2594` diff --git a/pk_generated_parent.pom b/pk_generated_parent.pom index 4d96bd1..1c8143b 100644 --- a/pk_generated_parent.pom +++ b/pk_generated_parent.pom @@ -3,7 +3,7 @@ 4.0.0 com.exasol hamcrest-resultset-matcher-generated-parent - 1.6.1 + 1.6.2 pom UTF-8 @@ -48,7 +48,7 @@ org.sonarsource.scanner.maven sonar-maven-plugin - 3.9.1.2184 + 3.10.0.2594 org.apache.maven.plugins @@ -62,7 +62,7 @@ org.apache.maven.plugins maven-enforcer-plugin - 3.4.0 + 3.4.1 enforce-maven @@ -72,7 +72,7 @@ - [3.8.7,3.9.0) + 3.6.3 @@ -132,7 +132,7 @@ org.codehaus.mojo versions-maven-plugin - 2.16.0 + 2.16.1 display-updates @@ -219,7 +219,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.5.0 + 3.6.0 attach-javadocs @@ -234,6 +234,7 @@ true true true + true @@ -281,7 +282,7 @@ org.jacoco jacoco-maven-plugin - 0.8.10 + 0.8.11 prepare-agent @@ -322,7 +323,7 @@ com.exasol error-code-crawler-maven-plugin - 1.3.0 + 1.3.1 verify diff --git a/pom.xml b/pom.xml index 5c3a189..02889bb 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 hamcrest-resultset-matcher - 1.6.1 + 1.6.2 Matcher for SQL Result Sets This project provides hamcrest matcher that compares java.sql.ResultSet objects. https://github.com/exasol/hamcrest-resultset-matcher/ @@ -30,7 +30,8 @@ org.apache.derby derby - 10.15.2.0 + 10.15.2.0 + test @@ -42,7 +43,7 @@ org.testcontainers junit-jupiter - 1.19.0 + 1.19.1 test @@ -53,7 +54,7 @@ org.testcontainers jdbc - 1.19.0 + 1.19.1 test @@ -62,7 +63,7 @@ com.exasol project-keeper-maven-plugin - 2.9.12 + 2.9.14 @@ -76,7 +77,7 @@ hamcrest-resultset-matcher-generated-parent com.exasol - 1.6.1 + 1.6.2 pk_generated_parent.pom diff --git a/src/main/java/com/exasol/matcher/ResultSetStructureMatcher.java b/src/main/java/com/exasol/matcher/ResultSetStructureMatcher.java index 125640e..0da9ee1 100644 --- a/src/main/java/com/exasol/matcher/ResultSetStructureMatcher.java +++ b/src/main/java/com/exasol/matcher/ResultSetStructureMatcher.java @@ -137,10 +137,12 @@ private boolean matchRowsInOrder(final ResultSet resultSet) { boolean ok = true; try { int rowIndex = 0; + int matcherRowIndex = 0; for (final List> cellMatcherRow : this.cellMatcherTable) { + ++matcherRowIndex; if (resultSet.next()) { ++rowIndex; - ok = ok && matchValuesInRow(resultSet, rowIndex, cellMatcherRow, true); + ok = ok && matchValuesInRow(resultSet, rowIndex, matcherRowIndex, cellMatcherRow, true); } else { ok = false; } @@ -162,12 +164,14 @@ private boolean matchRowsInAnyOrder(final ResultSet resultSet) { final int numberOfRowMatchers = this.cellMatcherTable.size(); int[] matchesForRowMatcher = new int[numberOfRowMatchers]; int rowIndex = 0; + int matcherRowIndex = 0; while (resultSet.next()) { ++rowIndex; boolean anyMatchForThisResultRow = false; int matcherIndex = 0; for (final List> cellMatcherRow : this.cellMatcherTable) { - if (matchValuesInRow(resultSet, rowIndex, cellMatcherRow, false)) { + ++matcherRowIndex; + if (matchValuesInRow(resultSet, rowIndex, matcherRowIndex, cellMatcherRow, false)) { ++matchesForRowMatcher[matcherIndex]; anyMatchForThisResultRow = true; } @@ -241,14 +245,15 @@ private int getExpectedColumnCount() { * recording it at this early stage is not useful. *

* - * @param resultSet result set from which to read the cell values - * @param rowIndex index of the row in the result set - * @param cellMatcherRow list of matchers that are tested against the row's cells + * @param resultSet result set from which to read the cell values + * @param rowIndex index of the row in the result set + * @param matcherRowIndex index of the matcher definition + * @param cellMatcherRow list of matchers that are tested against the row's cells * @param recordFirstDeviation record the first mismatch when set to {@code true} * @return {@code true} if the given matchers match all cells in this row */ - private boolean matchValuesInRow(final ResultSet resultSet, final int rowIndex, - final List> cellMatcherRow, final boolean recordFirstDeviation) { + private boolean matchValuesInRow(final ResultSet resultSet, final int rowIndex, int matcherRowIndex, + final List> cellMatcherRow, final boolean recordFirstDeviation) { int columnIndex = 0; try { for (final Matcher cellMatcher : cellMatcherRow) { @@ -262,8 +267,10 @@ private boolean matchValuesInRow(final ResultSet resultSet, final int rowIndex, } } } catch (final SQLException exception) { - throw new AssertionError("Unable to read actual result set value in row " + rowIndex + ", column " - + columnIndex + ": " + exception.getMessage(), exception); + throw new AssertionError("Row expectation definition " + matcherRowIndex + + " tries to validate the value of row " + rowIndex + ", column " + + columnIndex + " but that value can't be read from the result set. " + + "This usually means the column does not exist. \nCaused by SQL error: " + exception.getMessage()); } return true; } @@ -348,6 +355,13 @@ public static final class Builder { private Calendar calendar; private boolean requireSameOrder = true; + /** + * Create a new instance of a {@link ResultSetStructureMatcher.Builder}. + */ + public Builder() { + // intentionally empty + } + /** * Add a column to the structure to be matched. * diff --git a/src/test/java/com/exasol/matcher/RowMatcherIT.java b/src/test/java/com/exasol/matcher/RowMatcherIT.java new file mode 100644 index 0000000..eb4361a --- /dev/null +++ b/src/test/java/com/exasol/matcher/RowMatcherIT.java @@ -0,0 +1,71 @@ +package com.exasol.matcher; + +import org.hamcrest.Matcher; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.jupiter.api.Assertions.*; + +/** + * This integration test runs row matching tests against the Apache Derby database. + */ +class RowMatcherIT extends AbstractResultSetMatcherTest { + @BeforeEach + void beforeEach() throws SQLException { + final Connection connection = DriverManager.getConnection("jdbc:derby:memory:test;create=true"); + this.statement = connection.createStatement(); + } + + @AfterEach + void afterEach() { + execute("DROP TABLE T"); + } + + // This is a regression test for https://github.com/exasol/hamcrest-resultset-matcher/issues/44 + @Test + void testMatchingInAnyOrderAndExpectingThreeColumnsThrowsAssertionErrorWhenResultSetHasOnlyTwoColumns() + throws SQLException { + execute("CREATE TABLE T(I INTEGER, V VARCHAR(20))"); + execute("INSERT INTO T VALUES (1, 'a'), (2, 'b')"); + final Matcher anyOrderMatcher = ResultSetStructureMatcher // + .table()// + .row(1, "a", 1) // + .row(greaterThan(0), "b", 3) // + .matchesInAnyOrder(); + try(final ResultSet result = query("SELECT * FROM T")) { + final AssertionError error = assertThrows(AssertionError.class, + () -> anyOrderMatcher.matches(result)); + assertThat(error.getMessage(), startsWith("Row expectation definition 1 tries to validate the value of row 1, " + + "column 3 but that value can't be read from the result set. " + + "This usually means the column does not exist. \nCaused by SQL error:")); + } + } + + // This is a regression test for https://github.com/exasol/hamcrest-resultset-matcher/issues/44 + @Test + void testMatchingInStrictOrderAndExpectingThreeColumnsThrowsAssertionErrorWhenResultSetHasOnlyTwoColumns() + throws SQLException { + execute("CREATE TABLE T(I INTEGER, V VARCHAR(20))"); + execute("INSERT INTO T VALUES (1, 'A'), (2, 'B')"); + final Matcher orderedMatcher = ResultSetStructureMatcher // + .table()// + .row(1, "A", 1) // + .row(greaterThan(0), "B", 3) // + .matches(); + try (final ResultSet result = query("SELECT * FROM T")) { + final AssertionError error = assertThrows(AssertionError.class, () -> orderedMatcher.matches(result)); + assertThat(error.getMessage(), startsWith("Row expectation definition 1 tries to validate the value of row 1, " + + "column 3 but that value can't be read from the result set. " + + "This usually means the column does not exist. \nCaused by SQL error:")); + + } + } +} \ No newline at end of file