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