comparison OrthancFramework/UnitTestsSources/SQLiteChromiumTests.cpp @ 4044:d25f4c0fa160 framework

splitting code into OrthancFramework and OrthancServer
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 10 Jun 2020 20:30:34 +0200
parents UnitTestsSources/SQLiteChromiumTests.cpp@27628b0f6ada
children 05b8fd21089c
comparison
equal deleted inserted replaced
4043:6c6239aec462 4044:d25f4c0fa160
1 /**
2 * Orthanc - A Lightweight, RESTful DICOM Store
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium
6 *
7 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
11 *
12 * In addition, as a special exception, the copyright holders of this
13 * program give permission to link the code of its release with the
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it
15 * that use the same license as the "OpenSSL" library), and distribute
16 * the linked executables. You must obey the GNU General Public License
17 * in all respects for all of the code used other than "OpenSSL". If you
18 * modify file(s) with this exception, you may extend this exception to
19 * your version of the file(s), but you are not obligated to do so. If
20 * you do not wish to do so, delete this exception statement from your
21 * version. If you delete this exception statement from all source files
22 * in the program, then also delete it here.
23 *
24 * This program is distributed in the hope that it will be useful, but
25 * WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31 **/
32
33
34 #if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1
35 # include <OrthancFramework.h>
36 #endif
37
38 #include "PrecompiledHeadersUnitTests.h"
39 #include "gtest/gtest.h"
40
41 #include "../Core/Toolbox.h"
42 #include "../Core/SQLite/Connection.h"
43 #include "../Core/SQLite/Statement.h"
44 #include "../Core/SQLite/Transaction.h"
45
46 #include <sqlite3.h>
47
48
49 using namespace Orthanc;
50 using namespace Orthanc::SQLite;
51
52
53 /********************************************************************
54 ** Tests from
55 ** http://src.chromium.org/viewvc/chrome/trunk/src/sql/connection_unittest.cc
56 ********************************************************************/
57
58 namespace
59 {
60 class SQLConnectionTest : public testing::Test
61 {
62 public:
63 SQLConnectionTest()
64 {
65 }
66
67 virtual ~SQLConnectionTest() ORTHANC_OVERRIDE
68 {
69 }
70
71 virtual void SetUp() ORTHANC_OVERRIDE
72 {
73 db_.OpenInMemory();
74 }
75
76 virtual void TearDown() ORTHANC_OVERRIDE
77 {
78 db_.Close();
79 }
80
81 Connection& db()
82 {
83 return db_;
84 }
85
86 private:
87 Connection db_;
88 };
89 }
90
91
92
93 TEST_F(SQLConnectionTest, Execute)
94 {
95 // Valid statement should return true.
96 ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
97 EXPECT_EQ(SQLITE_OK, db().GetErrorCode());
98
99 // Invalid statement should fail.
100 ASSERT_EQ(SQLITE_ERROR,
101 db().ExecuteAndReturnErrorCode("CREATE TAB foo (a, b"));
102 EXPECT_EQ(SQLITE_ERROR, db().GetErrorCode());
103 }
104
105 TEST_F(SQLConnectionTest, ExecuteWithErrorCode) {
106 ASSERT_EQ(SQLITE_OK,
107 db().ExecuteAndReturnErrorCode("CREATE TABLE foo (a, b)"));
108 ASSERT_EQ(SQLITE_ERROR,
109 db().ExecuteAndReturnErrorCode("CREATE TABLE TABLE"));
110 ASSERT_EQ(SQLITE_ERROR,
111 db().ExecuteAndReturnErrorCode(
112 "INSERT INTO foo(a, b) VALUES (1, 2, 3, 4)"));
113 }
114
115 TEST_F(SQLConnectionTest, CachedStatement) {
116 StatementId id1("foo", 12);
117 ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
118 ASSERT_TRUE(db().Execute("INSERT INTO foo(a, b) VALUES (12, 13)"));
119
120 // Create a new cached statement.
121 {
122 Statement s(db(), id1, "SELECT a FROM foo");
123 ASSERT_TRUE(s.Step());
124 EXPECT_EQ(12, s.ColumnInt(0));
125 }
126
127 // The statement should be cached still.
128 EXPECT_TRUE(db().HasCachedStatement(id1));
129
130 {
131 // Get the same statement using different SQL. This should ignore our
132 // SQL and use the cached one (so it will be valid).
133 Statement s(db(), id1, "something invalid(");
134 ASSERT_TRUE(s.Step());
135 EXPECT_EQ(12, s.ColumnInt(0));
136 }
137
138 // Make sure other statements aren't marked as cached.
139 EXPECT_FALSE(db().HasCachedStatement(SQLITE_FROM_HERE));
140 }
141
142 TEST_F(SQLConnectionTest, IsSQLValidTest) {
143 ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
144 ASSERT_TRUE(db().IsSQLValid("SELECT a FROM foo"));
145 ASSERT_FALSE(db().IsSQLValid("SELECT no_exist FROM foo"));
146 }
147
148
149
150 TEST_F(SQLConnectionTest, DoesStuffExist) {
151 // Test DoesTableExist.
152 EXPECT_FALSE(db().DoesTableExist("foo"));
153 ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
154 EXPECT_TRUE(db().DoesTableExist("foo"));
155
156 // Should be case sensitive.
157 EXPECT_FALSE(db().DoesTableExist("FOO"));
158
159 // Test DoesColumnExist.
160 EXPECT_FALSE(db().DoesColumnExist("foo", "bar"));
161 EXPECT_TRUE(db().DoesColumnExist("foo", "a"));
162
163 // Testing for a column on a nonexistent table.
164 EXPECT_FALSE(db().DoesColumnExist("bar", "b"));
165 }
166
167 TEST_F(SQLConnectionTest, GetLastInsertRowId) {
168 ASSERT_TRUE(db().Execute("CREATE TABLE foo (id INTEGER PRIMARY KEY, value)"));
169
170 ASSERT_TRUE(db().Execute("INSERT INTO foo (value) VALUES (12)"));
171
172 // Last insert row ID should be valid.
173 int64_t row = db().GetLastInsertRowId();
174 EXPECT_LT(0, row);
175
176 // It should be the primary key of the row we just inserted.
177 Statement s(db(), "SELECT value FROM foo WHERE id=?");
178 s.BindInt64(0, row);
179 ASSERT_TRUE(s.Step());
180 EXPECT_EQ(12, s.ColumnInt(0));
181 }
182
183 TEST_F(SQLConnectionTest, Rollback) {
184 ASSERT_TRUE(db().BeginTransaction());
185 ASSERT_TRUE(db().BeginTransaction());
186 EXPECT_EQ(2, db().GetTransactionNesting());
187 db().RollbackTransaction();
188 EXPECT_FALSE(db().CommitTransaction());
189 EXPECT_TRUE(db().BeginTransaction());
190 }
191
192
193
194
195 /********************************************************************
196 ** Tests from
197 ** http://src.chromium.org/viewvc/chrome/trunk/src/sql/statement_unittest.cc
198 ********************************************************************/
199
200 namespace Orthanc
201 {
202 namespace SQLite
203 {
204 class SQLStatementTest : public SQLConnectionTest
205 {
206 };
207
208 TEST_F(SQLStatementTest, Run) {
209 ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
210 ASSERT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (3, 12)"));
211
212 Statement s(db(), "SELECT b FROM foo WHERE a=?");
213 // Stepping it won't work since we haven't bound the value.
214 EXPECT_FALSE(s.Step());
215
216 // Run should fail since this produces output, and we should use Step(). This
217 // gets a bit wonky since sqlite says this is OK so succeeded is set.
218 s.Reset(true);
219 s.BindInt(0, 3);
220 EXPECT_FALSE(s.Run());
221 EXPECT_EQ(SQLITE_ROW, db().GetErrorCode());
222
223 // Resetting it should put it back to the previous state (not runnable).
224 s.Reset(true);
225
226 // Binding and stepping should produce one row.
227 s.BindInt(0, 3);
228 EXPECT_TRUE(s.Step());
229 EXPECT_EQ(12, s.ColumnInt(0));
230 EXPECT_FALSE(s.Step());
231 }
232
233 TEST_F(SQLStatementTest, BasicErrorCallback) {
234 ASSERT_TRUE(db().Execute("CREATE TABLE foo (a INTEGER PRIMARY KEY, b)"));
235 // Insert in the foo table the primary key. It is an error to insert
236 // something other than an number. This error causes the error callback
237 // handler to be called with SQLITE_MISMATCH as error code.
238 Statement s(db(), "INSERT INTO foo (a) VALUES (?)");
239 s.BindCString(0, "bad bad");
240 EXPECT_THROW(s.Run(), OrthancException);
241 }
242
243 TEST_F(SQLStatementTest, Reset) {
244 ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
245 ASSERT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (3, 12)"));
246 ASSERT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (4, 13)"));
247
248 Statement s(db(), "SELECT b FROM foo WHERE a = ? ");
249 s.BindInt(0, 3);
250 ASSERT_TRUE(s.Step());
251 EXPECT_EQ(12, s.ColumnInt(0));
252 ASSERT_FALSE(s.Step());
253
254 s.Reset(false);
255 // Verify that we can get all rows again.
256 ASSERT_TRUE(s.Step());
257 EXPECT_EQ(12, s.ColumnInt(0));
258 EXPECT_FALSE(s.Step());
259
260 s.Reset(true);
261 ASSERT_FALSE(s.Step());
262 }
263 }
264 }
265
266
267
268
269
270
271 /********************************************************************
272 ** Tests from
273 ** http://src.chromium.org/viewvc/chrome/trunk/src/sql/transaction_unittest.cc
274 ********************************************************************/
275
276 namespace
277 {
278 class SQLTransactionTest : public SQLConnectionTest
279 {
280 public:
281 virtual void SetUp() ORTHANC_OVERRIDE
282 {
283 SQLConnectionTest::SetUp();
284 ASSERT_TRUE(db().Execute("CREATE TABLE foo (a, b)"));
285 }
286
287 // Returns the number of rows in table "foo".
288 int CountFoo()
289 {
290 Statement count(db(), "SELECT count(*) FROM foo");
291 count.Step();
292 return count.ColumnInt(0);
293 }
294 };
295 }
296
297
298 TEST_F(SQLTransactionTest, Commit) {
299 {
300 Transaction t(db());
301 EXPECT_FALSE(t.IsOpen());
302 t.Begin();
303 EXPECT_TRUE(t.IsOpen());
304
305 EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)"));
306
307 t.Commit();
308 EXPECT_FALSE(t.IsOpen());
309 }
310
311 EXPECT_EQ(1, CountFoo());
312 }
313
314 TEST_F(SQLTransactionTest, Rollback) {
315 // Test some basic initialization, and that rollback runs when you exit the
316 // scope.
317 {
318 Transaction t(db());
319 EXPECT_FALSE(t.IsOpen());
320 t.Begin();
321 EXPECT_TRUE(t.IsOpen());
322
323 EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)"));
324 }
325
326 // Nothing should have been committed since it was implicitly rolled back.
327 EXPECT_EQ(0, CountFoo());
328
329 // Test explicit rollback.
330 Transaction t2(db());
331 EXPECT_FALSE(t2.IsOpen());
332 t2.Begin();
333
334 EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)"));
335 t2.Rollback();
336 EXPECT_FALSE(t2.IsOpen());
337
338 // Nothing should have been committed since it was explicitly rolled back.
339 EXPECT_EQ(0, CountFoo());
340 }
341
342 // Rolling back any part of a transaction should roll back all of them.
343 TEST_F(SQLTransactionTest, NestedRollback) {
344 EXPECT_EQ(0, db().GetTransactionNesting());
345
346 // Outermost transaction.
347 {
348 Transaction outer(db());
349 outer.Begin();
350 EXPECT_EQ(1, db().GetTransactionNesting());
351
352 // The first inner one gets committed.
353 {
354 Transaction inner1(db());
355 inner1.Begin();
356 EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)"));
357 EXPECT_EQ(2, db().GetTransactionNesting());
358
359 inner1.Commit();
360 EXPECT_EQ(1, db().GetTransactionNesting());
361 }
362
363 // One row should have gotten inserted.
364 EXPECT_EQ(1, CountFoo());
365
366 // The second inner one gets rolled back.
367 {
368 Transaction inner2(db());
369 inner2.Begin();
370 EXPECT_TRUE(db().Execute("INSERT INTO foo (a, b) VALUES (1, 2)"));
371 EXPECT_EQ(2, db().GetTransactionNesting());
372
373 inner2.Rollback();
374 EXPECT_EQ(1, db().GetTransactionNesting());
375 }
376
377 // A third inner one will fail in Begin since one has already been rolled
378 // back.
379 EXPECT_EQ(1, db().GetTransactionNesting());
380 {
381 Transaction inner3(db());
382 EXPECT_THROW(inner3.Begin(), OrthancException);
383 EXPECT_EQ(1, db().GetTransactionNesting());
384 }
385 }
386 EXPECT_EQ(0, db().GetTransactionNesting());
387 EXPECT_EQ(0, CountFoo());
388 }