Coverage Report

Created: 2024-04-30 09:35

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