From c06db7f48b19f22d3d1d1a62dd2b14c3cee1cc25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Rombauts?= Date: Sat, 4 Jan 2020 17:34:58 +0100 Subject: [PATCH 1/5] editorconfig: only 2 space indentation for YAML CI configuration files --- .editorconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index eb476d6..1fab733 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,4 +11,4 @@ end_of_line = lf # 2 space indentation for CI configuration [*.yml] indent_style = space -indent_size = 4 +indent_size = 2 From 5a1fa743e54055ea07491ec34067d3e811aea36f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Rombauts?= Date: Sat, 4 Jan 2020 17:35:31 +0100 Subject: [PATCH 2/5] Add Valgrind to Travis CI, and improve the build Matrix with more variables Should detect the slight bug we currently have in our test of Database read header --- .travis.yml | 68 +++++++++++++++++++++++++++++++------------------- CHANGELOG.md | 14 ++++++----- CMakeLists.txt | 14 +++++------ README.md | 1 + TODO.txt | 2 -- build.sh | 2 +- 6 files changed, 59 insertions(+), 42 deletions(-) diff --git a/.travis.yml b/.travis.yml index 538d312..ded0ec6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,25 +16,38 @@ matrix: # GCC on Linux ########################################################################## + # GCC Debug build with GCov for coverage build - dist: bionic env: - - cc=gcc - - cxx=g++ - - CXXFLAGS="" + - cc=gcc cxx=g++ + - BUILD_TYPE=Debug + - ASAN=ON GCOV=ON - COVERALLS=true - + + # GCC Debug build with Valgrind instead of Address Sanitizer + - dist: bionic + env: + - cc=gcc cxx=g++ + - BUILD_TYPE=Debug + - VALGRIND=true + + # GCC Release build + - dist: bionic + env: + - cc=gcc cxx=g++ + - BUILD_TYPE=Release - dist: xenial env: - - cc=gcc - - cxx=g++ - - CXXFLAGS="" + - cc=gcc cxx=g++ + - BUILD_TYPE=Debug + - ASAN=ON - dist: trusty env: - - cc=gcc - - cxx=g++ - - CXXFLAGS="" + - cc=gcc cxx=g++ + - BUILD_TYPE=Debug + - ASAN=ON ########################################################################## # Clang on Linux @@ -42,21 +55,21 @@ matrix: - dist: bionic env: - - cc=clang - - cxx=clang++ - - CXXFLAGS="" + - cc=clang cxx=clang++ + - BUILD_TYPE=Debug + - ASAN=ON - dist: xenial env: - - cc=clang - - cxx=clang++ - - CXXFLAGS="" + - cc=clang cxx=clang++ + - BUILD_TYPE=Debug + - ASAN=ON - dist: trusty env: - - cc=clang - - cxx=clang++ - - CXXFLAGS="" + - cc=clang cxx=clang++ + - BUILD_TYPE=Debug + - ASAN=ON ########################################################################## # Clang on OSX @@ -65,17 +78,17 @@ matrix: # Latest XCode - os: osx env: - - cc=clang - - cxx=clang++ - - CXXFLAGS="" + - cc=clang cxx=clang++ + - BUILD_TYPE=Debug + - ASAN=ON # XCode 8.3 - os: osx osx_image: xcode8.3 env: - - cc=clang - - cxx=clang++ - - CXXFLAGS="" + - cc=clang cxx=clang++ + - BUILD_TYPE=Debug + - ASAN=ON before_install: # Set the compiler environment variables properly @@ -83,6 +96,7 @@ before_install: - export CXX=${cxx} - ${CC} --version - ${CXX} --version + - if [[ "$VALGRIND" == "true" ]]; then sudo apt-get install -qq valgrind ; fi install: # coveralls test coverage: @@ -92,13 +106,15 @@ install: before_script: - mkdir build - cd build - - cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_BUILD_TYPE=Debug -DSQLITECPP_USE_ASAN=ON -DSQLITECPP_USE_GCOV=ON -DSQLITECPP_BUILD_EXAMPLES=ON -DSQLITECPP_BUILD_TESTS=ON .. + - cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSQLITECPP_USE_ASAN=$ASAN -DSQLITECPP_USE_GCOV=$GCOV -DSQLITECPP_BUILD_EXAMPLES=ON -DSQLITECPP_BUILD_TESTS=ON .. # build examples, and run tests (ie make & make test) script: - cmake --build . - export ASAN_OPTIONS=verbosity=1:debug=1 - ctest --verbose --output-on-failure + - if [[ "$VALGRIND" == "true" ]]; then valgrind --leak-check=full --error-exitcode=1 ./SQLiteCpp_example1 ; fi + - if [[ "$VALGRIND" == "true" ]]; then valgrind --leak-check=full --error-exitcode=1 ./SQLiteCpp_tests ; fi # generate and publish GCov coveralls results after_success: diff --git a/CHANGELOG.md b/CHANGELOG.md index a45b6d9..71c59e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,12 @@ Mar 30 2012 - Start of a new thin C++ SQLite wrapper Apr 2 2012 -- The wrapper is functionnal +- The wrapper is functional - Added documentation and examples - Publication on GitHub Version 0.1.0 - Apr 4 2012 -- Added a Database::exec() methode to execute simple SQL statement +- Added a Database::exec() method to execute simple SQL statement - Added a version number like in sqlite3.h, starting with 0.1.0 Version 0.2.0 - Apr 11 2012 @@ -75,7 +75,7 @@ Version 1.3.0 - November 1 2015 - Added Backup class Version 1.3.1 - February 10 2016 -- Swith Linux/Mac build to the provided SQLite3 C library +- Switch Linux/Mac build to the provided SQLite3 C library - Update SQLite3 from 3.8.8.3 to latest 3.10.2 (2016-01-20) - Remove warnings - Remove biicode support (defunct service, servers will shutdown the 16th of February 2016) @@ -157,9 +157,11 @@ Version 2.5.0 - December 31 2019 - #251 Added example for getHeaderInfo() Version 3.0.0 - January 1 2020 -- C++11 minimum +- C++11 is now required - CMake 3.1 minimum - Visual Studio 2015 minimum -- Googletest 1.10 -- Remove Statement::isOk() deprecated in 2.2.0 when renamed to Statement::hasRow() +- Update Googletest to latest release 1.10 +- Add Github Actions continuous integration solution +- Add Valgrind memcheck tool to Travis CI +- Remove Statement::isOk() deprecated in 2.2.0 when renamed to Statement::hasRow() - Replace Database::backup() "C" implementation by calling the Backup class diff --git a/CMakeLists.txt b/CMakeLists.txt index 32e2a96..ef437a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,14 +43,14 @@ else (MSVC) set(CPPLINT_ARG_OUTPUT "--output=eclipse") set(CPPCHECK_ARG_TEMPLATE "--template=gcc") # Useful compile flags and extra warnings - add_compile_options(-fstack-protector -Wall -Wextra -Wpedantic -Wno-long-long -Wswitch-enum -Wshadow -Winline) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-c++0x-compat") # C++ only + add_compile_options(-fstack-protector) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -Wswitch-enum -Wshadow -Wno-long-long") # C++ only, don't bother with sqlite3 if (CMAKE_COMPILER_IS_GNUCXX) # GCC flags option(SQLITECPP_USE_GCOV "USE GCov instrumentation." OFF) if (SQLITECPP_USE_GCOV) message (STATUS "Using GCov instrumentation") - add_compile_options (-coverage) # NOTE -fkeep-inline-functions would be usefull but not working with current google test and gcc 4.8 + add_compile_options (-coverage) # NOTE -fkeep-inline-functions would be useful but not working with current Google test and GCC 4.8 set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -coverage") endif () endif (CMAKE_COMPILER_IS_GNUCXX) @@ -83,7 +83,7 @@ endif () ## Build the C++ Wrapper ## -# adding a new file require explicittly modifing the CMakeLists.txt +# adding a new file require explicitly modifying the CMakeLists.txt # so that CMake knows that it should rebuild the project (it is best practice) # list of sources files of the library @@ -307,7 +307,7 @@ if (SQLITECPP_BUILD_EXAMPLES) # add the basic example executable add_executable(SQLiteCpp_example1 ${SQLITECPP_EXAMPLES}) target_link_libraries(SQLiteCpp_example1 SQLiteCpp sqlite3) - # Link target with pthread and dl for linux + # Link target with pthread and dl for Linux if (UNIX) target_link_libraries(SQLiteCpp_example1 pthread) if (NOT APPLE) @@ -329,12 +329,12 @@ if (SQLITECPP_BUILD_TESTS) if (GTEST_FOUND) target_link_libraries(SQLiteCpp_tests GTest::GTest GTest::Main SQLiteCpp sqlite3) else (GTEST_FOUND) - # deactivate some warnings for compiling the gtest library + # deactivate some warnings for compiling the googletest library if (NOT MSVC) add_compile_options(-Wno-variadic-macros -Wno-long-long -Wno-switch-enum -Wno-float-equal -Wno-conversion-null -Wno-switch-default -Wno-pedantic) endif (NOT MSVC) - # add the subdirectory containing the CMakeLists.txt for the gtest library + # add the subdirectory containing the CMakeLists.txt for the googletest library if (NOT EXISTS "${PROJECT_SOURCE_DIR}/googletest/CMakeLists.txt") message(FATAL_ERROR "Missing 'googletest' submodule! Either use 'git submodule init' and 'git submodule update' to get googletest according to the README, or deactivate unit tests with -DSQLITECPP_BUILD_TESTS=OFF") endif () diff --git a/README.md b/README.md index dd2f64a..e768791 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ Developments and tests are done under the following OSs: - Windows 10, and Windows Server 2012 R2 & Windows Server 2016 (AppVeyor) - OS X 10.11 (Travis CI) - Github Actions +- Valgrind memcheck tool And the following IDEs/Compilers - GCC 4.8.4, 5.3.0 and 7.1.1 (C++11, C++14, C++17) diff --git a/TODO.txt b/TODO.txt index 6af0968..fa9a19d 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,5 +1,3 @@ -Switch to C++11 for v3.0.0 - Add a Tutorial for SQLite newbies Add a real example in the form of a small interactive console application diff --git a/build.sh b/build.sh index 72c265d..6043c3b 100755 --- a/build.sh +++ b/build.sh @@ -4,7 +4,7 @@ # Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt # or copy at http://opensource.org/licenses/MIT) -# exit on firts error +# exit on first error set -e mkdir -p build From 55de873f660b725470340ad737aec1340fcf6a26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Rombauts?= Date: Sat, 4 Jan 2020 18:54:27 +0100 Subject: [PATCH 3/5] Fix Database::getHeaderInfo() for case where the file is not even 100 bytes long --- src/Database.cpp | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/Database.cpp b/src/Database.cpp index 5f6f5b4..48248a1 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -287,28 +287,32 @@ Header Database::getHeaderInfo(const std::string& aFilename) if (aFilename.empty()) { - throw SQLite::Exception("Could not open database, the aFilename parameter was empty."); + throw SQLite::Exception("Filename parameter is empty"); } - std::ifstream fileBuffer(aFilename.c_str(), std::ios::in | std::ios::binary); - - if (fileBuffer.is_open()) { - fileBuffer.seekg(0, std::ios::beg); - fileBuffer.read(pBuf, 100); - fileBuffer.close(); - strncpy(pHeaderStr, pBuf, 16); - } - - else - { - throw SQLite::Exception("Error opening file: " + aFilename); + std::ifstream fileBuffer(aFilename.c_str(), std::ios::in | std::ios::binary); + if (fileBuffer.is_open()) + { + fileBuffer.seekg(0, std::ios::beg); + fileBuffer.read(pBuf, 100); + fileBuffer.close(); + if (fileBuffer.gcount() < 100) + { + throw SQLite::Exception("File " + aFilename + " is too short"); + } + } + else + { + throw SQLite::Exception("Error opening file " + aFilename); + } } // If the "magic string" can't be found then header is invalid, corrupt or unreadable + strncpy(pHeaderStr, pBuf, 16); if (!strncmp(pHeaderStr, "SQLite format 3", 15) == 0) { - throw SQLite::Exception("Invalid or encrypted SQLite header"); + throw SQLite::Exception("Invalid or encrypted SQLite header in file " + aFilename); } h.pageSizeBytes = (buf[16] << 8) | buf[17]; From ddb4929ddb8ba8544a2eb860598291431b7c40b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Rombauts?= Date: Sat, 4 Jan 2020 19:10:23 +0100 Subject: [PATCH 4/5] Fix and improve read-header unit tests, as well as backup tests --- tests/Backup_test.cpp | 130 +++++++++++++++++++++------------------- tests/Database_test.cpp | 51 +++++++++++----- 2 files changed, 104 insertions(+), 77 deletions(-) diff --git a/tests/Backup_test.cpp b/tests/Backup_test.cpp index 9770895..1b28542 100644 --- a/tests/Backup_test.cpp +++ b/tests/Backup_test.cpp @@ -24,14 +24,16 @@ TEST(Backup, initException) { remove("backup_test.db3"); - SQLite::Database srcDB("backup_test.db3", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE); - srcDB.exec("CREATE TABLE backup_test (id INTEGER PRIMARY KEY, value TEXT)"); - ASSERT_EQ(1, srcDB.exec("INSERT INTO backup_test VALUES (1, \"first\")")); - ASSERT_EQ(1, srcDB.exec("INSERT INTO backup_test VALUES (2, \"second\")")); - EXPECT_THROW(SQLite::Backup backup(srcDB, srcDB), SQLite::Exception); - EXPECT_THROW(SQLite::Backup backup(srcDB, "main", srcDB, "main"), SQLite::Exception); - const std::string name("main"); - EXPECT_THROW(SQLite::Backup backup(srcDB, name, srcDB, name), SQLite::Exception); + { + SQLite::Database srcDB("backup_test.db3", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE); + srcDB.exec("CREATE TABLE backup_test (id INTEGER PRIMARY KEY, value TEXT)"); + ASSERT_EQ(1, srcDB.exec("INSERT INTO backup_test VALUES (1, \"first\")")); + ASSERT_EQ(1, srcDB.exec("INSERT INTO backup_test VALUES (2, \"second\")")); + EXPECT_THROW(SQLite::Backup backup(srcDB, srcDB), SQLite::Exception); + EXPECT_THROW(SQLite::Backup backup(srcDB, "main", srcDB, "main"), SQLite::Exception); + const std::string name("main"); + EXPECT_THROW(SQLite::Backup backup(srcDB, name, srcDB, name), SQLite::Exception); + } remove("backup_test.db3"); } @@ -39,31 +41,33 @@ TEST(Backup, executeStepOne) { remove("backup_test.db3"); remove("backup_test.db3.backup"); - SQLite::Database srcDB("backup_test.db3", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE); - srcDB.exec("CREATE TABLE backup_test (id INTEGER PRIMARY KEY, value TEXT)"); - ASSERT_EQ(1, srcDB.exec("INSERT INTO backup_test VALUES (1, \"first\")")); - ASSERT_EQ(1, srcDB.exec("INSERT INTO backup_test VALUES (2, \"second\")")); + { + SQLite::Database srcDB("backup_test.db3", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE); + srcDB.exec("CREATE TABLE backup_test (id INTEGER PRIMARY KEY, value TEXT)"); + ASSERT_EQ(1, srcDB.exec("INSERT INTO backup_test VALUES (1, \"first\")")); + ASSERT_EQ(1, srcDB.exec("INSERT INTO backup_test VALUES (2, \"second\")")); - SQLite::Database destDB("backup_test.db3.backup", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE); - SQLite::Backup backup(destDB, "main", srcDB, "main"); - int res = backup.executeStep(1); // backup only one page at a time - ASSERT_EQ(SQLite::OK, res); - const int total = backup.getTotalPageCount(); - ASSERT_EQ(2, total); - int remaining = backup.getRemainingPageCount(); - ASSERT_EQ(1, remaining); - res = backup.executeStep(1); // backup the second and last page - ASSERT_EQ(SQLITE_DONE, res); - remaining = backup.getRemainingPageCount(); - ASSERT_EQ(0, remaining); + SQLite::Database destDB("backup_test.db3.backup", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE); + SQLite::Backup backup(destDB, "main", srcDB, "main"); + int res = backup.executeStep(1); // backup only one page at a time + ASSERT_EQ(SQLite::OK, res); + const int total = backup.getTotalPageCount(); + ASSERT_EQ(2, total); + int remaining = backup.getRemainingPageCount(); + ASSERT_EQ(1, remaining); + res = backup.executeStep(1); // backup the second and last page + ASSERT_EQ(SQLITE_DONE, res); + remaining = backup.getRemainingPageCount(); + ASSERT_EQ(0, remaining); - SQLite::Statement query(destDB, "SELECT * FROM backup_test ORDER BY id ASC"); - ASSERT_TRUE(query.executeStep()); - EXPECT_EQ(1, query.getColumn(0).getInt()); - EXPECT_STREQ("first", query.getColumn(1)); - ASSERT_TRUE(query.executeStep()); - EXPECT_EQ(2, query.getColumn(0).getInt()); - EXPECT_STREQ("second", query.getColumn(1)); + SQLite::Statement query(destDB, "SELECT * FROM backup_test ORDER BY id ASC"); + ASSERT_TRUE(query.executeStep()); + EXPECT_EQ(1, query.getColumn(0).getInt()); + EXPECT_STREQ("first", query.getColumn(1)); + ASSERT_TRUE(query.executeStep()); + EXPECT_EQ(2, query.getColumn(0).getInt()); + EXPECT_STREQ("second", query.getColumn(1)); + } remove("backup_test.db3"); remove("backup_test.db3.backup"); } @@ -72,27 +76,29 @@ TEST(Backup, executeStepAll) { remove("backup_test.db3"); remove("backup_test.db3.backup"); - SQLite::Database srcDB("backup_test.db3", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE); - srcDB.exec("CREATE TABLE backup_test (id INTEGER PRIMARY KEY, value TEXT)"); - ASSERT_EQ(1, srcDB.exec("INSERT INTO backup_test VALUES (1, \"first\")")); - ASSERT_EQ(1, srcDB.exec("INSERT INTO backup_test VALUES (2, \"second\")")); + { + SQLite::Database srcDB("backup_test.db3", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE); + srcDB.exec("CREATE TABLE backup_test (id INTEGER PRIMARY KEY, value TEXT)"); + ASSERT_EQ(1, srcDB.exec("INSERT INTO backup_test VALUES (1, \"first\")")); + ASSERT_EQ(1, srcDB.exec("INSERT INTO backup_test VALUES (2, \"second\")")); - SQLite::Database destDB("backup_test.db3.backup", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE); - SQLite::Backup backup(destDB, srcDB); - const int res = backup.executeStep(); // uses default argument "-1" => execute all steps at once - ASSERT_EQ(res, SQLITE_DONE); - const int total = backup.getTotalPageCount(); - ASSERT_EQ(2, total); - const int remaining = backup.getRemainingPageCount(); - ASSERT_EQ(0, remaining); + SQLite::Database destDB("backup_test.db3.backup", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE); + SQLite::Backup backup(destDB, srcDB); + const int res = backup.executeStep(); // uses default argument "-1" => execute all steps at once + ASSERT_EQ(res, SQLITE_DONE); + const int total = backup.getTotalPageCount(); + ASSERT_EQ(2, total); + const int remaining = backup.getRemainingPageCount(); + ASSERT_EQ(0, remaining); - SQLite::Statement query(destDB, "SELECT * FROM backup_test ORDER BY id ASC"); - ASSERT_TRUE(query.executeStep()); - EXPECT_EQ(1, query.getColumn(0).getInt()); - EXPECT_STREQ("first", query.getColumn(1)); - ASSERT_TRUE(query.executeStep()); - EXPECT_EQ(2, query.getColumn(0).getInt()); - EXPECT_STREQ("second", query.getColumn(1)); + SQLite::Statement query(destDB, "SELECT * FROM backup_test ORDER BY id ASC"); + ASSERT_TRUE(query.executeStep()); + EXPECT_EQ(1, query.getColumn(0).getInt()); + EXPECT_STREQ("first", query.getColumn(1)); + ASSERT_TRUE(query.executeStep()); + EXPECT_EQ(2, query.getColumn(0).getInt()); + EXPECT_STREQ("second", query.getColumn(1)); + } remove("backup_test.db3"); remove("backup_test.db3.backup"); } @@ -101,18 +107,20 @@ TEST(Backup, executeStepException) { remove("backup_test.db3"); remove("backup_test.db3.backup"); - SQLite::Database srcDB("backup_test.db3", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE); - srcDB.exec("CREATE TABLE backup_test (id INTEGER PRIMARY KEY, value TEXT)"); - ASSERT_EQ(1, srcDB.exec("INSERT INTO backup_test VALUES (1, \"first\")")); - ASSERT_EQ(1, srcDB.exec("INSERT INTO backup_test VALUES (2, \"second\")")); { - SQLite::Database destDB("backup_test.db3.backup", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE); - (void)destDB; - } - { - SQLite::Database destDB("backup_test.db3.backup", SQLite::OPEN_READONLY); - SQLite::Backup backup(destDB, srcDB); - EXPECT_THROW(backup.executeStep(), SQLite::Exception); + SQLite::Database srcDB("backup_test.db3", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE); + srcDB.exec("CREATE TABLE backup_test (id INTEGER PRIMARY KEY, value TEXT)"); + ASSERT_EQ(1, srcDB.exec("INSERT INTO backup_test VALUES (1, \"first\")")); + ASSERT_EQ(1, srcDB.exec("INSERT INTO backup_test VALUES (2, \"second\")")); + { + SQLite::Database destDB("backup_test.db3.backup", SQLite::OPEN_READWRITE|SQLite::OPEN_CREATE); + (void)destDB; + } + { + SQLite::Database destDB("backup_test.db3.backup", SQLite::OPEN_READONLY); + SQLite::Backup backup(destDB, srcDB); + EXPECT_THROW(backup.executeStep(), SQLite::Exception); + } } remove("backup_test.db3"); remove("backup_test.db3.backup"); diff --git a/tests/Database_test.cpp b/tests/Database_test.cpp index 102fac6..93dc205 100644 --- a/tests/Database_test.cpp +++ b/tests/Database_test.cpp @@ -140,15 +140,16 @@ TEST(Database, backup) EXPECT_TRUE(db.tableExists("test")); // Export the data into a file - remove("backup"); - EXPECT_NO_THROW(db.backup("backup", SQLite::Database::Save)); + remove("backup.db3"); + EXPECT_NO_THROW(db.backup("backup.db3", SQLite::Database::Save)); // Trash the table db.exec("DROP TABLE test;"); EXPECT_FALSE(db.tableExists("test")); // Import the data back from the file - EXPECT_NO_THROW(db.backup("backup", SQLite::Database::Load)); + EXPECT_NO_THROW(db.backup("backup.db3", SQLite::Database::Load)); + remove("backup.db3"); EXPECT_TRUE(db.tableExists("test")); } @@ -359,28 +360,46 @@ TEST(Database, getHeaderInfo) { remove("test.db3"); { - //Call without passing a database file name + // Call without passing a database file name EXPECT_THROW(SQLite::Database::getHeaderInfo(""),SQLite::Exception); - //Call with a non existant database + // Call with a non-existent database EXPECT_THROW(SQLite::Database::getHeaderInfo("test.db3"), SQLite::Exception); - //Simulate a corrupt header by writing garbage to a file - unsigned char badData[100]; - char* pBadData = reinterpret_cast(&badData[0]); + // Simulate an incomplete header by writing garbage to a file + { + const unsigned char badData[] = "garbage..."; + const char* pBadData = reinterpret_cast(&badData[0]); - std::ofstream corruptDb; - corruptDb.open("corrupt.db3", std::ios::app | std::ios::binary); - corruptDb.write(pBadData, 100); + remove("short.db3"); + std::ofstream corruptDb; + corruptDb.open("short.db3", std::ios::app | std::ios::binary); + corruptDb.write(pBadData, sizeof(badData)); + corruptDb.close(); - EXPECT_THROW(SQLite::Database::getHeaderInfo("corrupt.db3"), SQLite::Exception); - - remove("corrupt.db3"); + EXPECT_THROW(SQLite::Database::getHeaderInfo("short.db3"), SQLite::Exception); + remove("short.db3"); + } + + // Simulate a corrupt header by writing garbage to a file + { + const unsigned char badData[100] = "garbage..."; + const char* pBadData = reinterpret_cast(&badData[0]); + + remove("corrupt.db3"); + std::ofstream corruptDb; + corruptDb.open("corrupt.db3", std::ios::app | std::ios::binary); + corruptDb.write(pBadData, sizeof(badData)); + corruptDb.close(); + + EXPECT_THROW(SQLite::Database::getHeaderInfo("corrupt.db3"), SQLite::Exception); + remove("corrupt.db3"); + } // Create a new database SQLite::Database db("test.db3", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE); db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)"); - + // Set assorted SQLite header values using associated PRAGMA db.exec("PRAGMA main.user_version = 12345"); db.exec("PRAGMA main.application_id = 2468"); @@ -388,7 +407,7 @@ TEST(Database, getHeaderInfo) // Parse header fields from test database SQLite::Header h = SQLite::Database::getHeaderInfo("test.db3"); - //Test header values expliticly set via PRAGMA statements + //Test header values explicitly set via PRAGMA statements EXPECT_EQ(h.userVersion, 12345); EXPECT_EQ(h.applicationId, 2468); From 4f4d8338688750e68099b2a5d8629152129ce93c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Rombauts?= Date: Sat, 4 Jan 2020 19:11:24 +0100 Subject: [PATCH 5/5] Add a new non static variant for getHeaderInfo() (TODO: need unit tests) --- include/SQLiteCpp/Database.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/SQLiteCpp/Database.h b/include/SQLiteCpp/Database.h index 1276109..c849443 100644 --- a/include/SQLiteCpp/Database.h +++ b/include/SQLiteCpp/Database.h @@ -477,6 +477,12 @@ public: */ static Header getHeaderInfo(const std::string& aFilename); + // Parse SQLite header data from a database file. + Header getHeaderInfo() + { + return getHeaderInfo(mFilename); + } + /** * @brief BackupType for the backup() method */