diff --git a/src/test/java/org/springframework/data/r2dbc/core/PostgresReactiveDataAccessStrategyTests.java b/src/test/java/org/springframework/data/r2dbc/core/PostgresReactiveDataAccessStrategyTests.java index 238a818ef..b23015838 100644 --- a/src/test/java/org/springframework/data/r2dbc/core/PostgresReactiveDataAccessStrategyTests.java +++ b/src/test/java/org/springframework/data/r2dbc/core/PostgresReactiveDataAccessStrategyTests.java @@ -15,7 +15,7 @@ */ package org.springframework.data.r2dbc.core; -import static org.assertj.core.api.Assertions.*; +import static org.springframework.data.r2dbc.testing.Assertions.*; import lombok.RequiredArgsConstructor; @@ -33,7 +33,6 @@ import org.springframework.data.r2dbc.convert.EnumWriteSupport; import org.springframework.data.r2dbc.dialect.PostgresDialect; import org.springframework.data.r2dbc.mapping.OutboundRow; import org.springframework.data.relational.core.sql.SqlIdentifier; -import org.springframework.r2dbc.core.Parameter; /** * {@link PostgresDialect} specific tests for {@link ReactiveDataAccessStrategy}. @@ -54,8 +53,7 @@ public class PostgresReactiveDataAccessStrategyTests extends ReactiveDataAccessS OutboundRow row = strategy.getOutboundRow(new WithMultidimensionalArray(new int[][] { { 1, 2, 3 }, { 4, 5 } })); - assertThat(row.get(SqlIdentifier.unquoted("myarray")).hasValue()).isTrue(); - assertThat(row.get(SqlIdentifier.unquoted("myarray")).getValue()).isInstanceOf(Integer[][].class); + assertThat(row).withColumn("myarray").hasValueInstanceOf(Integer[][].class); } @Test // gh-161 @@ -63,8 +61,7 @@ public class PostgresReactiveDataAccessStrategyTests extends ReactiveDataAccessS OutboundRow row = strategy.getOutboundRow(new WithMultidimensionalArray(null)); - assertThat(row.get(SqlIdentifier.unquoted("myarray")).hasValue()).isFalse(); - assertThat(row.get(SqlIdentifier.unquoted("myarray")).getType()).isEqualTo(Integer[].class); + assertThat(row).withColumn("myarray").isEmpty().hasType(Integer[].class); } @Test // gh-161 @@ -72,8 +69,7 @@ public class PostgresReactiveDataAccessStrategyTests extends ReactiveDataAccessS OutboundRow row = strategy.getOutboundRow(new WithIntegerCollection(Arrays.asList(1, 2, 3))); - assertThat(row.get(SqlIdentifier.unquoted("myarray")).hasValue()).isTrue(); - assertThat(row.get(SqlIdentifier.unquoted("myarray")).getValue()).isInstanceOf(Integer[].class); + assertThat(row).withColumn("myarray").hasValueInstanceOf(Integer[].class); assertThat((Integer[]) row.get(SqlIdentifier.unquoted("myarray")).getValue()).contains(1, 2, 3); } @@ -88,9 +84,8 @@ public class PostgresReactiveDataAccessStrategyTests extends ReactiveDataAccessS OutboundRow outboundRow = strategy.getOutboundRow(withArray); - assertThat(outboundRow) // - .containsEntry(SqlIdentifier.unquoted("string_array"), Parameter.from(new String[] { "hello", "world" })) - .containsEntry(SqlIdentifier.unquoted("string_list"), Parameter.from(new String[] { "hello", "world" })); + assertThat(outboundRow).containsColumnWithValue("string_array", new String[] { "hello", "world" }) + .containsColumnWithValue("string_list", new String[] { "hello", "world" }); } @Test // gh-139 @@ -104,8 +99,7 @@ public class PostgresReactiveDataAccessStrategyTests extends ReactiveDataAccessS OutboundRow outboundRow = strategy.getOutboundRow(withConversion); - assertThat(outboundRow) // - .containsEntry(SqlIdentifier.unquoted("my_objects"), Parameter.from("[one, two]")); + assertThat(outboundRow).containsColumnWithValue("my_objects", "[one, two]"); } @Test // gh-139 @@ -119,12 +113,7 @@ public class PostgresReactiveDataAccessStrategyTests extends ReactiveDataAccessS OutboundRow outboundRow = strategy.getOutboundRow(withConversion); - assertThat(outboundRow) // - .containsKey(SqlIdentifier.unquoted("my_objects")); - - Parameter value = outboundRow.get("my_objects"); - assertThat(value.isEmpty()).isTrue(); - assertThat(value.getType()).isEqualTo(String.class); + assertThat(outboundRow).containsColumn("my_objects").withColumn("my_objects").isEmpty().hasType(String.class); } @Test // gh-252, gh-593 @@ -139,16 +128,10 @@ public class PostgresReactiveDataAccessStrategyTests extends ReactiveDataAccessS OutboundRow outboundRow = strategy.getOutboundRow(withEnums); - assertThat(outboundRow).containsKey(SqlIdentifier.unquoted("enum_set")); - assertThat(outboundRow.get(SqlIdentifier.unquoted("enum_set")).getValue()).isEqualTo(new String[] { "ONE", "TWO" }); - - assertThat(outboundRow).containsKey(SqlIdentifier.unquoted("enum_array")); - assertThat(outboundRow.get(SqlIdentifier.unquoted("enum_array")).getValue()) - .isEqualTo(new String[] { "ONE", "TWO" }); - - assertThat(outboundRow).containsKey(SqlIdentifier.unquoted("enum_list")); - assertThat(outboundRow.get(SqlIdentifier.unquoted("enum_list")).getValue()) - .isEqualTo(new String[] { "ONE", "TWO" }); + assertThat(outboundRow).containsColumns("enum_set", "enum_array", "enum_list"); + assertThat(outboundRow).withColumn("enum_set").hasValue(new String[] { "ONE", "TWO" }).hasType(String[].class); + assertThat(outboundRow).withColumn("enum_array").hasValue(new String[] { "ONE", "TWO" }).hasType(String[].class); + assertThat(outboundRow).withColumn("enum_list").hasValue(new String[] { "ONE", "TWO" }).hasType(String[].class); } @Test // gh-593 @@ -160,14 +143,10 @@ public class PostgresReactiveDataAccessStrategyTests extends ReactiveDataAccessS OutboundRow outboundRow = strategy.getOutboundRow(withEnums); - assertThat(outboundRow).containsKey(SqlIdentifier.unquoted("enum_set")); - assertThat(outboundRow.get(SqlIdentifier.unquoted("enum_set")).getType()).isEqualTo(String[].class); - - assertThat(outboundRow).containsKey(SqlIdentifier.unquoted("enum_array")); - assertThat(outboundRow.get(SqlIdentifier.unquoted("enum_array")).getType()).isEqualTo(String[].class); - - assertThat(outboundRow).containsKey(SqlIdentifier.unquoted("enum_list")); - assertThat(outboundRow.get(SqlIdentifier.unquoted("enum_list")).getType()).isEqualTo(String[].class); + assertThat(outboundRow).containsColumns("enum_set", "enum_array", "enum_list"); + assertThat(outboundRow).withColumn("enum_set").isEmpty().hasType(String[].class); + assertThat(outboundRow).withColumn("enum_array").isEmpty().hasType(String[].class); + assertThat(outboundRow).withColumn("enum_list").isEmpty().hasType(String[].class); } @Test // gh-593 @@ -183,14 +162,10 @@ public class PostgresReactiveDataAccessStrategyTests extends ReactiveDataAccessS OutboundRow outboundRow = strategy.getOutboundRow(withEnums); - assertThat(outboundRow).containsKey(SqlIdentifier.unquoted("enum_set")); - assertThat(outboundRow.get(SqlIdentifier.unquoted("enum_set")).getValue()).isInstanceOf(MyEnum[].class); - - assertThat(outboundRow).containsKey(SqlIdentifier.unquoted("enum_array")); - assertThat(outboundRow.get(SqlIdentifier.unquoted("enum_array")).getValue()).isInstanceOf(MyEnum[].class); - - assertThat(outboundRow).containsKey(SqlIdentifier.unquoted("enum_list")); - assertThat(outboundRow.get(SqlIdentifier.unquoted("enum_list")).getValue()).isInstanceOf(MyEnum[].class); + assertThat(outboundRow).containsColumns("enum_set", "enum_array", "enum_list"); + assertThat(outboundRow).withColumn("enum_set").hasValue().hasType(MyEnum[].class); + assertThat(outboundRow).withColumn("enum_array").hasValue().hasType(MyEnum[].class); + assertThat(outboundRow).withColumn("enum_list").hasValue().hasType(MyEnum[].class); } @Test // gh-593 @@ -203,14 +178,10 @@ public class PostgresReactiveDataAccessStrategyTests extends ReactiveDataAccessS OutboundRow outboundRow = strategy.getOutboundRow(withEnums); - assertThat(outboundRow).containsKey(SqlIdentifier.unquoted("enum_set")); - assertThat(outboundRow.get(SqlIdentifier.unquoted("enum_set")).getType()).isEqualTo(MyEnum[].class); - - assertThat(outboundRow).containsKey(SqlIdentifier.unquoted("enum_array")); - assertThat(outboundRow.get(SqlIdentifier.unquoted("enum_array")).getType()).isEqualTo(MyEnum[].class); - - assertThat(outboundRow).containsKey(SqlIdentifier.unquoted("enum_list")); - assertThat(outboundRow.get(SqlIdentifier.unquoted("enum_list")).getType()).isEqualTo(MyEnum[].class); + assertThat(outboundRow).containsColumns("enum_set", "enum_array", "enum_list"); + assertThat(outboundRow).withColumn("enum_set").isEmpty().hasType(MyEnum[].class); + assertThat(outboundRow).withColumn("enum_array").isEmpty().hasType(MyEnum[].class); + assertThat(outboundRow).withColumn("enum_list").isEmpty().hasType(MyEnum[].class); } @RequiredArgsConstructor diff --git a/src/test/java/org/springframework/data/r2dbc/core/ReactiveDataAccessStrategyTestSupport.java b/src/test/java/org/springframework/data/r2dbc/core/ReactiveDataAccessStrategyTestSupport.java index a9c0f7a5d..1475b7790 100644 --- a/src/test/java/org/springframework/data/r2dbc/core/ReactiveDataAccessStrategyTestSupport.java +++ b/src/test/java/org/springframework/data/r2dbc/core/ReactiveDataAccessStrategyTestSupport.java @@ -52,135 +52,135 @@ public abstract class ReactiveDataAccessStrategyTestSupport { protected abstract ReactiveDataAccessStrategy getStrategy(); @Test // gh-85 - public void shouldReadAndWriteString() { + void shouldReadAndWriteString() { testType(PrimitiveTypes::setString, PrimitiveTypes::getString, "foo", "string"); } @Test // gh-85 - public void shouldReadAndWriteCharacter() { + void shouldReadAndWriteCharacter() { testType(PrimitiveTypes::setCharacter, PrimitiveTypes::getCharacter, 'f', "character"); } @Test // gh-85 - public void shouldReadAndWriteBoolean() { + void shouldReadAndWriteBoolean() { testType(PrimitiveTypes::setBooleanValue, PrimitiveTypes::isBooleanValue, true, "boolean_value"); } @Test // gh-85 - public void shouldReadAndWriteBoxedBoolean() { + void shouldReadAndWriteBoxedBoolean() { testType(PrimitiveTypes::setBoxedBooleanValue, PrimitiveTypes::getBoxedBooleanValue, true, "boxed_boolean_value"); } @Test // gh-85 - public void shouldReadAndWriteByte() { + void shouldReadAndWriteByte() { testType(PrimitiveTypes::setByteValue, PrimitiveTypes::getByteValue, (byte) 123, "byte_value"); } @Test // gh-85 - public void shouldReadAndWriteBoxedByte() { + void shouldReadAndWriteBoxedByte() { testType(PrimitiveTypes::setBoxedByteValue, PrimitiveTypes::getBoxedByteValue, (byte) 123, "boxed_byte_value"); } @Test // gh-85 - public void shouldReadAndWriteShort() { + void shouldReadAndWriteShort() { testType(PrimitiveTypes::setShortValue, PrimitiveTypes::getShortValue, (short) 123, "short_value"); } @Test // gh-85 - public void shouldReadAndWriteBoxedShort() { + void shouldReadAndWriteBoxedShort() { testType(PrimitiveTypes::setBoxedShortValue, PrimitiveTypes::getBoxedShortValue, (short) 123, "boxed_short_value"); } @Test // gh-85 - public void shouldReadAndWriteInteger() { + void shouldReadAndWriteInteger() { testType(PrimitiveTypes::setIntValue, PrimitiveTypes::getIntValue, 123, "int_value"); } @Test // gh-85 - public void shouldReadAndWriteBoxedInteger() { + void shouldReadAndWriteBoxedInteger() { testType(PrimitiveTypes::setBoxedIntegerValue, PrimitiveTypes::getBoxedIntegerValue, 123, "boxed_integer_value"); } @Test // gh-85 - public void shouldReadAndWriteLong() { + void shouldReadAndWriteLong() { testType(PrimitiveTypes::setLongValue, PrimitiveTypes::getLongValue, 123L, "long_value"); } @Test // gh-85 - public void shouldReadAndWriteBoxedLong() { + void shouldReadAndWriteBoxedLong() { testType(PrimitiveTypes::setBoxedLongValue, PrimitiveTypes::getBoxedLongValue, 123L, "boxed_long_value"); } @Test // gh-85 - public void shouldReadAndWriteFloat() { + void shouldReadAndWriteFloat() { testType(PrimitiveTypes::setFloatValue, PrimitiveTypes::getFloatValue, 0.1f, "float_value"); } @Test // gh-85 - public void shouldReadAndWriteBoxedFloat() { + void shouldReadAndWriteBoxedFloat() { testType(PrimitiveTypes::setBoxedFloatValue, PrimitiveTypes::getBoxedFloatValue, 0.1f, "boxed_float_value"); } @Test // gh-85 - public void shouldReadAndWriteDouble() { + void shouldReadAndWriteDouble() { testType(PrimitiveTypes::setDoubleValue, PrimitiveTypes::getDoubleValue, 0.1, "double_value"); } @Test // gh-85 - public void shouldReadAndWriteBoxedDouble() { + void shouldReadAndWriteBoxedDouble() { testType(PrimitiveTypes::setBoxedDoubleValue, PrimitiveTypes::getBoxedDoubleValue, 0.1, "boxed_double_value"); } @Test // gh-85 - public void shouldReadAndWriteBigInteger() { + void shouldReadAndWriteBigInteger() { testType(PrimitiveTypes::setBigInteger, PrimitiveTypes::getBigInteger, BigInteger.TEN, "big_integer"); } @Test // gh-85 - public void shouldReadAndWriteBigDecimal() { + void shouldReadAndWriteBigDecimal() { testType(PrimitiveTypes::setBigDecimal, PrimitiveTypes::getBigDecimal, new BigDecimal("100.123"), "big_decimal"); } @Test // gh-85 - public void shouldReadAndWriteLocalDate() { + void shouldReadAndWriteLocalDate() { testType(PrimitiveTypes::setLocalDate, PrimitiveTypes::getLocalDate, LocalDate.now(), "local_date"); } @Test // gh-85 - public void shouldReadAndWriteLocalTime() { + void shouldReadAndWriteLocalTime() { testType(PrimitiveTypes::setLocalTime, PrimitiveTypes::getLocalTime, LocalTime.now(), "local_time"); } @Test // gh-85 - public void shouldReadAndWriteLocalDateTime() { + void shouldReadAndWriteLocalDateTime() { testType(PrimitiveTypes::setLocalDateTime, PrimitiveTypes::getLocalDateTime, LocalDateTime.now(), "local_date_time"); } @Test // gh-85 - public void shouldReadAndWriteZonedDateTime() { + void shouldReadAndWriteZonedDateTime() { testType(PrimitiveTypes::setZonedDateTime, PrimitiveTypes::getZonedDateTime, ZonedDateTime.now(), "zoned_date_time"); } @Test // gh-85 - public void shouldReadAndWriteOffsetDateTime() { + void shouldReadAndWriteOffsetDateTime() { testType(PrimitiveTypes::setOffsetDateTime, PrimitiveTypes::getOffsetDateTime, OffsetDateTime.now(), "offset_date_time"); } @Test // gh-85 - public void shouldReadAndWriteUuid() { + void shouldReadAndWriteUuid() { testType(PrimitiveTypes::setUuid, PrimitiveTypes::getUuid, UUID.randomUUID(), "uuid"); } @Test // gh-186 - public void shouldReadAndWriteBinary() { + void shouldReadAndWriteBinary() { testType(PrimitiveTypes::setBinary, PrimitiveTypes::getBinary, "hello".getBytes(), "binary"); } @Test // gh-354 - public void shouldNotWriteReadOnlyFields() { + void shouldNotWriteReadOnlyFields() { TypeWithReadOnlyFields toSave = new TypeWithReadOnlyFields(); diff --git a/src/test/java/org/springframework/data/r2dbc/testing/Assertions.java b/src/test/java/org/springframework/data/r2dbc/testing/Assertions.java new file mode 100644 index 000000000..526a2188e --- /dev/null +++ b/src/test/java/org/springframework/data/r2dbc/testing/Assertions.java @@ -0,0 +1,37 @@ +/* + * Copyright 2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.r2dbc.testing; + +import org.springframework.data.r2dbc.mapping.OutboundRow; + +/** + * @author Mark Paluch + */ +public abstract class Assertions extends org.assertj.core.api.Assertions { + + private Assertions() {} + + /** + * Create assertion for {@link OutboundRow}. + * + * @param actual the actual value. + * @param the type of the value contained in the {@link OutboundRow}. + * @return the created assertion object. + */ + public static OutboundRowAssert assertThat(OutboundRow actual) { + return OutboundRowAssert.assertThat(actual); + } +} diff --git a/src/test/java/org/springframework/data/r2dbc/testing/OutboundRowAssert.java b/src/test/java/org/springframework/data/r2dbc/testing/OutboundRowAssert.java new file mode 100644 index 000000000..7f2d7f07d --- /dev/null +++ b/src/test/java/org/springframework/data/r2dbc/testing/OutboundRowAssert.java @@ -0,0 +1,337 @@ +/* + * Copyright 2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.r2dbc.testing; + +import java.util.Arrays; +import java.util.stream.Collectors; + +import org.assertj.core.api.AbstractAssert; +import org.assertj.core.api.AbstractMapAssert; +import org.assertj.core.api.Assertions; +import org.assertj.core.error.BasicErrorMessageFactory; +import org.assertj.core.error.ShouldBeEmpty; +import org.assertj.core.error.ShouldContain; +import org.assertj.core.error.ShouldNotBeEmpty; + +import org.springframework.data.r2dbc.mapping.OutboundRow; +import org.springframework.data.relational.core.sql.SqlIdentifier; +import org.springframework.r2dbc.core.Parameter; + +/** + * Assertion methods for {@link OutboundRow}. + *

+ * To create an instance of this class, invoke {@link Assertions#assertThat(OutboundRow)}. + *

+ */ +public class OutboundRowAssert extends AbstractMapAssert { + + private OutboundRowAssert(OutboundRow actual) { + super(actual, OutboundRowAssert.class); + } + + public static OutboundRowAssert assertThat(OutboundRow actual) { + return new OutboundRowAssert(actual); + } + + /** + * Verifies that the actual row contains the given column. + * + * @param identifier the given identifier. + * @return {@code this} assertions object. + * @throws AssertionError if the actual row is {@code null}. + * @throws AssertionError if the actual row does not contain the given column. + * @see SqlIdentifier#unquoted(String) + */ + public OutboundRowAssert containsColumn(String identifier) { + return containsColumn(SqlIdentifier.unquoted(identifier)); + } + + /** + * Verifies that the actual row contains the given column. + * + * @param identifier the given identifier. + * @return {@code this} assertions object. + * @throws AssertionError if the actual row is {@code null}. + * @throws AssertionError if the actual row does not contain the given column. + */ + public OutboundRowAssert containsColumn(SqlIdentifier identifier) { + + isNotNull(); + if (!this.actual.containsKey(identifier)) { + failWithMessage(ShouldContain.shouldContain(actual, identifier, actual.keySet()).create()); + } + + return this; + } + + /** + * Verifies that the actual row contains only the given columns and nothing else, in any order. + * + * @param columns the given columns that should be in the actual row. + * @return {@code this} assertions object + * @throws AssertionError if the actual row is {@code null} or empty. + * @throws AssertionError if the actual row does not contain the given columns, i.e. the actual row contains some or + * none of the given columns, or the actual row's columns contains columns not in the given ones. + * @throws IllegalArgumentException if the given argument is an empty array. + */ + public OutboundRowAssert containsOnlyColumns(String... columns) { + return containsOnlyColumns(Arrays.stream(columns).map(SqlIdentifier::unquoted).collect(Collectors.toList())); + } + + /** + * Verifies that the actual row contains only the given columns and nothing else, in any order. + * + * @param columns the given columns that should be in the actual row. + * @return {@code this} assertions object + * @throws AssertionError if the actual row is {@code null} or empty. + * @throws AssertionError if the actual row does not contain the given columns, i.e. the actual row contains some or + * none of the given columns, or the actual row's columns contains columns not in the given ones. + * @throws IllegalArgumentException if the given argument is an empty array. + */ + public OutboundRowAssert containsOnlyColumns(SqlIdentifier... columns) { + return containsOnlyColumns(Arrays.asList(columns)); + } + + /** + * Verifies that the actual row contains only the given columns and nothing else, in any order. + * + * @param columns the given columns that should be in the actual row. + * @return {@code this} assertions object + * @throws AssertionError if the actual row is {@code null} or empty. + * @throws AssertionError if the actual row does not contain the given columns, i.e. the actual row contains some or + * none of the given columns, or the actual row's columns contains columns not in the given ones. + * @throws IllegalArgumentException if the given argument is an empty array. + */ + public OutboundRowAssert containsOnlyColumns(Iterable columns) { + containsOnlyKeys(columns); + return this; + } + + /** + * Verifies that the actual row contains the given column with a specific {@code value}. + * + * @param identifier the given identifier. + * @param value the value to assert for. + * @return {@code this} assertions object. + * @throws AssertionError if the actual row is {@code null}. + * @throws AssertionError if the actual row does not contain the given column. + * @see SqlIdentifier#unquoted(String) + */ + public OutboundRowAssert containsColumnWithValue(String identifier, Object value) { + return containsColumnWithValue(SqlIdentifier.unquoted(identifier), value); + } + + /** + * Verifies that the actual row contains the given column with a specific {@code value}. + * + * @param identifier the given identifier. + * @param value the value to assert for. + * @return {@code this} assertions object. + * @throws AssertionError if the actual row is {@code null}. + * @throws AssertionError if the actual row does not contain the given column. + */ + public OutboundRowAssert containsColumnWithValue(SqlIdentifier identifier, Object value) { + + isNotNull(); + + containsColumn(identifier); + withColumn(identifier).hasValue(value); + + return this; + } + + /** + * Verifies that the actual row contains the given columns. + * + * @param identifier the given identifier. + * @return {@code this} assertions object. + * @throws AssertionError if the actual row is {@code null}. + * @throws AssertionError if the actual row does not contain the given column. + * @see SqlIdentifier#unquoted(String) + */ + public OutboundRowAssert containsColumns(String... identifier) { + return containsColumns(Arrays.stream(identifier).map(SqlIdentifier::unquoted).toArray(SqlIdentifier[]::new)); + } + + /** + * Verifies that the actual row contains the given columns. + * + * @param identifier the given identifier. + * @return {@code this} assertions object. + * @throws AssertionError if the actual row is {@code null}. + * @throws AssertionError if the actual row does not contain the given column. + */ + public OutboundRowAssert containsColumns(SqlIdentifier... identifier) { + + isNotNull(); + + containsKeys(identifier); + + return this; + } + + /** + * Verifies that the actual row contains the given column that is {@link Parameter#isEmpty() empty}. + * + * @param identifier the given identifier. + * @return {@code this} assertions object. + * @throws AssertionError if the actual row is {@code null}. + * @throws AssertionError if the actual row does not contain the given column. + * @see SqlIdentifier#unquoted(String) + */ + public OutboundRowAssert containsEmptyColumn(String identifier) { + return containsColumn(SqlIdentifier.unquoted(identifier)); + } + + /** + * Verifies that the actual row contains the given column that is {@link Parameter#isEmpty() empty}. + * + * @param identifier the given identifier. + * @return {@code this} assertions object. + * @throws AssertionError if the actual row is {@code null}. + * @throws AssertionError if the actual row does not contain the given column. + */ + public OutboundRowAssert containsEmptyColumn(SqlIdentifier identifier) { + + containsColumn(identifier); + + Parameter parameter = actual.get(identifier); + if (!parameter.isEmpty()) { + failWithMessage(ShouldBeEmpty.shouldBeEmpty(parameter).create()); + } + + return this; + } + + /** + * Create a nested assertion for {@link Parameter}. + * + * @param identifier the given identifier. + * @return a new assertions object. + */ + public ParameterAssert withColumn(String identifier) { + return withColumn(SqlIdentifier.unquoted(identifier)); + } + + /** + * Create a nested assertion for {@link Parameter}. + * + * @param identifier the given identifier. + * @return a new assertions object. + */ + public ParameterAssert withColumn(SqlIdentifier identifier) { + return new ParameterAssert(actual.get(identifier)).as("Parameter " + identifier); + } + + /** + * Assertion methods for {@link Parameter}. + *

+ * To create an instance of this class, invoke Assertions#assertThat(row).withColumn("myColumn"). + *

+ */ + public static class ParameterAssert extends AbstractAssert { + + ParameterAssert(Parameter parameter) { + super(parameter, ParameterAssert.class); + } + + /** + * Verifies that the parameter is empty. + * + * @throws AssertionError if the actual parameter is {@code null}. + * @throws AssertionError if the actual parameter contains a value. + * @return {@code this} assertions object. + */ + public ParameterAssert isEmpty() { + + isNotNull(); + + if (!this.actual.isEmpty()) { + failWithMessage(ShouldBeEmpty.shouldBeEmpty(actual).create()); + } + + return this; + } + + /** + * Verifies that the parameter contains a value. + * + * @throws AssertionError if the actual parameter is {@code null}. + * @throws AssertionError if the actual parameter is empty. + * @return {@code this} assertions object. + */ + public ParameterAssert hasValue() { + + isNotNull(); + + if (!this.actual.hasValue()) { + failWithMessage(ShouldNotBeEmpty.shouldNotBeEmpty().create()); + } + + return this; + } + + /** + * Verifies that the parameter contains a specific value. + * + * @throws AssertionError if the actual parameter is {@code null}. + * @throws AssertionError if the actual parameter does not match the value. + * @return {@code this} assertions object. + */ + public ParameterAssert hasValue(Object value) { + + isNotNull(); + + Assertions.assertThat(actual.getValue()).isEqualTo(value); + + return this; + } + + /** + * Verifies that the parameter contains a value that is instance of {@code type}. + * + * @return {@code this} assertions object. + */ + public ParameterAssert hasValueInstanceOf(Class type) { + + isNotNull(); + + Assertions.assertThat(actual.getValue()).isInstanceOf(type); + + return this; + } + + /** + * Verifies that the parameter type is equal to {@code type}. + * + * @return {@code this} assertions object. + */ + public ParameterAssert hasType(Class type) { + + isNotNull(); + + if (!this.actual.getType().equals(type)) { + failWithMessage(new BasicErrorMessageFactory( + "Expecting\n" + " <%s>\n" + "to be instance of:\n" + " <%s>\n" + "but was not", actual.getType(), type) + .create()); + } + + return this; + } + + } + +}