From b913932be243893f4620d4a0e1de27451c136062 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Rombauts?= Date: Tue, 28 Jun 2016 13:17:33 +0200 Subject: [PATCH] Add a unit test for transactions + a few small minor new assert in other tests --- CMakeLists.txt | 1 + examples/example1/main.cpp | 2 +- include/SQLiteCpp/Database.h | 2 +- tests/Column_test.cpp | 5 ++- tests/Statement_test.cpp | 2 + tests/Transaction_test.cpp | 77 ++++++++++++++++++++++++++++++++++++ 6 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 tests/Transaction_test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 38a2872..f8973e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,6 +120,7 @@ set(SQLITECPP_TESTS tests/Database_test.cpp tests/Statement_test.cpp tests/Backup_test.cpp + tests/Transaction_test.cpp tests/VariadicBind_test.cpp ) source_group(tests FILES ${SQLITECPP_TESTS}) diff --git a/examples/example1/main.cpp b/examples/example1/main.cpp index 9cd38cf..15abe75 100644 --- a/examples/example1/main.cpp +++ b/examples/example1/main.cpp @@ -357,7 +357,7 @@ int main () nb = db.exec("INSERT INTO test ObviousError"); std::cout << "INSERT INTO test \"error\", returned " << nb << std::endl; - return EXIT_FAILURE; // unexpected success : exit the example program + return EXIT_FAILURE; // we should never get there : exit the example program // Commit transaction transaction.commit(); diff --git a/include/SQLiteCpp/Database.h b/include/SQLiteCpp/Database.h index b82ccc6..5a8d6b6 100644 --- a/include/SQLiteCpp/Database.h +++ b/include/SQLiteCpp/Database.h @@ -100,7 +100,7 @@ public: /** * @brief Set a busy handler that sleeps for a specified amount of time when a table is locked. * - * This is usefull in multithreaded program to handle case where a table is locked for writting by a thread. + * This is useful in multithreaded program to handle case where a table is locked for writing by a thread. * Any other thread cannot access the table and will receive a SQLITE_BUSY error: * setting a timeout will wait and retry up to the time specified before returning this SQLITE_BUSY error. * Reading the value of timeout for current connection can be done with SQL query "PRAGMA busy_timeout;". diff --git a/tests/Column_test.cpp b/tests/Column_test.cpp index 95501b4..920d51f 100644 --- a/tests/Column_test.cpp +++ b/tests/Column_test.cpp @@ -40,10 +40,11 @@ TEST(Column, basis) { insert.bind(1, blob, size); // Execute the one-step query to insert the row EXPECT_EQ(1, insert.exec()); - EXPECT_EQ(1, db.getLastInsertRowid()); EXPECT_EQ(1, db.getTotalChanges()); + EXPECT_THROW(insert.exec(), SQLite::Exception); // exec() shall throw as it needs to be reseted + // Compile a SQL query SQLite::Statement query(db, "SELECT * FROM test"); EXPECT_STREQ("SELECT * FROM test", query.getQuery().c_str()); @@ -166,4 +167,4 @@ TEST(Column, getName) { EXPECT_EQ("id", oname0); EXPECT_EQ("msg", oname1); #endif -} \ No newline at end of file +} diff --git a/tests/Statement_test.cpp b/tests/Statement_test.cpp index f47b4ad..0d70b35 100644 --- a/tests/Statement_test.cpp +++ b/tests/Statement_test.cpp @@ -72,6 +72,8 @@ TEST(Statement, invalid) { EXPECT_THROW(query.isColumnNull(0), SQLite::Exception); EXPECT_THROW(query.getColumn(0), SQLite::Exception); + EXPECT_THROW(query.exec(), SQLite::Exception); // exec() shall throw as it needs to be reseted + // Add a first row EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (NULL, \"first\")")); EXPECT_EQ(1, db.getLastInsertRowid()); diff --git a/tests/Transaction_test.cpp b/tests/Transaction_test.cpp new file mode 100644 index 0000000..ecf9ef4 --- /dev/null +++ b/tests/Transaction_test.cpp @@ -0,0 +1,77 @@ +/** + * @file Transaction_test.cpp + * @ingroup tests + * @brief Test of a SQLite Transaction. + * + * Copyright (c) 2012-2016 Sebastien Rombauts (sebastien.rombauts@gmail.com) + * + * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt + * or copy at http://opensource.org/licenses/MIT) + */ + +#include +#include +#include +#include + +#include + +#include + +TEST(Transaction, commitRollback) { + // Create a new database + SQLite::Database db(":memory:", SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); + EXPECT_EQ(SQLITE_OK, db.getErrorCode()); + + { + // Begin transaction + SQLite::Transaction transaction(db); + + EXPECT_EQ(0, db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)")); + EXPECT_EQ(SQLITE_OK, db.getErrorCode()); + + // Insert a first value + EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (NULL, \"first\")")); + EXPECT_EQ(1, db.getLastInsertRowid()); + + // Commit transaction + transaction.commit(); + + // Commit again throw an exception + EXPECT_THROW(transaction.commit(), SQLite::Exception); + } + + // Auto rollback of a transaction on error + try + { + // Begin transaction + SQLite::Transaction transaction(db); + + // Insert a second value (that will be rollbacked) + EXPECT_EQ(1, db.exec("INSERT INTO test VALUES (NULL, \"second\")")); + EXPECT_EQ(2, db.getLastInsertRowid()); + + // Execute with an error to rollback + db.exec("Obvious syntax error to raise an exception"); + GTEST_FATAL_FAILURE_("we should never get there"); + + // Commit transaction + transaction.commit(); + } + catch (std::exception& e) + { + std::cout << "SQLite exception: " << e.what() << std::endl; + // expected error, see above + } + + // Check the results (expect only one row of result, as the second one has been rollbacked by the error) + SQLite::Statement query(db, "SELECT * FROM test"); + int nbRows = 0; + while (query.executeStep()) + { + nbRows++; + EXPECT_EQ(1, query.getColumn(0).getInt()); + EXPECT_STREQ("first", query.getColumn(1).getText()); + } + EXPECT_EQ(1, nbRows); +}