GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: test/zserio/SqliteConnectionTest.cpp Lines: 216 216 100.0 %
Date: 2023-12-13 14:51:09 Branches: 429 1402 30.6 %

Line Branch Exec 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
4
    class SqliteResultAccumulator
20
    {
21
    public:
22
        using TRow = std::vector<std::string>;
23
        using TResult = std::vector<TRow>;
24
25
2
        TResult const& getResult() const
26
        {
27
2
            return result;
28
        }
29
30
2
        int callback(size_t nColumns, char** colValues, char**)
31
        {
32
2
            auto colValuesSpan = Span<char*>(colValues, nColumns);
33
4
            TRow row;
34
2
            row.reserve(nColumns);
35
4
            for (const char* colValue : colValuesSpan)
36
2
                row.emplace_back(colValue);
37
2
            result.push_back(row);
38
4
            return 0; // continue
39
        }
40
41
        TResult result;
42
    };
43
44
2
    int sqliteResultAccumulatorCallback(void *data, int nColumns, char** colValues, char** colNames)
45
    {
46
2
        SqliteResultAccumulator *self = static_cast<SqliteResultAccumulator*>(data);
47
2
        return self->callback(static_cast<size_t>(nColumns), colValues, colNames);
48
    }
49
} // namespace
50
51
static const char* const SQLITE3_MEM_DB = ":memory:";
52
53


802
TEST(SqliteConnectionTest, emptyConstructor)
54
{
55
2
    SqliteConnection db;
56



1
    ASSERT_EQ(nullptr, db.getConnection());
57
}
58
59


802
TEST(SqliteConnectionTest, externalConstructor)
60
{
61
1
    sqlite3 *externalConnection = nullptr;
62
1
    int result = sqlite3_open(SQLITE3_MEM_DB, &externalConnection);
63



1
    ASSERT_EQ(SQLITE_OK, result);
64
65
2
    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
}
76
77


802
TEST(SqliteConnectionTest, internalConstructor)
78
{
79
1
    sqlite3* internalConnection = nullptr;
80
1
    int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection);
81



1
    ASSERT_EQ(SQLITE_OK, result);
82
83
2
    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
}
92
93


802
TEST(SqliteConnectionTest, defaultInternalConstructor)
94
{
95
1
    sqlite3* internalConnection = nullptr;
96
1
    int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection);
97



1
    ASSERT_EQ(SQLITE_OK, result);
98
99
2
    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
}
108
109


802
TEST(SqliteConnectionTest, resetExternal)
110
{
111
1
    sqlite3 *externalConnection = nullptr;
112
1
    int result = sqlite3_open(SQLITE3_MEM_DB, &externalConnection);
113



1
    ASSERT_EQ(SQLITE_OK, result);
114
115
2
    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
}
128
129


802
TEST(SqliteConnectionTest, resetInternal)
130
{
131
1
    sqlite3* internalConnection = nullptr;
132
1
    int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection);
133



1
    ASSERT_EQ(SQLITE_OK, result);
134
135
2
    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
}
145
146


802
TEST(SqliteConnectionTest, resetDefaultInternal)
147
{
148
1
    sqlite3* internalConnection = nullptr;
149
1
    int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection);
150



1
    ASSERT_EQ(SQLITE_OK, result);
151
152
2
    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
}
162
163


802
TEST(SqliteConnectionTest, doubleResetExternal)
164
{
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
    {
174
2
        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
    } // 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
}
192
193


802
TEST(SqliteConnectionTest, doubleResetInternal)
194
{
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
    {
204
2
        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
    } // db dtor
213
214



1
    ASSERT_EQ(SQLITE_OK, sqlite3_shutdown());
215
}
216
217


802
TEST(SqliteConnectionTest, getConnection)
218
{
219
1
    sqlite3 *internalConnection = nullptr;
220
1
    int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection);
221



1
    ASSERT_EQ(SQLITE_OK, result);
222
223
2
    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
}
231
232


802
TEST(SqliteConnectionTest, getConnectionType)
233
{
234
1
    sqlite3 *internalConnection = nullptr;
235
1
    int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection);
236



1
    ASSERT_EQ(SQLITE_OK, result);
237
238
2
    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
}
251
252


802
TEST(SqliteConnectionTest, reset)
253
{
254
1
    sqlite3 *internalConnection = nullptr;
255
1
    int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection);
256



1
    ASSERT_EQ(SQLITE_OK, result);
257
258
2
    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
}
267
268


802
TEST(SqliteConnectionTest, executeUpdate)
269
{
270
1
    sqlite3 *internalConnection = nullptr;
271
1
    int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection);
272



1
    ASSERT_EQ(SQLITE_OK, result);
273
274
2
    SqliteConnection db(internalConnection);
275
276

2
    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
2
    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
}
293
294


802
TEST(SqliteConnectionTest, executeUpdateOnReadOnlyDatabase)
295
{
296
1
    sqlite3 *internalConnection = nullptr;
297
1
    int result = sqlite3_open_v2(SQLITE3_MEM_DB, &internalConnection, SQLITE_OPEN_READONLY, nullptr);
298
2
    SqliteConnection db(internalConnection);
299



1
    ASSERT_EQ(SQLITE_OK, result);
300










2
    ASSERT_THROW(db.executeUpdate("CREATE TABLE Foo AS SELECT 1"), SqliteException);
301
}
302
303


802
TEST(SqliteConnectionTest, prepareStatement)
304
{
305
1
    sqlite3 *internalConnection = nullptr;
306
1
    int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection);
307



1
    ASSERT_EQ(SQLITE_OK, result);
308
309
2
    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

2
    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










2
    ASSERT_THROW(db.prepareStatement("SOME RUBBISH"), SqliteException);
329
330
1
    db.reset();
331
332




1
    ASSERT_EQ(SQLITE_OK, sqlite3_shutdown());
333
}
334
335


802
TEST(SqliteConnectionTest, startEndTransaction)
336
{
337
1
    sqlite3 *internalConnection = nullptr;
338
1
    int result = sqlite3_open(SQLITE3_MEM_DB, &internalConnection);
339



1
    ASSERT_EQ(SQLITE_OK, result);
340
341
2
    SqliteConnection db(internalConnection);
342
343
1
    const bool wasTransactionStarted = db.startTransaction();
344

2
    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
2
    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
}
366
367

2394
} // namespace zserio