1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.dbunit;
22
23 import static org.assertj.core.api.Assertions.assertThat;
24 import static org.assertj.core.api.Assertions.assertThatCode;
25
26 import java.sql.PreparedStatement;
27 import java.sql.SQLException;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.List;
31 import java.util.Locale;
32 import java.util.concurrent.atomic.AtomicInteger;
33
34 import org.dbunit.database.CachedResultSetTableFactory;
35 import org.dbunit.database.DatabaseConfig;
36 import org.dbunit.database.IDatabaseConnection;
37 import org.dbunit.database.IResultSetTable;
38 import org.dbunit.database.IResultSetTableFactory;
39 import org.dbunit.dataset.Column;
40 import org.dbunit.dataset.DataSetException;
41 import org.dbunit.dataset.ITable;
42 import org.dbunit.dataset.ITableMetaData;
43 import org.dbunit.operation.DatabaseOperation;
44 import org.dbunit.util.fileloader.DataFileLoader;
45 import org.dbunit.util.fileloader.FlatXmlDataFileLoader;
46 import org.junit.jupiter.api.Test;
47
48
49
50
51
52
53
54
55
56
57 class DefaultPrepAndExpectedTestCaseColumnProjectionIT
58 {
59 private static final String ALL_TABLES_DATA_FILE_NAME = "/xml/flatXmlDataSetTest.xml";
60 private static final String TEST_TABLE_DATA_FILE_NAME =
61 "/xml/columnProjectionPrepAndExpected.xml";
62 private static final String TEST_TABLE = "TEST_TABLE";
63 private static final String[] NO_COLUMNS = {};
64
65 private final DataFileLoader dataFileLoader = new FlatXmlDataFileLoader();
66
67 @Test
68 void testPostTest_sortOnFilteredColumnsOnlyOnEveryTable_passesOnTheDatabaseColumns()
69 throws Exception
70 {
71 final VerifyTableDefinition[] tables = {sorted("TEST_TABLE"), sorted("SECOND_TABLE"),
72 sorted("EMPTY_TABLE"), sorted("PK_TABLE"), sorted("ONLY_PK_TABLE"),
73 sorted("EMPTY_MULTITYPE_TABLE")};
74
75 runWithRecordingFactory(ALL_TABLES_DATA_FILE_NAME, tables, (testCase, recording) ->
76 assertThatCode(testCase::postTest)
77 .as("Selecting the compared columns from the database's own column"
78 + " definitions must verify the same data as selecting every"
79 + " column, on every table shape.")
80 .doesNotThrowAnyException());
81 }
82
83 @Test
84 void testPostTest_sortOnFilteredColumnsOnlyWithExcludedColumns_selectsOnlyTheComparedColumns()
85 throws Exception
86 {
87 final VerifyTableDefinition[] tables = {new VerifyTableDefinition(TEST_TABLE,
88 new String[] {"COLUMN2", "COLUMN3"}, null, null, true)};
89
90 runWithRecordingFactory(TEST_TABLE_DATA_FILE_NAME, tables, (testCase, recording) ->
91 {
92 testCase.postTest();
93
94 assertThat(recording.getRequestedColumnNames())
95 .as("An excluded column plays no part in sorting or comparing, so it must not"
96 + " be selected.")
97 .containsExactly(Arrays.asList("COLUMN0", "COLUMN1"));
98 assertThat(recording.getSelectStatements())
99 .as("No select * statement may be issued when the columns can be projected.")
100 .isEmpty();
101 });
102 }
103
104 @Test
105 void testPostTest_defaultSortWithExcludedColumns_selectsEveryColumn() throws Exception
106 {
107 final VerifyTableDefinition[] tables = {new VerifyTableDefinition(TEST_TABLE,
108 new String[] {"COLUMN2", "COLUMN3"}, null, null, false)};
109
110 runWithRecordingFactory(TEST_TABLE_DATA_FILE_NAME, tables, (testCase, recording) ->
111 {
112 testCase.postTest();
113
114 assertThat(recording.getSelectStatements())
115 .as("Every database column is a sort key in the default mode, so every column"
116 + " must still be selected.")
117 .singleElement().asString().containsIgnoringCase("select *");
118 assertThat(recording.getRequestedColumnNames())
119 .as("The default mode must not project the columns, so no column list may be"
120 + " requested.")
121 .isEmpty();
122 });
123 }
124
125 @Test
126 void testPostTest_sortOnFilteredColumnsOnlyAndEveryColumnExcluded_fallsBackToSelectingEveryColumn()
127 throws Exception
128 {
129 final VerifyTableDefinition[] tables = {new VerifyTableDefinition(TEST_TABLE,
130 new String[] {"COLUMN0", "COLUMN1", "COLUMN2", "COLUMN3"}, null, null, true)};
131
132 runWithRecordingFactory(TEST_TABLE_DATA_FILE_NAME, tables, (testCase, recording) ->
133 {
134 assertThatCode(testCase::postTest)
135 .as("Nothing is compared, so the verification must pass.")
136 .doesNotThrowAnyException();
137
138 assertThat(recording.getSelectStatements())
139 .as("A select list with no columns is invalid, so the whole table must be"
140 + " selected instead.")
141 .singleElement().asString().containsIgnoringCase("select *");
142 });
143 }
144
145 @Test
146 void testPostTest_sortOnFilteredColumnsOnlyAndLoadTableDataFromDatabaseOverridden_callsTheOverride()
147 throws Exception
148 {
149 final VerifyTableDefinition[] tables = {new VerifyTableDefinition(TEST_TABLE,
150 new String[] {"COLUMN2", "COLUMN3"}, null, null, true)};
151 final AtomicInteger overrideCalls = new AtomicInteger();
152 final IDatabaseTester tester = makeDatabaseTester();
153 final DefaultPrepAndExpectedTestCase testCase =
154 new DefaultPrepAndExpectedTestCase(dataFileLoader, tester)
155 {
156 @Override
157 public ITable loadTableDataFromDatabase(final String tableName,
158 final IDatabaseConnection connection) throws Exception
159 {
160 overrideCalls.incrementAndGet();
161 return super.loadTableDataFromDatabase(tableName, connection);
162 }
163 };
164 testCase.configureTest(tables, new String[] {TEST_TABLE_DATA_FILE_NAME},
165 new String[] {TEST_TABLE_DATA_FILE_NAME});
166 testCase.preTest();
167
168 try
169 {
170 testCase.postTest();
171 } finally
172 {
173 DatabaseEnvironment.getInstance().closeConnection();
174 }
175
176 assertThat(overrideCalls)
177 .as("A subclass that overrides how the table is loaded, for example to add a"
178 + " where clause, must keep deciding that, so the columns are not"
179 + " projected behind its back.")
180 .hasValue(1);
181 }
182
183 private interface Verification
184 {
185 void run(DefaultPrepAndExpectedTestCase testCase, RecordingResultSetTableFactory recording)
186 throws Exception;
187 }
188
189 private void runWithRecordingFactory(final String dataFileName,
190 final VerifyTableDefinition[] tables, final Verification verification)
191 throws Exception
192 {
193 final DatabaseEnvironment environment = DatabaseEnvironment.getInstance();
194 try
195 {
196 final IDatabaseConnection connection = environment.getConnection();
197 final RecordingResultSetTableFactory recording = new RecordingResultSetTableFactory();
198 connection.getConfig().setProperty(DatabaseConfig.PROPERTY_RESULTSET_TABLE_FACTORY,
199 recording);
200 final IDatabaseTester tester = new DefaultDatabaseTester(connection);
201 tester.setTearDownOperation(DatabaseOperation.DELETE_ALL);
202 final DefaultPrepAndExpectedTestCase testCase =
203 new DefaultPrepAndExpectedTestCase(dataFileLoader, tester);
204 testCase.configureTest(tables, new String[] {dataFileName},
205 new String[] {dataFileName});
206 testCase.preTest();
207
208 verification.run(testCase, recording);
209 } finally
210 {
211 environment.closeConnection();
212 }
213 }
214
215 private static VerifyTableDefinition sorted(final String tableName)
216 {
217 return new VerifyTableDefinition(tableName, NO_COLUMNS, null, null, true);
218 }
219
220 private IDatabaseTester makeDatabaseTester() throws Exception
221 {
222 final IDatabaseConnection connection = DatabaseEnvironment.getInstance().getConnection();
223 final IDatabaseTester tester = new DefaultDatabaseTester(connection);
224 tester.setTearDownOperation(DatabaseOperation.DELETE_ALL);
225 return tester;
226 }
227
228 private static final class RecordingResultSetTableFactory implements IResultSetTableFactory
229 {
230 private final IResultSetTableFactory delegate = new CachedResultSetTableFactory();
231 private final List<String> selectStatements = new ArrayList<>();
232 private final List<List<String>> requestedColumnNames = new ArrayList<>();
233
234 @Override
235 public IResultSetTable createTable(final String tableName, final String selectStatement,
236 final IDatabaseConnection connection) throws SQLException, DataSetException
237 {
238 selectStatements.add(selectStatement);
239 return delegate.createTable(tableName, selectStatement, connection);
240 }
241
242 @Override
243 public IResultSetTable createTable(final ITableMetaData metaData,
244 final IDatabaseConnection connection) throws SQLException, DataSetException
245 {
246 final List<String> columnNames = new ArrayList<>();
247 for (final Column column : metaData.getColumns())
248 {
249 columnNames.add(column.getColumnName().toUpperCase(Locale.ENGLISH));
250 }
251 requestedColumnNames.add(columnNames);
252 return delegate.createTable(metaData, connection);
253 }
254
255 @Override
256 public IResultSetTable createTable(final String tableName,
257 final PreparedStatement preparedStatement, final IDatabaseConnection connection)
258 throws SQLException, DataSetException
259 {
260 return delegate.createTable(tableName, preparedStatement, connection);
261 }
262
263 private List<String> getSelectStatements()
264 {
265 return selectStatements;
266 }
267
268 private List<List<String>> getRequestedColumnNames()
269 {
270 return requestedColumnNames;
271 }
272 }
273 }