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 | row.emplace_back(colValue); |
36 | 2 | result.push_back(row); |
37 | 2 | return 0; // continue |
38 | 2 | } |
39 | | |
40 | | TResult result; |
41 | | }; |
42 | | |
43 | | int sqliteResultAccumulatorCallback(void* data, int nColumns, char** colValues, char** colNames) |
44 | 2 | { |
45 | 2 | SqliteResultAccumulator* self = static_cast<SqliteResultAccumulator*>(data); |
46 | 2 | return self->callback(static_cast<size_t>(nColumns), colValues, colNames); |
47 | 2 | } |
48 | | } // namespace |
49 | | |
50 | | static const char* const SQLITE3_MEM_DB = ":memory:"; |
51 | | |
52 | | TEST(SqliteConnectionTest, emptyConstructor) |
53 | 1 | { |
54 | 1 | SqliteConnection db; |
55 | 1 | ASSERT_EQ(nullptr, db.getConnection()); |
56 | 1 | } |
57 | | |
58 | | TEST(SqliteConnectionTest, externalConstructor) |
59 | 1 | { |
60 | 1 | sqlite3* externalConnection = nullptr; |
61 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &externalConnection); |
62 | 1 | ASSERT_EQ(SQLITE_OK, result); |
63 | | |
64 | 1 | SqliteConnection db(externalConnection, SqliteConnection::EXTERNAL_CONNECTION); |
65 | 1 | ASSERT_EQ(externalConnection, db.getConnection()); |
66 | 1 | ASSERT_EQ(SqliteConnection::EXTERNAL_CONNECTION, db.getConnectionType()); |
67 | | |
68 | 1 | db.reset(); |
69 | | |
70 | 1 | result = sqlite3_close(externalConnection); |
71 | 1 | ASSERT_EQ(SQLITE_OK, result); |
72 | | |
73 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
74 | 1 | } |
75 | | |
76 | | TEST(SqliteConnectionTest, internalConstructor) |
77 | 1 | { |
78 | 1 | sqlite3* internalConnection = nullptr; |
79 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection); |
80 | 1 | ASSERT_EQ(SQLITE_OK, result); |
81 | | |
82 | 1 | SqliteConnection db(internalConnection, SqliteConnection::INTERNAL_CONNECTION); |
83 | 1 | ASSERT_EQ(internalConnection, db.getConnection()); |
84 | 1 | ASSERT_EQ(SqliteConnection::INTERNAL_CONNECTION, db.getConnectionType()); |
85 | | |
86 | 1 | db.reset(); |
87 | 1 | ASSERT_EQ(nullptr, db.getConnection()); |
88 | | |
89 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
90 | 1 | } |
91 | | |
92 | | TEST(SqliteConnectionTest, defaultInternalConstructor) |
93 | 1 | { |
94 | 1 | sqlite3* internalConnection = nullptr; |
95 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection); |
96 | 1 | ASSERT_EQ(SQLITE_OK, result); |
97 | | |
98 | 1 | SqliteConnection db(internalConnection, SqliteConnection::INTERNAL_CONNECTION); |
99 | 1 | ASSERT_EQ(internalConnection, db.getConnection()); |
100 | 1 | ASSERT_EQ(SqliteConnection::INTERNAL_CONNECTION, db.getConnectionType()); |
101 | | |
102 | 1 | db.reset(); |
103 | 1 | ASSERT_EQ(nullptr, db.getConnection()); |
104 | | |
105 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
106 | 1 | } |
107 | | |
108 | | TEST(SqliteConnectionTest, resetExternal) |
109 | 1 | { |
110 | 1 | sqlite3* externalConnection = nullptr; |
111 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &externalConnection); |
112 | 1 | ASSERT_EQ(SQLITE_OK, result); |
113 | | |
114 | 1 | SqliteConnection db; |
115 | 1 | db.reset(externalConnection, SqliteConnection::EXTERNAL_CONNECTION); |
116 | 1 | ASSERT_EQ(externalConnection, db.getConnection()); |
117 | 1 | ASSERT_EQ(SqliteConnection::EXTERNAL_CONNECTION, db.getConnectionType()); |
118 | | |
119 | 1 | db.reset(); |
120 | 1 | ASSERT_EQ(nullptr, db.getConnection()); |
121 | | |
122 | 1 | result = sqlite3_close(externalConnection); |
123 | 1 | ASSERT_EQ(SQLITE_OK, result); |
124 | | |
125 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
126 | 1 | } |
127 | | |
128 | | TEST(SqliteConnectionTest, resetInternal) |
129 | 1 | { |
130 | 1 | sqlite3* internalConnection = nullptr; |
131 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection); |
132 | 1 | ASSERT_EQ(SQLITE_OK, result); |
133 | | |
134 | 1 | SqliteConnection db; |
135 | 1 | db.reset(internalConnection, SqliteConnection::INTERNAL_CONNECTION); |
136 | 1 | ASSERT_EQ(internalConnection, db.getConnection()); |
137 | 1 | ASSERT_EQ(SqliteConnection::INTERNAL_CONNECTION, db.getConnectionType()); |
138 | | |
139 | 1 | db.reset(); |
140 | 1 | ASSERT_EQ(nullptr, db.getConnection()); |
141 | | |
142 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
143 | 1 | } |
144 | | |
145 | | TEST(SqliteConnectionTest, resetDefaultInternal) |
146 | 1 | { |
147 | 1 | sqlite3* internalConnection = nullptr; |
148 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection); |
149 | 1 | ASSERT_EQ(SQLITE_OK, result); |
150 | | |
151 | 1 | SqliteConnection db; |
152 | 1 | db.reset(internalConnection); |
153 | 1 | ASSERT_EQ(internalConnection, db.getConnection()); |
154 | 1 | ASSERT_EQ(SqliteConnection::INTERNAL_CONNECTION, db.getConnectionType()); |
155 | | |
156 | 1 | db.reset(); |
157 | 1 | ASSERT_EQ(nullptr, db.getConnection()); |
158 | | |
159 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
160 | 1 | } |
161 | | |
162 | | TEST(SqliteConnectionTest, doubleResetExternal) |
163 | 1 | { |
164 | 1 | sqlite3* externalConnection1 = nullptr; |
165 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &externalConnection1); |
166 | 1 | ASSERT_EQ(SQLITE_OK, result); |
167 | | |
168 | 1 | sqlite3* externalConnection2 = nullptr; |
169 | 1 | result = sqlite3_open(SQLITE3_MEM_DB, &externalConnection2); |
170 | 1 | ASSERT_EQ(SQLITE_OK, result); |
171 | | |
172 | 1 | { |
173 | 1 | SqliteConnection db; |
174 | 1 | db.reset(externalConnection1, SqliteConnection::EXTERNAL_CONNECTION); |
175 | 1 | ASSERT_EQ(externalConnection1, db.getConnection()); |
176 | 1 | ASSERT_EQ(SqliteConnection::EXTERNAL_CONNECTION, db.getConnectionType()); |
177 | | |
178 | 1 | db.reset(externalConnection2, SqliteConnection::EXTERNAL_CONNECTION); |
179 | 1 | ASSERT_EQ(externalConnection2, db.getConnection()); |
180 | 1 | ASSERT_EQ(SqliteConnection::EXTERNAL_CONNECTION, db.getConnectionType()); |
181 | 1 | } // db dtor |
182 | | |
183 | 1 | result = sqlite3_close(externalConnection1); |
184 | 1 | ASSERT_EQ(SQLITE_OK, result); |
185 | | |
186 | 1 | result = sqlite3_close(externalConnection2); |
187 | 1 | ASSERT_EQ(SQLITE_OK, result); |
188 | | |
189 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
190 | 1 | } |
191 | | |
192 | | TEST(SqliteConnectionTest, doubleResetInternal) |
193 | 1 | { |
194 | 1 | sqlite3* internalConnection1 = nullptr; |
195 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection1); |
196 | 1 | ASSERT_EQ(SQLITE_OK, result); |
197 | | |
198 | 1 | sqlite3* internalConnection2 = nullptr; |
199 | 1 | result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection2); |
200 | 1 | ASSERT_EQ(SQLITE_OK, result); |
201 | | |
202 | 1 | { |
203 | 1 | SqliteConnection db; |
204 | 1 | db.reset(internalConnection1); |
205 | 1 | ASSERT_EQ(internalConnection1, db.getConnection()); |
206 | 1 | ASSERT_EQ(SqliteConnection::INTERNAL_CONNECTION, db.getConnectionType()); |
207 | | |
208 | 1 | db.reset(internalConnection2); |
209 | 1 | ASSERT_EQ(internalConnection2, db.getConnection()); |
210 | 1 | ASSERT_EQ(SqliteConnection::INTERNAL_CONNECTION, db.getConnectionType()); |
211 | 1 | } // db dtor |
212 | | |
213 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
214 | 1 | } |
215 | | |
216 | | TEST(SqliteConnectionTest, getConnection) |
217 | 1 | { |
218 | 1 | sqlite3* internalConnection = nullptr; |
219 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection); |
220 | 1 | ASSERT_EQ(SQLITE_OK, result); |
221 | | |
222 | 1 | SqliteConnection db(internalConnection); |
223 | 1 | ASSERT_EQ(internalConnection, db.getConnection()); |
224 | | |
225 | 1 | db.reset(); |
226 | 1 | ASSERT_EQ(nullptr, db.getConnection()); |
227 | | |
228 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
229 | 1 | } |
230 | | |
231 | | TEST(SqliteConnectionTest, getConnectionType) |
232 | 1 | { |
233 | 1 | sqlite3* internalConnection = nullptr; |
234 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection); |
235 | 1 | ASSERT_EQ(SQLITE_OK, result); |
236 | | |
237 | 1 | SqliteConnection db(internalConnection); |
238 | 1 | ASSERT_EQ(SqliteConnection::INTERNAL_CONNECTION, db.getConnectionType()); |
239 | | |
240 | 1 | sqlite3* externalConnection = nullptr; |
241 | 1 | result = sqlite3_open(SQLITE3_MEM_DB, &externalConnection); |
242 | 1 | ASSERT_EQ(SQLITE_OK, result); |
243 | | |
244 | 1 | db.reset(externalConnection, SqliteConnection::EXTERNAL_CONNECTION); |
245 | 1 | ASSERT_EQ(SqliteConnection::EXTERNAL_CONNECTION, db.getConnectionType()); |
246 | | |
247 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_close(externalConnection)); |
248 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
249 | 1 | } |
250 | | |
251 | | TEST(SqliteConnectionTest, reset) |
252 | 1 | { |
253 | 1 | sqlite3* internalConnection = nullptr; |
254 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection); |
255 | 1 | ASSERT_EQ(SQLITE_OK, result); |
256 | | |
257 | 1 | SqliteConnection db; |
258 | 1 | db.reset(internalConnection); |
259 | 1 | ASSERT_EQ(internalConnection, db.getConnection()); |
260 | | |
261 | 1 | db.reset(); |
262 | 1 | ASSERT_EQ(nullptr, db.getConnection()); |
263 | | |
264 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
265 | 1 | } |
266 | | |
267 | | TEST(SqliteConnectionTest, executeUpdate) |
268 | 1 | { |
269 | 1 | sqlite3* internalConnection = nullptr; |
270 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection); |
271 | 1 | ASSERT_EQ(SQLITE_OK, result); |
272 | | |
273 | 1 | SqliteConnection db(internalConnection); |
274 | | |
275 | 1 | const std::string query("CREATE TABLE Foo AS SELECT 1"); // check that generic string version works |
276 | 1 | db.executeUpdate(query); |
277 | | |
278 | 1 | sqlite3* const dbConnection = db.getConnection(); |
279 | 1 | SqliteResultAccumulator resultAcc; |
280 | 1 | sqlite3_exec(dbConnection, "SELECT * FROM Foo", sqliteResultAccumulatorCallback, &resultAcc, nullptr); |
281 | | |
282 | 1 | SqliteResultAccumulator::TResult const& accResult = resultAcc.getResult(); |
283 | 1 | ASSERT_EQ(1, accResult.size()); |
284 | 1 | SqliteResultAccumulator::TRow const& row = accResult.front(); |
285 | 1 | ASSERT_EQ(1, row.size()); |
286 | 1 | ASSERT_EQ("1", row.front()); |
287 | | |
288 | 1 | db.reset(); |
289 | | |
290 | 1 | ASSERT_EQ(SQLITE_OK, sqlite3_shutdown()); |
291 | 1 | } |
292 | | |
293 | | TEST(SqliteConnectionTest, executeUpdateOnReadOnlyDatabase) |
294 | 1 | { |
295 | 1 | sqlite3* internalConnection = nullptr; |
296 | 1 | int result = sqlite3_open_v2(SQLITE3_MEM_DB, &internalConnection, SQLITE_OPEN_READONLY, nullptr); |
297 | 1 | SqliteConnection db(internalConnection); |
298 | 1 | ASSERT_EQ(SQLITE_OK, result); |
299 | 1 | ASSERT_THROW(db.executeUpdate("CREATE TABLE Foo AS SELECT 1"), SqliteException); |
300 | 1 | } |
301 | | |
302 | | TEST(SqliteConnectionTest, prepareStatement) |
303 | 1 | { |
304 | 1 | sqlite3* internalConnection = nullptr; |
305 | 1 | int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection); |
306 | 1 | ASSERT_EQ(SQLITE_OK, result); |
307 | | |
308 | 1 | SqliteConnection db(internalConnection); |
309 | 1 | db.executeUpdate("CREATE TABLE Foo AS SELECT 1"); |
310 | | |
311 | 1 | sqlite3_stmt* const statement = db.prepareStatement("SELECT 1"); |
312 | 1 | ASSERT_TRUE(statement != nullptr); |
313 | | |
314 | 1 | result = sqlite3_step(statement); |
315 | 1 | ASSERT_EQ(SQLITE_ROW, result); |
316 | | |
317 | 1 | ASSERT_EQ(1, sqlite3_column_count(statement)); |
318 | 1 | const unsigned char* textValue = sqlite3_column_text(statement, 0); |
319 | 1 | const std::string resultString(static_cast<const char*>(static_cast<const void*>(textValue))); |
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 |