test/zserio/SqliteConnectionTest.cpp
Line | Count | Source |
1 | | #include "zserio/SqliteConnection.h" |
2 | | #include "zserio/SqliteException.h" |
3 | | |
4 | | #include <string> |
5 | | #include <vector> |
6 | | #include <algorithm> |
7 | | |
8 | | #include "sqlite3.h" |
9 | | |
10 | | #include "gtest/gtest.h" |
11 | | |
12 | | namespace zserio |
13 | | { |
14 | | |
15 | | namespace |
16 | | { |
17 | | extern "C" int sqliteResultAccumulatorCallback(void *data, int nColumns, char** colValues, char** colNames); |
18 | | |
19 | | class SqliteResultAccumulator |
20 | | { |
21 | | public: |
22 | | using TRow = std::vector<std::string>; |
23 | | using TResult = std::vector<TRow>; |
24 | | |
25 | | TResult const& getResult() const |
26 | 2 | { |
27 | 2 | return result; |
28 | 2 | } |
29 | | |
30 | | int callback(size_t nColumns, char** colValues, char**) |
31 | 2 | { |
32 | 2 | auto colValuesSpan = Span<char*>(colValues, nColumns); |
33 | 2 | TRow row; |
34 | 2 | row.reserve(nColumns); |
35 | 2 | for (const char* colValue : colValuesSpan) |
36 | 2 | row.emplace_back(colValue); |
37 | 2 | result.push_back(row); |
38 | 2 | return 0; // continue |
39 | 2 | } |
40 | | |
41 | | TResult result; |
42 | | }; |
43 | | |
44 | | int sqliteResultAccumulatorCallback(void *data, int nColumns, char** colValues, char** colNames) |
45 | 2 | { |
46 | 2 | SqliteResultAccumulator *self = static_cast<SqliteResultAccumulator*>(data); |
47 | 2 | return self->callback(static_cast<size_t>(nColumns), colValues, colNames); |
48 | 2 | } |
49 | | } // namespace |
50 | | |
51 | | static const char* const SQLITE3_MEM_DB = ":memory:"; |
52 | | |
53 | | TEST(SqliteConnectionTest, emptyConstructor) |
54 | 1 | { |
55 | 1 | SqliteConnection db; |
56 | 1 | ASSERT_EQ(nullptr, db.getConnection()); |
57 | 1 | } |
58 | | |
59 | | TEST(SqliteConnectionTest, externalConstructor) |
60 | 1 | { |
61 | 1 | sqlite3 *externalConnection = nullptr; |
62 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &externalConnection); |
63 | 1 | ASSERT_EQ(SQLITE_OK, result); |
64 | | |
65 | 1 | SqliteConnection db(externalConnection, SqliteConnection::EXTERNAL_CONNECTION); |
66 | 1 | ASSERT_EQ(externalConnection, db.getConnection()); |
67 | 1 | ASSERT_EQ(SqliteConnection::EXTERNAL_CONNECTION, db.getConnectionType()); |
68 | | |
69 | 1 | db.reset(); |
70 | | |
71 | 1 | result = sqlite3_close(externalConnection); |
72 | 1 | ASSERT_EQ(SQLITE_OK, result); |
73 | | |
74 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
75 | 1 | } |
76 | | |
77 | | TEST(SqliteConnectionTest, internalConstructor) |
78 | 1 | { |
79 | 1 | sqlite3* internalConnection = nullptr; |
80 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection); |
81 | 1 | ASSERT_EQ(SQLITE_OK, result); |
82 | | |
83 | 1 | SqliteConnection db(internalConnection, SqliteConnection::INTERNAL_CONNECTION); |
84 | 1 | ASSERT_EQ(internalConnection, db.getConnection()); |
85 | 1 | ASSERT_EQ(SqliteConnection::INTERNAL_CONNECTION, db.getConnectionType()); |
86 | | |
87 | 1 | db.reset(); |
88 | 1 | ASSERT_EQ(nullptr, db.getConnection()); |
89 | | |
90 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
91 | 1 | } |
92 | | |
93 | | TEST(SqliteConnectionTest, defaultInternalConstructor) |
94 | 1 | { |
95 | 1 | sqlite3* internalConnection = nullptr; |
96 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection); |
97 | 1 | ASSERT_EQ(SQLITE_OK, result); |
98 | | |
99 | 1 | SqliteConnection db(internalConnection, SqliteConnection::INTERNAL_CONNECTION); |
100 | 1 | ASSERT_EQ(internalConnection, db.getConnection()); |
101 | 1 | ASSERT_EQ(SqliteConnection::INTERNAL_CONNECTION, db.getConnectionType()); |
102 | | |
103 | 1 | db.reset(); |
104 | 1 | ASSERT_EQ(nullptr, db.getConnection()); |
105 | | |
106 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
107 | 1 | } |
108 | | |
109 | | TEST(SqliteConnectionTest, resetExternal) |
110 | 1 | { |
111 | 1 | sqlite3 *externalConnection = nullptr; |
112 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &externalConnection); |
113 | 1 | ASSERT_EQ(SQLITE_OK, result); |
114 | | |
115 | 1 | SqliteConnection db; |
116 | 1 | db.reset(externalConnection, SqliteConnection::EXTERNAL_CONNECTION); |
117 | 1 | ASSERT_EQ(externalConnection, db.getConnection()); |
118 | 1 | ASSERT_EQ(SqliteConnection::EXTERNAL_CONNECTION, db.getConnectionType()); |
119 | | |
120 | 1 | db.reset(); |
121 | 1 | ASSERT_EQ(nullptr, db.getConnection()); |
122 | | |
123 | 1 | result = sqlite3_close(externalConnection); |
124 | 1 | ASSERT_EQ(SQLITE_OK, result); |
125 | | |
126 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
127 | 1 | } |
128 | | |
129 | | TEST(SqliteConnectionTest, resetInternal) |
130 | 1 | { |
131 | 1 | sqlite3* internalConnection = nullptr; |
132 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection); |
133 | 1 | ASSERT_EQ(SQLITE_OK, result); |
134 | | |
135 | 1 | SqliteConnection db; |
136 | 1 | db.reset(internalConnection, SqliteConnection::INTERNAL_CONNECTION); |
137 | 1 | ASSERT_EQ(internalConnection, db.getConnection()); |
138 | 1 | ASSERT_EQ(SqliteConnection::INTERNAL_CONNECTION, db.getConnectionType()); |
139 | | |
140 | 1 | db.reset(); |
141 | 1 | ASSERT_EQ(nullptr, db.getConnection()); |
142 | | |
143 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
144 | 1 | } |
145 | | |
146 | | TEST(SqliteConnectionTest, resetDefaultInternal) |
147 | 1 | { |
148 | 1 | sqlite3* internalConnection = nullptr; |
149 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection); |
150 | 1 | ASSERT_EQ(SQLITE_OK, result); |
151 | | |
152 | 1 | SqliteConnection db; |
153 | 1 | db.reset(internalConnection); |
154 | 1 | ASSERT_EQ(internalConnection, db.getConnection()); |
155 | 1 | ASSERT_EQ(SqliteConnection::INTERNAL_CONNECTION, db.getConnectionType()); |
156 | | |
157 | 1 | db.reset(); |
158 | 1 | ASSERT_EQ(nullptr, db.getConnection()); |
159 | | |
160 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
161 | 1 | } |
162 | | |
163 | | TEST(SqliteConnectionTest, doubleResetExternal) |
164 | 1 | { |
165 | 1 | sqlite3 *externalConnection1 = nullptr; |
166 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &externalConnection1); |
167 | 1 | ASSERT_EQ(SQLITE_OK, result); |
168 | | |
169 | 1 | sqlite3 *externalConnection2 = nullptr; |
170 | 1 | result = sqlite3_open(SQLITE3_MEM_DB, &externalConnection2); |
171 | 1 | ASSERT_EQ(SQLITE_OK, result); |
172 | | |
173 | 1 | { |
174 | 1 | SqliteConnection db; |
175 | 1 | db.reset(externalConnection1, SqliteConnection::EXTERNAL_CONNECTION); |
176 | 1 | ASSERT_EQ(externalConnection1, db.getConnection()); |
177 | 1 | ASSERT_EQ(SqliteConnection::EXTERNAL_CONNECTION, db.getConnectionType()); |
178 | | |
179 | 1 | db.reset(externalConnection2, SqliteConnection::EXTERNAL_CONNECTION); |
180 | 1 | ASSERT_EQ(externalConnection2, db.getConnection()); |
181 | 1 | ASSERT_EQ(SqliteConnection::EXTERNAL_CONNECTION, db.getConnectionType()); |
182 | 1 | } // db dtor |
183 | | |
184 | 1 | result = sqlite3_close(externalConnection1); |
185 | 1 | ASSERT_EQ(SQLITE_OK, result); |
186 | | |
187 | 1 | result = sqlite3_close(externalConnection2); |
188 | 1 | ASSERT_EQ(SQLITE_OK, result); |
189 | | |
190 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
191 | 1 | } |
192 | | |
193 | | TEST(SqliteConnectionTest, doubleResetInternal) |
194 | 1 | { |
195 | 1 | sqlite3 *internalConnection1 = nullptr; |
196 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection1); |
197 | 1 | ASSERT_EQ(SQLITE_OK, result); |
198 | | |
199 | 1 | sqlite3 *internalConnection2 = nullptr; |
200 | 1 | result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection2); |
201 | 1 | ASSERT_EQ(SQLITE_OK, result); |
202 | | |
203 | 1 | { |
204 | 1 | SqliteConnection db; |
205 | 1 | db.reset(internalConnection1); |
206 | 1 | ASSERT_EQ(internalConnection1, db.getConnection()); |
207 | 1 | ASSERT_EQ(SqliteConnection::INTERNAL_CONNECTION, db.getConnectionType()); |
208 | | |
209 | 1 | db.reset(internalConnection2); |
210 | 1 | ASSERT_EQ(internalConnection2, db.getConnection()); |
211 | 1 | ASSERT_EQ(SqliteConnection::INTERNAL_CONNECTION, db.getConnectionType()); |
212 | 1 | } // db dtor |
213 | | |
214 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
215 | 1 | } |
216 | | |
217 | | TEST(SqliteConnectionTest, getConnection) |
218 | 1 | { |
219 | 1 | sqlite3 *internalConnection = nullptr; |
220 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection); |
221 | 1 | ASSERT_EQ(SQLITE_OK, result); |
222 | | |
223 | 1 | SqliteConnection db(internalConnection); |
224 | 1 | ASSERT_EQ(internalConnection, db.getConnection()); |
225 | | |
226 | 1 | db.reset(); |
227 | 1 | ASSERT_EQ(nullptr, db.getConnection()); |
228 | | |
229 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
230 | 1 | } |
231 | | |
232 | | TEST(SqliteConnectionTest, getConnectionType) |
233 | 1 | { |
234 | 1 | sqlite3 *internalConnection = nullptr; |
235 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection); |
236 | 1 | ASSERT_EQ(SQLITE_OK, result); |
237 | | |
238 | 1 | SqliteConnection db(internalConnection); |
239 | 1 | ASSERT_EQ(SqliteConnection::INTERNAL_CONNECTION, db.getConnectionType()); |
240 | | |
241 | 1 | sqlite3 *externalConnection = nullptr; |
242 | 1 | result = sqlite3_open(SQLITE3_MEM_DB, &externalConnection); |
243 | 1 | ASSERT_EQ(SQLITE_OK, result); |
244 | | |
245 | 1 | db.reset(externalConnection, SqliteConnection::EXTERNAL_CONNECTION); |
246 | 1 | ASSERT_EQ(SqliteConnection::EXTERNAL_CONNECTION, db.getConnectionType()); |
247 | | |
248 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_close(externalConnection)); |
249 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
250 | 1 | } |
251 | | |
252 | | TEST(SqliteConnectionTest, reset) |
253 | 1 | { |
254 | 1 | sqlite3 *internalConnection = nullptr; |
255 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection); |
256 | 1 | ASSERT_EQ(SQLITE_OK, result); |
257 | | |
258 | 1 | SqliteConnection db; |
259 | 1 | db.reset(internalConnection); |
260 | 1 | ASSERT_EQ(internalConnection, db.getConnection()); |
261 | | |
262 | 1 | db.reset(); |
263 | 1 | ASSERT_EQ(nullptr, db.getConnection()); |
264 | | |
265 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
266 | 1 | } |
267 | | |
268 | | TEST(SqliteConnectionTest, executeUpdate) |
269 | 1 | { |
270 | 1 | sqlite3 *internalConnection = nullptr; |
271 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection); |
272 | 1 | ASSERT_EQ(SQLITE_OK, result); |
273 | | |
274 | 1 | SqliteConnection db(internalConnection); |
275 | | |
276 | 1 | const std::string query("CREATE TABLE Foo AS SELECT 1"); // check that generic string version works |
277 | 1 | db.executeUpdate(query); |
278 | | |
279 | 1 | sqlite3* const dbConnection = db.getConnection(); |
280 | 1 | SqliteResultAccumulator resultAcc; |
281 | 1 | sqlite3_exec(dbConnection, "SELECT * FROM Foo", sqliteResultAccumulatorCallback, &resultAcc, nullptr); |
282 | | |
283 | 1 | SqliteResultAccumulator::TResult const& accResult = resultAcc.getResult(); |
284 | 1 | ASSERT_EQ(1, accResult.size()); |
285 | 1 | SqliteResultAccumulator::TRow const& row = accResult.front(); |
286 | 1 | ASSERT_EQ(1, row.size()); |
287 | 1 | ASSERT_EQ("1", row.front()); |
288 | | |
289 | 1 | db.reset(); |
290 | | |
291 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
292 | 1 | } |
293 | | |
294 | | TEST(SqliteConnectionTest, executeUpdateOnReadOnlyDatabase) |
295 | 1 | { |
296 | 1 | sqlite3 *internalConnection = nullptr; |
297 | 1 | int result = sqlite3_open_v2(SQLITE3_MEM_DB, &internalConnection, SQLITE_OPEN_READONLY, nullptr); |
298 | 1 | SqliteConnection db(internalConnection); |
299 | 1 | ASSERT_EQ(SQLITE_OK, result); |
300 | 1 | ASSERT_THROW(db.executeUpdate("CREATE TABLE Foo AS SELECT 1"), SqliteException); |
301 | 1 | } |
302 | | |
303 | | TEST(SqliteConnectionTest, prepareStatement) |
304 | 1 | { |
305 | 1 | sqlite3 *internalConnection = nullptr; |
306 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection); |
307 | 1 | ASSERT_EQ(SQLITE_OK, result); |
308 | | |
309 | 1 | SqliteConnection db(internalConnection); |
310 | 1 | db.executeUpdate("CREATE TABLE Foo AS SELECT 1"); |
311 | | |
312 | 1 | sqlite3_stmt* const statement = db.prepareStatement("SELECT 1"); |
313 | 1 | ASSERT_TRUE(statement != nullptr); |
314 | | |
315 | 1 | result = sqlite3_step(statement); |
316 | 1 | ASSERT_EQ(SQLITE_ROW, result); |
317 | | |
318 | 1 | ASSERT_EQ(1, sqlite3_column_count(statement)); |
319 | 1 | const std::string resultString(reinterpret_cast<const char*>(sqlite3_column_text(statement, 0))); |
320 | 1 | ASSERT_EQ("1", resultString); |
321 | | |
322 | 1 | result = sqlite3_step(statement); |
323 | 1 | ASSERT_EQ(SQLITE_DONE, result); |
324 | | |
325 | 1 | result = sqlite3_finalize(statement); |
326 | 1 | ASSERT_EQ(SQLITE_OK, result); |
327 | | |
328 | 1 | ASSERT_THROW(db.prepareStatement("SOME RUBBISH"), SqliteException); |
329 | | |
330 | 1 | db.reset(); |
331 | | |
332 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
333 | 1 | } |
334 | | |
335 | | TEST(SqliteConnectionTest, startEndTransaction) |
336 | 1 | { |
337 | 1 | sqlite3 *internalConnection = nullptr; |
338 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection); |
339 | 1 | ASSERT_EQ(SQLITE_OK, result); |
340 | | |
341 | 1 | SqliteConnection db(internalConnection); |
342 | | |
343 | 1 | const bool wasTransactionStarted = db.startTransaction(); |
344 | 1 | const std::string query("CREATE TABLE Foo AS SELECT 1"); // check that generic string version works |
345 | 1 | db.executeUpdate(query); |
346 | 1 | db.endTransaction(wasTransactionStarted); |
347 | | |
348 | 1 | sqlite3* const dbConnection = db.getConnection(); |
349 | 1 | SqliteResultAccumulator resultAcc; |
350 | 1 | sqlite3_exec(dbConnection, "SELECT * FROM Foo", sqliteResultAccumulatorCallback, &resultAcc, nullptr); |
351 | | |
352 | 1 | SqliteResultAccumulator::TResult const& accResult = resultAcc.getResult(); |
353 | 1 | ASSERT_EQ(1, accResult.size()); |
354 | 1 | SqliteResultAccumulator::TRow const& row = accResult.front(); |
355 | 1 | ASSERT_EQ(1, row.size()); |
356 | 1 | ASSERT_EQ("1", row.front()); |
357 | | |
358 | 1 | db.executeUpdate("BEGIN"); |
359 | 1 | const bool transactionNotStarted = db.startTransaction(); |
360 | 1 | ASSERT_FALSE(transactionNotStarted); |
361 | 1 | db.endTransaction(transactionNotStarted); |
362 | | |
363 | 1 | db.reset(); |
364 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
365 | 1 | } |
366 | | |
367 | | } // namespace zserio |