aboutsummaryrefslogtreecommitdiffstats
path: root/tests/unit
diff options
context:
space:
mode:
authorEike Ziller <eike.ziller@qt.io>2020-06-08 16:04:15 +0200
committerEike Ziller <eike.ziller@qt.io>2020-06-08 16:04:15 +0200
commitc644e7c80aa752c6154fa36fdc3ce47e0e17e758 (patch)
tree7aea6f2d15477c7dc0b0e4aa9e00156920c65b1d /tests/unit
parentbfcd1149eb688707a5495ce63f39e93bcf0c0a54 (diff)
parent42cad8970819c650c73f5daa4b6ea2f775ff7ad0 (diff)
Merge remote-tracking branch 'origin/qds-1.59'
Conflicts: src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp src/plugins/qmlpreview/qmlpreviewconnectionmanager.cpp Change-Id: Ifa7c66330c1995378280cdb4c57c30015dc11b68
Diffstat (limited to 'tests/unit')
-rw-r--r--tests/unit/unittest/commandlinebuilder-test.cpp4
-rw-r--r--tests/unit/unittest/createtablesqlstatementbuilder-test.cpp373
-rw-r--r--tests/unit/unittest/data/sqlite_database.dbbin4096 -> 12288 bytes
-rw-r--r--tests/unit/unittest/google-using-declarations.h19
-rw-r--r--tests/unit/unittest/gtest-creator-printing.cpp87
-rw-r--r--tests/unit/unittest/gtest-creator-printing.h22
-rw-r--r--tests/unit/unittest/gtest-llvm-printing.cpp2
-rw-r--r--tests/unit/unittest/lastchangedrowid-test.cpp471
-rw-r--r--tests/unit/unittest/mocksqlitedatabase.h8
-rw-r--r--tests/unit/unittest/mocksqlitestatement.h5
-rw-r--r--tests/unit/unittest/mocksqlitetransactionbackend.h3
-rw-r--r--tests/unit/unittest/pchcreator-test.cpp2
-rw-r--r--tests/unit/unittest/pchtaskqueue-test.cpp9
-rw-r--r--tests/unit/unittest/pchtasksmerger-test.cpp5
-rw-r--r--tests/unit/unittest/sqlitecolumn-test.cpp99
-rw-r--r--tests/unit/unittest/sqlitedatabase-test.cpp130
-rw-r--r--tests/unit/unittest/sqlitedatabasebackend-test.cpp46
-rw-r--r--tests/unit/unittest/sqlitesessions-test.cpp443
-rw-r--r--tests/unit/unittest/sqlitestatement-test.cpp343
-rw-r--r--tests/unit/unittest/sqlitetable-test.cpp202
-rw-r--r--tests/unit/unittest/sqlitetransaction-test.cpp59
-rw-r--r--tests/unit/unittest/sqlitevalue-test.cpp80
-rw-r--r--tests/unit/unittest/symbolquery-test.cpp15
-rw-r--r--tests/unit/unittest/unittest.pro2
-rw-r--r--tests/unit/unittest/unittests-main.cpp3
25 files changed, 2174 insertions, 258 deletions
diff --git a/tests/unit/unittest/commandlinebuilder-test.cpp b/tests/unit/unittest/commandlinebuilder-test.cpp
index 08c4e32f76..ee16438039 100644
--- a/tests/unit/unittest/commandlinebuilder-test.cpp
+++ b/tests/unit/unittest/commandlinebuilder-test.cpp
@@ -52,8 +52,8 @@ public:
CommandLineBuilder() { cppProjectInfo.language = Utils::Language::Cxx; }
public:
- ClangBackEnd::PchTask emptyProjectInfo{0, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}};
- ClangBackEnd::PchTask cppProjectInfo{1, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}};
+ ClangBackEnd::PchTask emptyProjectInfo{0, {}, {}, {}, {}, {}, {}, {}, {}, {}};
+ ClangBackEnd::PchTask cppProjectInfo{1, {}, {}, {}, {}, {}, {}, {}, {}, {}};
};
template <>
diff --git a/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp b/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp
index 9a56777a17..0e92b06897 100644
--- a/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp
+++ b/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp
@@ -30,20 +30,40 @@
namespace {
+using Sqlite::Column;
using Sqlite::ColumnType;
-using Sqlite::Contraint;
+using Sqlite::ConstraintType;
+using Sqlite::Enforment;
+using Sqlite::ForeignKey;
+using Sqlite::ForeignKeyAction;
using Sqlite::JournalMode;
using Sqlite::OpenMode;
-using Sqlite::Column;
+using Sqlite::PrimaryKey;
using Sqlite::SqliteColumns;
-
using Sqlite::SqlStatementBuilderException;
+using Sqlite::Unique;
class CreateTableSqlStatementBuilder : public ::testing::Test
{
protected:
- void bindValues();
- static SqliteColumns createColumns();
+ void bindValues()
+ {
+ builder.clear();
+ builder.setTableName("test");
+ builder.addColumn("id", ColumnType::Integer, {PrimaryKey{}});
+ builder.addColumn("name", ColumnType::Text);
+ builder.addColumn("number", ColumnType::Numeric);
+ }
+
+ static SqliteColumns createColumns()
+ {
+ SqliteColumns columns;
+ columns.emplace_back("", "id", ColumnType::Integer, Sqlite::Constraints{PrimaryKey{}});
+ columns.emplace_back("", "name", ColumnType::Text);
+ columns.emplace_back("", "number", ColumnType::Numeric);
+
+ return columns;
+ }
protected:
Sqlite::CreateTableSqlStatementBuilder builder;
@@ -157,7 +177,7 @@ TEST_F(CreateTableSqlStatementBuilder, UniqueContraint)
builder.clear();
builder.setTableName("test");
- builder.addColumn("id", ColumnType::Integer, Contraint::Unique);
+ builder.addColumn("id", ColumnType::Integer, {Unique{}});
ASSERT_THAT(builder.sqlStatement(),
"CREATE TABLE test(id INTEGER UNIQUE)");
@@ -167,7 +187,7 @@ TEST_F(CreateTableSqlStatementBuilder, IfNotExitsModifier)
{
builder.clear();
builder.setTableName("test");
- builder.addColumn("id", ColumnType::Integer, Contraint::NoConstraint);
+ builder.addColumn("id", ColumnType::Integer, {});
builder.setUseIfNotExists(true);
@@ -179,7 +199,7 @@ TEST_F(CreateTableSqlStatementBuilder, TemporaryTable)
{
builder.clear();
builder.setTableName("test");
- builder.addColumn("id", ColumnType::Integer, Contraint::NoConstraint);
+ builder.addColumn("id", ColumnType::Integer, {});
builder.setUseTemporaryTable(true);
@@ -187,23 +207,340 @@ TEST_F(CreateTableSqlStatementBuilder, TemporaryTable)
"CREATE TEMPORARY TABLE test(id INTEGER)");
}
-void CreateTableSqlStatementBuilder::bindValues()
+TEST_F(CreateTableSqlStatementBuilder, ForeignKeyWithoutColumn)
+{
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("id", ColumnType::Integer, {ForeignKey{"otherTable", ""}});
+
+ ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER REFERENCES otherTable)");
+}
+
+TEST_F(CreateTableSqlStatementBuilder, ForeignKeyWithColumn)
+{
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("id", ColumnType::Integer, {ForeignKey{"otherTable", "otherColumn"}});
+
+ ASSERT_THAT(builder.sqlStatement(),
+ "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn))");
+}
+
+TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateNoAction)
+{
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("id", ColumnType::Integer, {ForeignKey{"otherTable", "otherColumn"}});
+
+ ASSERT_THAT(builder.sqlStatement(),
+ "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn))");
+}
+
+TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateRestrict)
+{
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("id",
+ ColumnType::Integer,
+ {ForeignKey{"otherTable", "otherColumn", ForeignKeyAction::Restrict}});
+
+ ASSERT_THAT(
+ builder.sqlStatement(),
+ "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON UPDATE RESTRICT)");
+}
+
+TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateSetNull)
+{
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("id",
+ ColumnType::Integer,
+ {ForeignKey{"otherTable", "otherColumn", ForeignKeyAction::SetNull}});
+
+ ASSERT_THAT(
+ builder.sqlStatement(),
+ "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON UPDATE SET NULL)");
+}
+
+TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateSetDefault)
{
builder.clear();
builder.setTableName("test");
- builder.addColumn("id", ColumnType::Integer, Contraint::PrimaryKey);
- builder.addColumn("name", ColumnType::Text);
- builder.addColumn("number",ColumnType:: Numeric);
+
+ builder.addColumn("id",
+ ColumnType::Integer,
+ {ForeignKey{"otherTable", "otherColumn", ForeignKeyAction::SetDefault}});
+
+ ASSERT_THAT(
+ builder.sqlStatement(),
+ "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON UPDATE SET DEFAULT)");
}
-SqliteColumns CreateTableSqlStatementBuilder::createColumns()
+TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateCascade)
{
- SqliteColumns columns;
- columns.emplace_back("id", ColumnType::Integer, Contraint::PrimaryKey);
- columns.emplace_back("name", ColumnType::Text);
- columns.emplace_back("number", ColumnType::Numeric);
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("id",
+ ColumnType::Integer,
+ {ForeignKey{"otherTable", "otherColumn", ForeignKeyAction::Cascade}});
- return columns;
+ ASSERT_THAT(
+ builder.sqlStatement(),
+ "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON UPDATE CASCADE)");
}
+TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteNoAction)
+{
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("id", ColumnType::Integer, {ForeignKey{"otherTable", "otherColumn"}});
+
+ ASSERT_THAT(builder.sqlStatement(),
+ "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn))");
+}
+
+TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteRestrict)
+{
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("id",
+ ColumnType::Integer,
+ {ForeignKey{"otherTable", "otherColumn", {}, ForeignKeyAction::Restrict}});
+
+ ASSERT_THAT(
+ builder.sqlStatement(),
+ "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON DELETE RESTRICT)");
+}
+
+TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteSetNull)
+{
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("id",
+ ColumnType::Integer,
+ {ForeignKey{"otherTable", "otherColumn", {}, ForeignKeyAction::SetNull}});
+
+ ASSERT_THAT(
+ builder.sqlStatement(),
+ "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON DELETE SET NULL)");
+}
+
+TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteSetDefault)
+{
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("id",
+ ColumnType::Integer,
+ {ForeignKey{"otherTable", "otherColumn", {}, ForeignKeyAction::SetDefault}});
+
+ ASSERT_THAT(
+ builder.sqlStatement(),
+ "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON DELETE SET DEFAULT)");
+}
+
+TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteCascade)
+{
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("id",
+ ColumnType::Integer,
+ {ForeignKey{"otherTable", "otherColumn", {}, ForeignKeyAction::Cascade}});
+
+ ASSERT_THAT(
+ builder.sqlStatement(),
+ "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON DELETE CASCADE)");
+}
+
+TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteAndUpdateAction)
+{
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("id",
+ ColumnType::Integer,
+ {ForeignKey{"otherTable",
+ "otherColumn",
+ ForeignKeyAction::SetDefault,
+ ForeignKeyAction::Cascade}});
+
+ ASSERT_THAT(builder.sqlStatement(),
+ "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON UPDATE SET "
+ "DEFAULT ON DELETE CASCADE)");
+}
+
+TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeferred)
+{
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("id",
+ ColumnType::Integer,
+ {ForeignKey{"otherTable",
+ "otherColumn",
+ ForeignKeyAction::SetDefault,
+ ForeignKeyAction::Cascade,
+ Enforment::Deferred}});
+
+ ASSERT_THAT(builder.sqlStatement(),
+ "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON UPDATE SET "
+ "DEFAULT ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)");
}
+
+TEST_F(CreateTableSqlStatementBuilder, NotNullConstraint)
+{
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("id", ColumnType::Integer, {Sqlite::NotNull{}});
+
+ ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER NOT NULL)");
+}
+
+TEST_F(CreateTableSqlStatementBuilder, NotNullAndUniqueConstraint)
+{
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("id", ColumnType::Integer, {Sqlite::Unique{}, Sqlite::NotNull{}});
+
+ ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER UNIQUE NOT NULL)");
+}
+
+TEST_F(CreateTableSqlStatementBuilder, Check)
+{
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("id", ColumnType::Text, {Sqlite::Check{"id != ''"}});
+
+ ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id TEXT CHECK (id != ''))");
+}
+
+TEST_F(CreateTableSqlStatementBuilder, DefaultValueInt)
+{
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("id", ColumnType::Integer, {Sqlite::DefaultValue{1LL}});
+
+ ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER DEFAULT 1)");
+}
+
+TEST_F(CreateTableSqlStatementBuilder, DefaultValueFloat)
+{
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("id", ColumnType::Real, {Sqlite::DefaultValue{1.1}});
+
+ ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id REAL DEFAULT 1.100000)");
+}
+
+TEST_F(CreateTableSqlStatementBuilder, DefaultValueString)
+{
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("id", ColumnType::Text, {Sqlite::DefaultValue{"foo"}});
+
+ ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id TEXT DEFAULT 'foo')");
+}
+
+TEST_F(CreateTableSqlStatementBuilder, DefaultExpression)
+{
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("id",
+ ColumnType::Integer,
+ {Sqlite::DefaultExpression{"SELECT name FROM foo WHERE id=?"}});
+
+ ASSERT_THAT(builder.sqlStatement(),
+ "CREATE TABLE test(id INTEGER DEFAULT (SELECT name FROM foo WHERE id=?))");
+}
+
+TEST_F(CreateTableSqlStatementBuilder, Collation)
+{
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("id", ColumnType::Text, {Sqlite::Collate{"unicode"}});
+
+ ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id TEXT COLLATE unicode)");
+}
+
+TEST_F(CreateTableSqlStatementBuilder, GeneratedAlwaysStored)
+{
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("id",
+ ColumnType::Text,
+ {Sqlite::GeneratedAlways{"SELECT name FROM foo WHERE id=?",
+ Sqlite::GeneratedAlwaysStorage::Stored}});
+
+ ASSERT_THAT(
+ builder.sqlStatement(),
+ "CREATE TABLE test(id TEXT GENERATED ALWAYS AS (SELECT name FROM foo WHERE id=?) STORED)");
+}
+
+TEST_F(CreateTableSqlStatementBuilder, GeneratedAlwaysVirtual)
+{
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("id",
+ ColumnType::Text,
+ {Sqlite::GeneratedAlways{"SELECT name FROM foo WHERE id=?",
+ Sqlite::GeneratedAlwaysStorage::Virtual}});
+
+ ASSERT_THAT(builder.sqlStatement(),
+ "CREATE TABLE test(id TEXT GENERATED ALWAYS AS (SELECT name FROM foo WHERE id=?) "
+ "VIRTUAL)");
+}
+
+TEST_F(CreateTableSqlStatementBuilder, PrimaryKeyAutoincrement)
+{
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("id", ColumnType::Integer, {Sqlite::PrimaryKey{Sqlite::AutoIncrement::Yes}});
+
+ ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER PRIMARY KEY AUTOINCREMENT)");
+}
+
+TEST_F(CreateTableSqlStatementBuilder, BlobType)
+{
+ builder.clear();
+ builder.setTableName("test");
+
+ builder.addColumn("data", ColumnType::Blob);
+
+ ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(data BLOB)");
+}
+
+TEST_F(CreateTableSqlStatementBuilder, TablePrimaryKeyConstaint)
+{
+ builder.clear();
+ builder.setTableName("test");
+ builder.addColumn("id", ColumnType::Integer);
+ builder.addColumn("text", ColumnType::Text);
+
+ builder.addConstraint(Sqlite::TablePrimaryKey{{"id, text"}});
+ auto statement = builder.sqlStatement();
+
+ ASSERT_THAT(statement, "CREATE TABLE test(id INTEGER, text TEXT, PRIMARY KEY(id, text))");
+}
+
+} // namespace
diff --git a/tests/unit/unittest/data/sqlite_database.db b/tests/unit/unittest/data/sqlite_database.db
index 9c5879579e..5a7284d087 100644
--- a/tests/unit/unittest/data/sqlite_database.db
+++ b/tests/unit/unittest/data/sqlite_database.db
Binary files differ
diff --git a/tests/unit/unittest/google-using-declarations.h b/tests/unit/unittest/google-using-declarations.h
index e8bbd52800..1a92ff3388 100644
--- a/tests/unit/unittest/google-using-declarations.h
+++ b/tests/unit/unittest/google-using-declarations.h
@@ -37,21 +37,28 @@ using testing::AnyOf;
using testing::Assign;
using testing::ByMove;
using testing::ByRef;
-using testing::Contains;
using testing::ContainerEq;
+using testing::Contains;
using testing::ElementsAre;
+using testing::Eq;
using testing::Field;
+using testing::Ge;
+using testing::Gt;
using testing::HasSubstr;
using testing::InSequence;
using testing::Invoke;
using testing::IsEmpty;
using testing::IsNull;
+using testing::Le;
+using testing::Lt;
using testing::Matcher;
using testing::Mock;
using testing::MockFunction;
+using testing::Ne;
using testing::NiceMock;
-using testing::NotNull;
using testing::Not;
+using testing::NotNull;
+using testing::Optional;
using testing::Pair;
using testing::PrintToString;
using testing::Property;
@@ -64,10 +71,4 @@ using testing::StrEq;
using testing::Throw;
using testing::TypedEq;
using testing::UnorderedElementsAre;
-
-using testing::Eq;
-using testing::Ge;
-using testing::Gt;
-using testing::Le;
-using testing::Lt;
-using testing::Ne;
+using testing::VariantWith;
diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp
index 62561d279b..0f79e048b9 100644
--- a/tests/unit/unittest/gtest-creator-printing.cpp
+++ b/tests/unit/unittest/gtest-creator-printing.cpp
@@ -58,6 +58,7 @@
#include <sourcedependency.h>
#include <sourcelocationentry.h>
#include <sourcelocationscontainer.h>
+#include <sqlitesessionchangeset.h>
#include <sqlitevalue.h>
#include <symbol.h>
#include <symbolentry.h>
@@ -67,6 +68,8 @@
#include <usedmacro.h>
#include <utils/link.h>
+#include <sqlite3ext.h>
+
namespace {
ClangBackEnd::FilePathCaching *filePathCache = nullptr;
}
@@ -321,6 +324,90 @@ std::ostream &operator<<(std::ostream &out, const Value &value)
return out << ")";
}
+
+namespace {
+Utils::SmallStringView operationText(int operation)
+{
+ switch (operation) {
+ case SQLITE_INSERT:
+ return "INSERT";
+ case SQLITE_UPDATE:
+ return "UPDATE";
+ case SQLITE_DELETE:
+ return "DELETE";
+ }
+
+ return {};
+}
+
+std::ostream &operator<<(std::ostream &out, sqlite3_changeset_iter *iter)
+{
+ out << "(";
+
+ const char *tableName = nullptr;
+ int columns = 0;
+ int operation = 0;
+ sqlite3_value *value = nullptr;
+
+ sqlite3changeset_op(iter, &tableName, &columns, &operation, 0);
+
+ out << operationText(operation) << " " << tableName << " {";
+
+ if (operation == SQLITE_UPDATE || operation == SQLITE_DELETE) {
+ out << "Old: [";
+
+ for (int i = 0; i < columns; i++) {
+ sqlite3changeset_old(iter, i, &value);
+
+ if (value)
+ out << " " << sqlite3_value_text(value);
+ else
+ out << " -";
+ }
+ out << "]";
+ }
+
+ if (operation == SQLITE_UPDATE)
+ out << ", ";
+
+ if (operation == SQLITE_UPDATE || operation == SQLITE_INSERT) {
+ out << "New: [";
+ for (int i = 0; i < columns; i++) {
+ sqlite3changeset_new(iter, i, &value);
+
+ if (value)
+ out << " " << sqlite3_value_text(value);
+ else
+ out << " -";
+ }
+ out << "]";
+ }
+
+ out << "})";
+
+ return out;
+}
+} // namespace
+
+std::ostream &operator<<(std::ostream &out, const SessionChangeSet &changeset)
+{
+ sqlite3_changeset_iter *iter = nullptr;
+ sqlite3changeset_start(&iter, changeset.size, const_cast<void *>(changeset.data));
+
+ out << "ChangeSets([";
+
+ if (SQLITE_ROW == sqlite3changeset_next(iter)) {
+ out << iter;
+ while (SQLITE_ROW == sqlite3changeset_next(iter))
+ out << ", " << iter;
+ }
+
+ sqlite3changeset_finalize(iter);
+
+ out << "])";
+
+ return out;
+}
} // namespace Sqlite
namespace ClangBackEnd {
diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h
index b91c8d46be..c791290ae2 100644
--- a/tests/unit/unittest/gtest-creator-printing.h
+++ b/tests/unit/unittest/gtest-creator-printing.h
@@ -66,8 +66,10 @@ void PrintTo(const TextRange &range, ::std::ostream *os);
namespace Sqlite {
class Value;
+class SessionChangeSet;
std::ostream &operator<<(std::ostream &out, const Value &value);
+std::ostream &operator<<(std::ostream &out, const SessionChangeSet &changeset);
} // namespace Sqlite
namespace ProjectExplorer {
@@ -348,4 +350,24 @@ std::ostream &operator<<(std::ostream &out, const Diagnostic &diag);
} // namespace Internal
} // namespace CppTools
+namespace std {
+template<typename T>
+ostream &operator<<(ostream &out, const vector<T> &vector)
+{
+ out << "[";
+
+ for (auto current = vector.begin(); current != vector.end(); ++current) {
+ out << *current;
+
+ if (std::next(current) != vector.end())
+ out << ", ";
+ }
+
+ out << "]";
+
+ return out;
+}
+
+} // namespace std
+
void setFilePathCache(ClangBackEnd::FilePathCaching *filePathCache);
diff --git a/tests/unit/unittest/gtest-llvm-printing.cpp b/tests/unit/unittest/gtest-llvm-printing.cpp
index c78b4f9eea..467f4a5261 100644
--- a/tests/unit/unittest/gtest-llvm-printing.cpp
+++ b/tests/unit/unittest/gtest-llvm-printing.cpp
@@ -23,6 +23,8 @@
**
****************************************************************************/
+#include "gtest-creator-printing.h"
+
#include <gtest/gtest-printers.h>
#include <utils/smallstringio.h>
diff --git a/tests/unit/unittest/lastchangedrowid-test.cpp b/tests/unit/unittest/lastchangedrowid-test.cpp
new file mode 100644
index 0000000000..07b29bee57
--- /dev/null
+++ b/tests/unit/unittest/lastchangedrowid-test.cpp
@@ -0,0 +1,471 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "googletest.h"
+
+#include "mocksqlitedatabase.h"
+
+#include <lastchangedrowid.h>
+
+namespace {
+
+class LastChangedRowId : public testing::Test
+{
+protected:
+ NiceMock<MockSqliteDatabase> mockSqliteDatabase;
+ Sqlite::LastChangedRowId lastRowId{mockSqliteDatabase, "main", "foo"};
+};
+
+TEST_F(LastChangedRowId, SetUpdateHookInContructor)
+{
+ EXPECT_CALL(mockSqliteDatabase, setUpdateHook(_));
+
+ Sqlite::LastChangedRowId lastRowId{mockSqliteDatabase, "main", "foo"};
+}
+
+TEST_F(LastChangedRowId, ResetUpdateHookInDestructor)
+{
+ EXPECT_CALL(mockSqliteDatabase, resetUpdateHook());
+}
+
+TEST_F(LastChangedRowId, GetMinusOneAsRowIdIfNoCallbackWasCalled)
+{
+ ASSERT_THAT(lastRowId.lastRowId, -1);
+}
+
+TEST_F(LastChangedRowId, CallbackSetsLastRowId)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 42);
+
+ ASSERT_THAT(lastRowId.lastRowId, 42);
+}
+
+TEST_F(LastChangedRowId, CallbackChecksDatabaseName)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 33);
+
+ lastRowId.callback(Sqlite::ChangeType::Update, "temp", "foo", 42);
+
+ ASSERT_THAT(lastRowId.lastRowId, 33);
+}
+
+TEST_F(LastChangedRowId, CallbackChecksTableName)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 33);
+
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "bar", 42);
+
+ ASSERT_THAT(lastRowId.lastRowId, 33);
+}
+
+TEST_F(LastChangedRowId, LastCallSetsRowId)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 42);
+ lastRowId.callback(Sqlite::ChangeType::Insert, "main", "foo", 33);
+
+ lastRowId.callback(Sqlite::ChangeType::Delete, "main", "foo", 66);
+
+ ASSERT_THAT(lastRowId.lastRowId, 66);
+}
+
+TEST_F(LastChangedRowId, TakeLastRowId)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 42);
+
+ auto id = lastRowId.takeLastRowId();
+
+ ASSERT_THAT(id, 42);
+}
+
+TEST_F(LastChangedRowId, TakeLastRowIdResetsRowIdToMinusOne)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 42);
+ lastRowId.takeLastRowId();
+
+ auto id = lastRowId.takeLastRowId();
+
+ ASSERT_THAT(id, -1);
+}
+
+class LastChangedRowIdWithTwoTables : public testing::Test
+{
+protected:
+ NiceMock<MockSqliteDatabase> mockSqliteDatabase;
+
+ Sqlite::LastChangedRowId lastRowId{mockSqliteDatabase, "main", "foo", "bar"};
+};
+
+TEST_F(LastChangedRowIdWithTwoTables, SetUpdateHookInContructor)
+{
+ EXPECT_CALL(mockSqliteDatabase, setUpdateHook(_));
+
+ Sqlite::LastChangedRowId lastRowId{mockSqliteDatabase, "main", "foo"};
+}
+
+TEST_F(LastChangedRowIdWithTwoTables, ResetUpdateHookInDestructor)
+{
+ EXPECT_CALL(mockSqliteDatabase, resetUpdateHook());
+}
+
+TEST_F(LastChangedRowIdWithTwoTables, GetMinusOneAsRowIdIfNoCallbackWasCalled)
+{
+ ASSERT_THAT(lastRowId.lastRowId, -1);
+}
+
+TEST_F(LastChangedRowIdWithTwoTables, CallbackSetsLastRowIdFirstTable)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 42);
+
+ ASSERT_THAT(lastRowId.lastRowId, 42);
+}
+
+TEST_F(LastChangedRowIdWithTwoTables, CallbackSetsLastRowIdSecondTable)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "bar", 66);
+
+ ASSERT_THAT(lastRowId.lastRowId, 66);
+}
+
+TEST_F(LastChangedRowIdWithTwoTables, CallbackChecksDatabaseName)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 33);
+
+ lastRowId.callback(Sqlite::ChangeType::Update, "temp", "foo", 42);
+
+ ASSERT_THAT(lastRowId.lastRowId, 33);
+}
+
+TEST_F(LastChangedRowIdWithTwoTables, CallbackChecksTableName)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 33);
+
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "zoo", 42);
+
+ ASSERT_THAT(lastRowId.lastRowId, 33);
+}
+
+TEST_F(LastChangedRowIdWithTwoTables, LastCallSetsRowId)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 42);
+
+ lastRowId.callback(Sqlite::ChangeType::Delete, "main", "bar", 66);
+
+ ASSERT_THAT(lastRowId.lastRowId, 66);
+}
+
+TEST_F(LastChangedRowIdWithTwoTables, TakeLastRowId)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 42);
+
+ auto id = lastRowId.takeLastRowId();
+
+ ASSERT_THAT(id, 42);
+}
+
+TEST_F(LastChangedRowIdWithTwoTables, TakeLastRowIdResetsRowIdToMinusOne)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 42);
+ lastRowId.takeLastRowId();
+
+ auto id = lastRowId.takeLastRowId();
+
+ ASSERT_THAT(id, -1);
+}
+
+class LastChangedRowIdWithThreeTables : public testing::Test
+{
+protected:
+ NiceMock<MockSqliteDatabase> mockSqliteDatabase;
+
+ Sqlite::LastChangedRowId lastRowId{mockSqliteDatabase, "main", "foo", "bar", "too"};
+};
+
+TEST_F(LastChangedRowIdWithThreeTables, SetUpdateHookInContructor)
+{
+ EXPECT_CALL(mockSqliteDatabase, setUpdateHook(_));
+
+ Sqlite::LastChangedRowId lastRowId{mockSqliteDatabase, "main", "foo"};
+}
+
+TEST_F(LastChangedRowIdWithThreeTables, ResetUpdateHookInDestructor)
+{
+ EXPECT_CALL(mockSqliteDatabase, resetUpdateHook());
+}
+
+TEST_F(LastChangedRowIdWithThreeTables, GetMinusOneAsRowIdIfNoCallbackWasCalled)
+{
+ ASSERT_THAT(lastRowId.lastRowId, -1);
+}
+
+TEST_F(LastChangedRowIdWithThreeTables, CallbackSetsLastRowIdFirstTable)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 42);
+
+ ASSERT_THAT(lastRowId.lastRowId, 42);
+}
+
+TEST_F(LastChangedRowIdWithThreeTables, CallbackSetsLastRowIdSecondTable)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "bar", 42);
+
+ ASSERT_THAT(lastRowId.lastRowId, 42);
+}
+
+TEST_F(LastChangedRowIdWithThreeTables, CallbackSetsLastRowIdThirdTable)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "too", 42);
+
+ ASSERT_THAT(lastRowId.lastRowId, 42);
+}
+
+TEST_F(LastChangedRowIdWithThreeTables, CallbackChecksDatabaseName)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 33);
+
+ lastRowId.callback(Sqlite::ChangeType::Update, "temp", "foo", 42);
+
+ ASSERT_THAT(lastRowId.lastRowId, 33);
+}
+
+TEST_F(LastChangedRowIdWithThreeTables, CallbackChecksTableName)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 33);
+
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "zoo", 42);
+
+ ASSERT_THAT(lastRowId.lastRowId, 33);
+}
+
+TEST_F(LastChangedRowIdWithThreeTables, LastCallSetsRowId)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "bar", 42);
+ lastRowId.callback(Sqlite::ChangeType::Insert, "main", "too", 33);
+
+ lastRowId.callback(Sqlite::ChangeType::Delete, "main", "too", 66);
+
+ ASSERT_THAT(lastRowId.lastRowId, 66);
+}
+
+TEST_F(LastChangedRowIdWithThreeTables, TakeLastRowId)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 42);
+
+ auto id = lastRowId.takeLastRowId();
+
+ ASSERT_THAT(id, 42);
+}
+
+TEST_F(LastChangedRowIdWithThreeTables, TakeLastRowIdResetsRowIdToMinusOne)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 42);
+ lastRowId.takeLastRowId();
+
+ auto id = lastRowId.takeLastRowId();
+
+ ASSERT_THAT(id, -1);
+}
+
+class LastChangedRowIdWithNoDatabaseAndTable : public testing::Test
+{
+protected:
+ NiceMock<MockSqliteDatabase> mockSqliteDatabase;
+ Sqlite::LastChangedRowId lastRowId{mockSqliteDatabase};
+};
+
+TEST_F(LastChangedRowIdWithNoDatabaseAndTable, SetUpdateHookInContructor)
+{
+ EXPECT_CALL(mockSqliteDatabase, setUpdateHook(_));
+
+ Sqlite::LastChangedRowId lastRowId{mockSqliteDatabase, "main", "foo"};
+}
+
+TEST_F(LastChangedRowIdWithNoDatabaseAndTable, ResetUpdateHookInDestructor)
+{
+ EXPECT_CALL(mockSqliteDatabase, resetUpdateHook());
+}
+
+TEST_F(LastChangedRowIdWithNoDatabaseAndTable, GetMinusOneAsRowIdIfNoCallbackWasCalled)
+{
+ ASSERT_THAT(lastRowId.lastRowId, -1);
+}
+
+TEST_F(LastChangedRowIdWithNoDatabaseAndTable, CallbackSetsLastRowId)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 42);
+
+ ASSERT_THAT(lastRowId.lastRowId, 42);
+}
+
+TEST_F(LastChangedRowIdWithNoDatabaseAndTable, CallbackDoNotChecksDatabaseName)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 33);
+
+ lastRowId.callback(Sqlite::ChangeType::Update, "temp", "foo", 42);
+
+ ASSERT_THAT(lastRowId.lastRowId, 42);
+}
+
+TEST_F(LastChangedRowIdWithNoDatabaseAndTable, CallbackDoNotChecksTableName)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 33);
+
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "bar", 42);
+
+ ASSERT_THAT(lastRowId.lastRowId, 42);
+}
+
+TEST_F(LastChangedRowIdWithNoDatabaseAndTable, LastCallSetsRowId)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 42);
+ lastRowId.callback(Sqlite::ChangeType::Insert, "main", "foo", 33);
+
+ lastRowId.callback(Sqlite::ChangeType::Delete, "main", "foo", 66);
+
+ ASSERT_THAT(lastRowId.lastRowId, 66);
+}
+
+TEST_F(LastChangedRowIdWithNoDatabaseAndTable, TakeLastRowId)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 42);
+
+ auto id = lastRowId.takeLastRowId();
+
+ ASSERT_THAT(id, 42);
+}
+
+TEST_F(LastChangedRowIdWithNoDatabaseAndTable, TakeLastRowIdResetsRowIdToMinusOne)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 42);
+ lastRowId.takeLastRowId();
+
+ auto id = lastRowId.takeLastRowId();
+
+ ASSERT_THAT(id, -1);
+}
+
+class LastChangedRowIdWithNoTable : public testing::Test
+{
+protected:
+ NiceMock<MockSqliteDatabase> mockSqliteDatabase;
+ Sqlite::LastChangedRowId lastRowId{mockSqliteDatabase, "main"};
+};
+
+TEST_F(LastChangedRowIdWithNoTable, SetUpdateHookInContructor)
+{
+ EXPECT_CALL(mockSqliteDatabase, setUpdateHook(_));
+
+ Sqlite::LastChangedRowId lastRowId{mockSqliteDatabase, "main", "foo"};
+}
+
+TEST_F(LastChangedRowIdWithNoTable, ResetUpdateHookInDestructor)
+{
+ EXPECT_CALL(mockSqliteDatabase, resetUpdateHook());
+}
+
+TEST_F(LastChangedRowIdWithNoTable, GetMinusOneAsRowIdIfNoCallbackWasCalled)
+{
+ ASSERT_THAT(lastRowId.lastRowId, -1);
+}
+
+TEST_F(LastChangedRowIdWithNoTable, CallbackSetsLastRowId)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 42);
+
+ ASSERT_THAT(lastRowId.lastRowId, 42);
+}
+
+TEST_F(LastChangedRowIdWithNoTable, CallbackChecksDatabaseName)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 33);
+
+ lastRowId.callback(Sqlite::ChangeType::Update, "temp", "foo", 42);
+
+ ASSERT_THAT(lastRowId.lastRowId, 33);
+}
+
+TEST_F(LastChangedRowIdWithNoTable, CallbackDoNotChecksTableName)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 33);
+
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "bar", 42);
+
+ ASSERT_THAT(lastRowId.lastRowId, 42);
+}
+
+TEST_F(LastChangedRowIdWithNoTable, LastCallSetsRowId)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 42);
+ lastRowId.callback(Sqlite::ChangeType::Insert, "main", "foo", 33);
+
+ lastRowId.callback(Sqlite::ChangeType::Delete, "main", "foo", 66);
+
+ ASSERT_THAT(lastRowId.lastRowId, 66);
+}
+
+TEST_F(LastChangedRowIdWithNoTable, TakeLastRowId)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 42);
+
+ auto id = lastRowId.takeLastRowId();
+
+ ASSERT_THAT(id, 42);
+}
+
+TEST_F(LastChangedRowIdWithNoTable, TakeLastRowIdResetsRowIdToMinusOne)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 42);
+ lastRowId.takeLastRowId();
+
+ auto id = lastRowId.takeLastRowId();
+
+ ASSERT_THAT(id, -1);
+}
+
+TEST_F(LastChangedRowIdWithNoTable, LastRowIdIsNotValidForNegativeValues)
+{
+ auto isValid = lastRowId.lastRowIdIsValid();
+
+ ASSERT_FALSE(isValid);
+}
+
+TEST_F(LastChangedRowIdWithNoTable, LastRowIdIsValidForNull)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 0);
+
+ auto isValid = lastRowId.lastRowIdIsValid();
+
+ ASSERT_TRUE(isValid);
+}
+
+TEST_F(LastChangedRowIdWithNoTable, LastRowIdIsValidForPositiveValues)
+{
+ lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 777);
+
+ auto isValid = lastRowId.lastRowIdIsValid();
+
+ ASSERT_TRUE(isValid);
+}
+
+} // namespace
diff --git a/tests/unit/unittest/mocksqlitedatabase.h b/tests/unit/unittest/mocksqlitedatabase.h
index 05f6f4e958..c627f995a4 100644
--- a/tests/unit/unittest/mocksqlitedatabase.h
+++ b/tests/unit/unittest/mocksqlitedatabase.h
@@ -59,5 +59,13 @@ public:
void (bool));
MOCK_METHOD0(walCheckpointFull, void());
+
+ MOCK_METHOD1(setUpdateHook, void(Sqlite::DatabaseInterface::UpdateCallback &));
+
+ MOCK_METHOD0(resetUpdateHook, void());
+
+ MOCK_METHOD0(applyAndUpdateSessions, void());
+
+ MOCK_METHOD1(setAttachedTables, void(const Utils::SmallStringVector &tables));
};
diff --git a/tests/unit/unittest/mocksqlitestatement.h b/tests/unit/unittest/mocksqlitestatement.h
index 26f5b0de6e..7be7f3f05e 100644
--- a/tests/unit/unittest/mocksqlitestatement.h
+++ b/tests/unit/unittest/mocksqlitestatement.h
@@ -52,9 +52,10 @@ public:
MOCK_METHOD2(bind, void (int, double));
MOCK_METHOD2(bind, void (int, Utils::SmallStringView));
MOCK_METHOD2(bind, void (int, long));
- MOCK_CONST_METHOD1(bindingIndexForName, int (Utils::SmallStringView name));
- MOCK_METHOD1(prepare, void (Utils::SmallStringView sqlStatement));
+ MOCK_METHOD1(prepare, void(Utils::SmallStringView sqlStatement));
+
+ MOCK_METHOD1(checkColumnCount, void(int));
};
template<>
diff --git a/tests/unit/unittest/mocksqlitetransactionbackend.h b/tests/unit/unittest/mocksqlitetransactionbackend.h
index 0cfeee2892..363ad573d7 100644
--- a/tests/unit/unittest/mocksqlitetransactionbackend.h
+++ b/tests/unit/unittest/mocksqlitetransactionbackend.h
@@ -40,4 +40,7 @@ public:
MOCK_METHOD0(rollback, void ());
MOCK_METHOD0(lock, void ());
MOCK_METHOD0(unlock, void ());
+ MOCK_METHOD0(immediateSessionBegin, void());
+ MOCK_METHOD0(sessionCommit, void());
+ MOCK_METHOD0(sessionRollback, void());
};
diff --git a/tests/unit/unittest/pchcreator-test.cpp b/tests/unit/unittest/pchcreator-test.cpp
index ad5b57b4f5..c7268a51d8 100644
--- a/tests/unit/unittest/pchcreator-test.cpp
+++ b/tests/unit/unittest/pchcreator-test.cpp
@@ -137,7 +137,6 @@ protected:
sorted({id(main2Path), id(generatedFilePath)}),
{},
{},
- {},
{{TESTDATA_DIR "/builddependencycollector/system", 2, IncludeSearchPathType::BuiltIn},
{TESTDATA_DIR "/builddependencycollector/external", 1, IncludeSearchPathType::System}},
{{TESTDATA_DIR "/builddependencycollector/project", 1, IncludeSearchPathType::User}},
@@ -374,7 +373,6 @@ TEST_F(PchCreatorVerySlowTest, FaultyProjectPartPchForCreatesFaultyPchForPchTask
{},
{{"DEFINE", "1", 1}},
{},
- {},
{{TESTDATA_DIR "/builddependencycollector/external", 1, IncludeSearchPathType::System}},
{{TESTDATA_DIR "/builddependencycollector/project", 1, IncludeSearchPathType::User}}};
diff --git a/tests/unit/unittest/pchtaskqueue-test.cpp b/tests/unit/unittest/pchtaskqueue-test.cpp
index f516858862..598a2a5132 100644
--- a/tests/unit/unittest/pchtaskqueue-test.cpp
+++ b/tests/unit/unittest/pchtaskqueue-test.cpp
@@ -71,7 +71,6 @@ protected:
{3, 4},
{6, 7},
{{"YI", "1", 1}, {"SAN", "3", 3}},
- {{"LIANG", 0}, {"YI", 1}},
{"--yi"},
systemIncludeSearchPaths,
projectIncludeSearchPaths};
@@ -82,7 +81,6 @@ protected:
{3, 4},
{6, 7},
{{"YI", "1", 1}, {"SAN", "3", 3}},
- {{"LIANG", 0}, {"YI", 1}},
{"--yi"},
systemIncludeSearchPaths,
projectIncludeSearchPaths};
@@ -93,7 +91,6 @@ protected:
{4, 7},
{8, 9},
{{"YI", "1", 1}, {"SAN", "3", 3}},
- {{"LIANG", 0}, {"YI", 1}},
{"--yi"},
systemIncludeSearchPaths,
projectIncludeSearchPaths};
@@ -104,7 +101,6 @@ protected:
{3, 4},
{6, 7},
{{"YI", "1", 1}, {"SAN", "3", 3}},
- {{"LIANG", 0}, {"YI", 1}},
{"--yi"},
systemIncludeSearchPaths,
projectIncludeSearchPaths};
@@ -115,7 +111,6 @@ protected:
{13, 14},
{16, 17},
{{"SE", "4", 4}, {"WU", "5", 5}},
- {{"ER", 2}, {"SAN", 3}},
{"--yi"},
systemIncludeSearchPaths,
projectIncludeSearchPaths};
@@ -126,7 +121,6 @@ protected:
{13, 14},
{16, 17},
{{"SE", "4", 4}, {"WU", "5", 5}},
- {{"ER", 2}, {"SAN", 3}},
{"--yi"},
systemIncludeSearchPaths,
projectIncludeSearchPaths};
@@ -137,7 +131,6 @@ protected:
{23, 24},
{26, 27},
{{"SE", "4", 4}, {"WU", "5", 5}},
- {{"ER", 2}, {"SAN", 3}},
{"--yi"},
systemIncludeSearchPaths,
projectIncludeSearchPaths};
@@ -148,7 +141,6 @@ protected:
{23, 24},
{26, 27},
{{"SE", "4", 4}, {"WU", "5", 5}},
- {{"ER", 2}, {"SAN", 3}},
{"--yi"},
systemIncludeSearchPaths,
projectIncludeSearchPaths};
@@ -159,7 +151,6 @@ protected:
{3, 4},
{5, 8},
{{"YI", "1", 1}, {"SAN", "3", 3}},
- {{"LIANG", 0}, {"YI", 1}},
{"--yi"},
systemIncludeSearchPaths,
projectIncludeSearchPaths};
diff --git a/tests/unit/unittest/pchtasksmerger-test.cpp b/tests/unit/unittest/pchtasksmerger-test.cpp
index 28f9593ad4..a816a7f5cb 100644
--- a/tests/unit/unittest/pchtasksmerger-test.cpp
+++ b/tests/unit/unittest/pchtasksmerger-test.cpp
@@ -59,7 +59,6 @@ protected:
{},
{},
{{"YI", "1", 1}, {"SAN", "3", 3}},
- {"YI", "LIANG"},
{"--yi"},
{{"/system/path", 2, IncludeSearchPathType::System},
{"/builtin/path2", 3, IncludeSearchPathType::BuiltIn},
@@ -73,7 +72,6 @@ protected:
{31, 32},
{41, 42},
{{"SE", "4", 4}, {"WU", "5", 5}},
- {"ER", "SAN"},
{"--yi"},
{{"/system/path", 1, IncludeSearchPathType::System},
{"/builtin/path", 2, IncludeSearchPathType::BuiltIn}},
@@ -86,7 +84,6 @@ protected:
{},
{},
{{"SE", "4", 4}, {"WU", "5", 5}},
- {"ER", "SAN"},
{"--yi"},
{{"/system/path", 2, IncludeSearchPathType::System},
{"/builtin/path", 3, IncludeSearchPathType::BuiltIn},
@@ -100,7 +97,6 @@ protected:
{31, 32},
{41, 42},
{{"SE", "4", 4}, {"WU", "5", 5}},
- {"ER", "SAN"},
{"--yi"},
{{"/system/path", 2, IncludeSearchPathType::System},
{"/builtin/path", 3, IncludeSearchPathType::BuiltIn},
@@ -114,7 +110,6 @@ protected:
{},
{},
{{"YI", "2", 1}, {"SAN", "3", 3}},
- {"YI", "LIANG"},
{"--yi"},
{{"/system/path", 2, IncludeSearchPathType::System},
{"/builtin/path", 3, IncludeSearchPathType::BuiltIn},
diff --git a/tests/unit/unittest/sqlitecolumn-test.cpp b/tests/unit/unittest/sqlitecolumn-test.cpp
index 3daa32bd23..9753457c94 100644
--- a/tests/unit/unittest/sqlitecolumn-test.cpp
+++ b/tests/unit/unittest/sqlitecolumn-test.cpp
@@ -29,70 +29,93 @@
namespace {
-using testing::AllOf;
-using testing::Contains;
-using testing::Property;
-
using Sqlite::ColumnType;
-using Sqlite::Contraint;
+using Sqlite::ConstraintType;
using Sqlite::JournalMode;
using Sqlite::OpenMode;
using Column = Sqlite::Column;
+using Sqlite::Enforment;
+using Sqlite::ForeignKey;
+using Sqlite::ForeignKeyAction;
using Sqlite::SqliteColumns;
class SqliteColumn : public ::testing::Test
{
protected:
- void SetUp() override;
-
Sqlite::Column column;
};
-TEST_F(SqliteColumn, ChangeName)
+TEST_F(SqliteColumn, DefaultConstruct)
{
- column.setName("Claudia");
-
- ASSERT_THAT(column.name(), "Claudia");
-}
-
-TEST_F(SqliteColumn, DefaultType)
-{
- ASSERT_THAT(column.type(), ColumnType::Numeric);
+ ASSERT_THAT(column,
+ AllOf(Field(&Column::name, IsEmpty()),
+ Field(&Column::tableName, IsEmpty()),
+ Field(&Column::type, ColumnType::Numeric),
+ Field(&Column::constraints, IsEmpty())));
}
-TEST_F(SqliteColumn, ChangeType)
+TEST_F(SqliteColumn, Clear)
{
- column.setType(ColumnType::Text);
+ column.name = "foo";
+ column.name = "foo";
+ column.type = ColumnType::Text;
+ column.constraints = {Sqlite::PrimaryKey{}};
- ASSERT_THAT(column.type(), ColumnType::Text);
-}
+ column.clear();
-TEST_F(SqliteColumn, DefaultConstraint)
-{
- ASSERT_THAT(column.constraint(), Contraint::NoConstraint);
+ ASSERT_THAT(column,
+ AllOf(Field(&Column::name, IsEmpty()),
+ Field(&Column::tableName, IsEmpty()),
+ Field(&Column::type, ColumnType::Numeric),
+ Field(&Column::constraints, IsEmpty())));
}
-TEST_F(SqliteColumn, SetConstraint)
+TEST_F(SqliteColumn, Constructor)
{
- column.setContraint(Contraint::PrimaryKey);
+ column = Sqlite::Column{"table",
+ "column",
+ ColumnType::Text,
+ {ForeignKey{"referencedTable",
+ "referencedColumn",
+ ForeignKeyAction::SetNull,
+ ForeignKeyAction::Cascade,
+ Enforment::Deferred}}};
- ASSERT_THAT(column.constraint(), Contraint::PrimaryKey);
+ ASSERT_THAT(column,
+ AllOf(Field(&Column::name, Eq("column")),
+ Field(&Column::tableName, Eq("table")),
+ Field(&Column::type, ColumnType::Text),
+ Field(&Column::constraints,
+ ElementsAre(VariantWith<ForeignKey>(
+ AllOf(Field(&ForeignKey::table, Eq("referencedTable")),
+ Field(&ForeignKey::column, Eq("referencedColumn")),
+ Field(&ForeignKey::updateAction, ForeignKeyAction::SetNull),
+ Field(&ForeignKey::deleteAction, ForeignKeyAction::Cascade),
+ Field(&ForeignKey::enforcement, Enforment::Deferred)))))));
}
-TEST_F(SqliteColumn, GetColumnDefinition)
+TEST_F(SqliteColumn, FlatConstructor)
{
- column.setName("Claudia");
+ column = Sqlite::Column{"table",
+ "column",
+ ColumnType::Text,
+ {ForeignKey{"referencedTable",
+ "referencedColumn",
+ ForeignKeyAction::SetNull,
+ ForeignKeyAction::Cascade,
+ Enforment::Deferred}}};
ASSERT_THAT(column,
- AllOf(
- Property(&Column::name, "Claudia"),
- Property(&Column::type, ColumnType::Numeric),
- Property(&Column::constraint, Contraint::NoConstraint)));
-}
-
-void SqliteColumn::SetUp()
-{
- column.clear();
+ AllOf(Field(&Column::name, Eq("column")),
+ Field(&Column::tableName, Eq("table")),
+ Field(&Column::type, ColumnType::Text),
+ Field(&Column::constraints,
+ ElementsAre(VariantWith<ForeignKey>(
+ AllOf(Field(&ForeignKey::table, Eq("referencedTable")),
+ Field(&ForeignKey::column, Eq("referencedColumn")),
+ Field(&ForeignKey::updateAction, ForeignKeyAction::SetNull),
+ Field(&ForeignKey::deleteAction, ForeignKeyAction::Cascade),
+ Field(&ForeignKey::enforcement, Enforment::Deferred)))))));
}
-}
+} // namespace
diff --git a/tests/unit/unittest/sqlitedatabase-test.cpp b/tests/unit/unittest/sqlitedatabase-test.cpp
index 66c1aa8387..5d7fdb1e54 100644
--- a/tests/unit/unittest/sqlitedatabase-test.cpp
+++ b/tests/unit/unittest/sqlitedatabase-test.cpp
@@ -28,6 +28,7 @@
#include "spydummy.h"
#include <sqlitedatabase.h>
+#include <sqlitereadstatement.h>
#include <sqlitetable.h>
#include <sqlitewritestatement.h>
#include <utf8string.h>
@@ -50,27 +51,36 @@ using Sqlite::Table;
class SqliteDatabase : public ::testing::Test
{
protected:
- void SetUp() override
+ SqliteDatabase()
{
database.setJournalMode(JournalMode::Memory);
database.setDatabaseFilePath(databaseFilePath);
auto &table = database.addTable();
table.setName("test");
+ table.addColumn("id", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
table.addColumn("name");
database.open();
}
- void TearDown() override
+ ~SqliteDatabase()
{
if (database.isOpen())
database.close();
}
+ std::vector<Utils::SmallString> names() const
+ {
+ return Sqlite::ReadStatement("SELECT name FROM test", database).values<Utils::SmallString>(8);
+ }
+
+protected:
SpyDummy spyDummy;
QString databaseFilePath{":memory:"};
- Sqlite::Database database;
+ mutable Sqlite::Database database;
Sqlite::TransactionInterface &transactionInterface = database;
+ MockFunction<void(Sqlite::ChangeType tupe, char const *, char const *, long long)> callbackMock;
+ Sqlite::Database::UpdateCallback callback = callbackMock.AsStdFunction();
};
TEST_F(SqliteDatabase, SetDatabaseFilePath)
@@ -220,4 +230,118 @@ TEST_F(SqliteDatabase, Rollback)
ASSERT_NO_THROW(transactionInterface.rollback());
}
+TEST_F(SqliteDatabase, SetUpdateHookSet)
+{
+ database.setUpdateHook(callback);
+
+ EXPECT_CALL(callbackMock, Call(_, _, _, _));
+ Sqlite::WriteStatement("INSERT INTO test(name) VALUES (?)", database).write(42);
+}
+
+TEST_F(SqliteDatabase, SetNullUpdateHook)
+{
+ database.setUpdateHook(callback);
+ Sqlite::Database::UpdateCallback newCallback;
+
+ database.setUpdateHook(newCallback);
+
+ EXPECT_CALL(callbackMock, Call(_, _, _, _)).Times(0);
+ Sqlite::WriteStatement("INSERT INTO test(name) VALUES (?)", database).write(42);
+}
+
+TEST_F(SqliteDatabase, ResetUpdateHook)
+{
+ database.setUpdateHook(callback);
+ Sqlite::Database::UpdateCallback newCallback;
+
+ database.resetUpdateHook();
+
+ EXPECT_CALL(callbackMock, Call(_, _, _, _)).Times(0);
+ Sqlite::WriteStatement("INSERT INTO test(name) VALUES (?)", database).write(42);
+}
+
+TEST_F(SqliteDatabase, DeleteUpdateHookCall)
+{
+ Sqlite::WriteStatement("INSERT INTO test(name) VALUES (?)", database).write(42);
+ database.setUpdateHook(callback);
+
+ EXPECT_CALL(callbackMock, Call(Eq(Sqlite::ChangeType::Delete), _, _, _));
+
+ Sqlite::WriteStatement("DELETE FROM test WHERE name = 42", database).execute();
}
+
+TEST_F(SqliteDatabase, InsertUpdateHookCall)
+{
+ database.setUpdateHook(callback);
+
+ EXPECT_CALL(callbackMock, Call(Eq(Sqlite::ChangeType::Insert), _, _, _));
+
+ Sqlite::WriteStatement("INSERT INTO test(name) VALUES (?)", database).write(42);
+}
+
+TEST_F(SqliteDatabase, UpdateUpdateHookCall)
+{
+ database.setUpdateHook(callback);
+
+ EXPECT_CALL(callbackMock, Call(Eq(Sqlite::ChangeType::Insert), _, _, _));
+
+ Sqlite::WriteStatement("INSERT INTO test(name) VALUES (?)", database).write(42);
+}
+
+TEST_F(SqliteDatabase, RowIdUpdateHookCall)
+{
+ database.setUpdateHook(callback);
+
+ EXPECT_CALL(callbackMock, Call(_, _, _, Eq(42)));
+
+ Sqlite::WriteStatement("INSERT INTO test(rowid, name) VALUES (?,?)", database).write(42, "foo");
+}
+
+TEST_F(SqliteDatabase, DatabaseUpdateHookCall)
+{
+ database.setUpdateHook(callback);
+
+ EXPECT_CALL(callbackMock, Call(_, StrEq("main"), _, _));
+
+ Sqlite::WriteStatement("INSERT INTO test(name) VALUES (?)", database).write(42);
+}
+
+TEST_F(SqliteDatabase, TableUpdateHookCall)
+{
+ database.setUpdateHook(callback);
+
+ EXPECT_CALL(callbackMock, Call(_, _, StrEq("test"), _));
+
+ Sqlite::WriteStatement("INSERT INTO test(name) VALUES (?)", database).write(42);
+}
+
+TEST_F(SqliteDatabase, SessionsCommit)
+{
+ database.setAttachedTables({"test"});
+ Sqlite::WriteStatement("INSERT INTO test(id, name) VALUES (?,?)", database).write(1, "foo");
+
+ Sqlite::ImmediateSessionTransaction transaction{database};
+ Sqlite::WriteStatement("INSERT INTO test(id, name) VALUES (?,?)", database).write(2, "bar");
+ transaction.commit();
+ Sqlite::WriteStatement("INSERT OR REPLACE INTO test(id, name) VALUES (?,?)", database).write(2, "hoo");
+ database.applyAndUpdateSessions();
+
+ ASSERT_THAT(names(), ElementsAre("foo", "bar"));
+}
+
+TEST_F(SqliteDatabase, SessionsRollback)
+{
+ database.setAttachedTables({"test"});
+ Sqlite::WriteStatement("INSERT INTO test(id, name) VALUES (?,?)", database).write(1, "foo");
+
+ {
+ Sqlite::ImmediateSessionTransaction transaction{database};
+ Sqlite::WriteStatement("INSERT INTO test(id, name) VALUES (?,?)", database).write(2, "bar");
+ }
+ Sqlite::WriteStatement("INSERT OR REPLACE INTO test(id, name) VALUES (?,?)", database).write(2, "hoo");
+ database.applyAndUpdateSessions();
+
+ ASSERT_THAT(names(), ElementsAre("foo", "hoo"));
+}
+
+} // namespace
diff --git a/tests/unit/unittest/sqlitedatabasebackend-test.cpp b/tests/unit/unittest/sqlitedatabasebackend-test.cpp
index 40227148bc..2390bd4a3c 100644
--- a/tests/unit/unittest/sqlitedatabasebackend-test.cpp
+++ b/tests/unit/unittest/sqlitedatabasebackend-test.cpp
@@ -39,10 +39,9 @@ namespace {
using Backend = Sqlite::DatabaseBackend;
using Sqlite::ColumnType;
-using Sqlite::Contraint;
+using Sqlite::ConstraintType;
using Sqlite::JournalMode;
using Sqlite::OpenMode;
-using Sqlite::TextEncoding;
using Sqlite::Exception;
using Sqlite::WriteStatement;
@@ -111,49 +110,6 @@ TEST_F(SqliteDatabaseBackend, PersistJournalMode)
ASSERT_THAT(databaseBackend.journalMode(), JournalMode::Persist);
}
-TEST_F(SqliteDatabaseBackend, DefaultTextEncoding)
-{
- ASSERT_THAT(databaseBackend.textEncoding(), TextEncoding::Utf8);
-}
-
-TEST_F(SqliteDatabaseBackend, Utf16TextEncoding)
-{
- databaseBackend.setTextEncoding(TextEncoding::Utf16);
-
- ASSERT_THAT(databaseBackend.textEncoding(), TextEncoding::Utf16);
-}
-
-TEST_F(SqliteDatabaseBackend, Utf16beTextEncoding)
-{
- databaseBackend.setTextEncoding(TextEncoding::Utf16be);
-
- ASSERT_THAT(databaseBackend.textEncoding(),TextEncoding::Utf16be);
-}
-
-TEST_F(SqliteDatabaseBackend, Utf16leTextEncoding)
-{
- databaseBackend.setTextEncoding(TextEncoding::Utf16le);
-
- ASSERT_THAT(databaseBackend.textEncoding(), TextEncoding::Utf16le);
-}
-
-TEST_F(SqliteDatabaseBackend, Utf8TextEncoding)
-{
- databaseBackend.setTextEncoding(TextEncoding::Utf8);
-
- ASSERT_THAT(databaseBackend.textEncoding(), TextEncoding::Utf8);
-}
-
-TEST_F(SqliteDatabaseBackend, TextEncodingCannotBeChangedAfterTouchingDatabase)
-{
- databaseBackend.setJournalMode(JournalMode::Memory);
-
- databaseBackend.execute("CREATE TABLE text(name, number)");
-
- ASSERT_THROW(databaseBackend.setTextEncoding(TextEncoding::Utf16),
- Sqlite::PragmaValueNotSet);
-}
-
TEST_F(SqliteDatabaseBackend, OpenModeReadOnly)
{
auto mode = Backend::openMode(OpenMode::ReadOnly);
diff --git a/tests/unit/unittest/sqlitesessions-test.cpp b/tests/unit/unittest/sqlitesessions-test.cpp
new file mode 100644
index 0000000000..f10dde1bc8
--- /dev/null
+++ b/tests/unit/unittest/sqlitesessions-test.cpp
@@ -0,0 +1,443 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "googletest.h"
+
+#include <sqlitedatabase.h>
+#include <sqlitereadstatement.h>
+#include <sqlitesessionchangeset.h>
+#include <sqlitesessions.h>
+#include <sqlitetransaction.h>
+#include <sqlitewritestatement.h>
+
+#include <ostream>
+
+namespace {
+
+using Sqlite::SessionChangeSet;
+using Sqlite::SessionChangeSets;
+
+class DatabaseExecute
+{
+public:
+ DatabaseExecute(Utils::SmallStringView sqlStatement, Sqlite::Database &database)
+ {
+ database.execute(sqlStatement);
+ }
+};
+
+class Data
+{
+public:
+ Data(Sqlite::ValueView name, Sqlite::ValueView number, Sqlite::ValueView value)
+ : name(name)
+ , number(number)
+ , value(value)
+ {}
+
+ Sqlite::Value name;
+ Sqlite::Value number;
+ Sqlite::Value value;
+};
+
+std::ostream &operator<<(std::ostream &out, const Data &data)
+{
+ return out << "(" << data.name << ", " << data.number << " " << data.value << ")";
+}
+
+MATCHER_P3(HasData,
+ name,
+ number,
+ value,
+ std::string(negation ? "hasn't " : "has ") + PrintToString(name) + ", "
+ + PrintToString(number) + ", " + PrintToString(value))
+{
+ const Data &data = arg;
+
+ return data.name == name && data.number == number && data.value == value;
+}
+
+class Tag
+{
+public:
+ Tag(Sqlite::ValueView name, Sqlite::ValueView tag)
+ : name(name)
+ , tag(tag)
+ {}
+
+ Sqlite::Value name;
+ Sqlite::Value tag;
+};
+
+std::ostream &operator<<(std::ostream &out, const Tag &tag)
+{
+ return out << "(" << tag.name << ", " << tag.tag << ")";
+}
+
+MATCHER_P2(HasTag,
+ name,
+ tag,
+ std::string(negation ? "hasn't " : "has ") + PrintToString(name) + ", " + PrintToString(tag))
+{
+ const Tag &t = arg;
+
+ return t.name == name && t.tag == tag;
+}
+
+class Sessions : public testing::Test
+{
+protected:
+ Sessions() { sessions.setAttachedTables({"data", "tags"}); }
+
+ std::vector<Data> fetchData() { return selectData.values<Data, 3>(8); }
+ std::vector<Tag> fetchTags() { return selectTags.values<Tag, 2>(8); }
+ SessionChangeSets fetchChangeSets() { return selectChangeSets.values<SessionChangeSet>(8); }
+
+protected:
+ Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
+ DatabaseExecute createTable{"CREATE TABLE data(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT "
+ "UNIQUE, number NUMERIC, value NUMERIC)",
+ database};
+ DatabaseExecute createTable2{"CREATE TABLE tags(id INTEGER PRIMARY KEY AUTOINCREMENT, dataId "
+ "INTEGER NOT NULL REFERENCES data ON DELETE CASCADE DEFERRABLE "
+ "INITIALLY DEFERRED, tag NUMERIC)",
+ database};
+ Sqlite::Sessions sessions{database, "main", "testsessions"};
+ Sqlite::WriteStatement insertData{"INSERT INTO data(name, number, value) VALUES (?1, ?2, ?3) "
+ "ON CONFLICT (name) DO UPDATE SET (number, value) = (?2, ?3)",
+ database};
+ Sqlite::WriteStatement updateNumber{"UPDATE data SET number = ?002 WHERE name=?001", database};
+ Sqlite::WriteStatement updateValue{"UPDATE data SET value = ?002 WHERE name=?001", database};
+ Sqlite::WriteStatement deleteData{"DELETE FROM data WHERE name=?", database};
+ Sqlite::WriteStatement deleteTag{
+ "DELETE FROM tags WHERE dataId=(SELECT id FROM data WHERE name=?)", database};
+ Sqlite::WriteStatement insertTag{
+ "INSERT INTO tags(dataId, tag) VALUES ((SELECT id FROM data WHERE name=?1), ?2) ", database};
+ Sqlite::ReadStatement selectData{"SELECT name, number, value FROM data", database};
+ Sqlite::ReadStatement selectTags{"SELECT name, tag FROM tags JOIN data ON data.id=tags.dataId",
+ database};
+ Sqlite::ReadStatement selectChangeSets{"SELECT changeset FROM testsessions", database};
+};
+
+TEST_F(Sessions, DontThrowForCommittingWithoutSessionStart)
+{
+ ASSERT_NO_THROW(sessions.commit());
+}
+
+TEST_F(Sessions, CreateEmptySession)
+{
+ sessions.create();
+ sessions.commit();
+
+ ASSERT_THAT(fetchChangeSets(), IsEmpty());
+}
+
+TEST_F(Sessions, CreateSessionWithInsert)
+{
+ sessions.create();
+ insertData.write("foo", 22, 3.14);
+ sessions.commit();
+
+ ASSERT_THAT(fetchChangeSets(), SizeIs(1));
+}
+
+TEST_F(Sessions, CreateSessionWithUpdate)
+{
+ insertData.write("foo", 22, 3.14);
+
+ sessions.create();
+ updateNumber.write("foo", "bar");
+ sessions.commit();
+
+ ASSERT_THAT(fetchChangeSets(), SizeIs(1));
+}
+
+TEST_F(Sessions, CreateSessionWithDelete)
+{
+ insertData.write("foo", 22, 3.14);
+
+ sessions.create();
+ deleteData.write("foo");
+ sessions.commit();
+
+ ASSERT_THAT(fetchChangeSets(), SizeIs(1));
+}
+
+TEST_F(Sessions, CreateSessionWithInsertAndUpdate)
+{
+ sessions.create();
+ insertData.write("foo", 22, 3.14);
+ sessions.commit();
+
+ sessions.create();
+ updateNumber.write("foo", "bar");
+ sessions.commit();
+
+ ASSERT_THAT(fetchChangeSets(), SizeIs(2));
+}
+
+TEST_F(Sessions, CreateSession)
+{
+ sessions.create();
+ insertData.write("foo", 22, 3.14);
+
+ sessions.commit();
+
+ ASSERT_THAT(fetchChangeSets(), SizeIs(1));
+}
+
+TEST_F(Sessions, RevertSession)
+{
+ sessions.create();
+ insertData.write("foo", 22, 3.14);
+ sessions.commit();
+
+ sessions.revert();
+
+ ASSERT_THAT(fetchData(), IsEmpty());
+}
+
+TEST_F(Sessions, RevertSessionToBase)
+{
+ insertData.write("bar", "foo", 99);
+ sessions.create();
+ insertData.write("foo", 22, 3.14);
+ sessions.commit();
+
+ sessions.revert();
+
+ ASSERT_THAT(fetchData(), ElementsAre(HasData("bar", "foo", 99)));
+}
+
+TEST_F(Sessions, RevertMultipleSession)
+{
+ sessions.create();
+ insertData.write("foo", 22, 3.14);
+ sessions.commit();
+ sessions.create();
+ updateNumber.write("foo", "bar");
+ sessions.commit();
+
+ sessions.revert();
+
+ ASSERT_THAT(fetchData(), IsEmpty());
+}
+
+TEST_F(Sessions, ApplySession)
+{
+ sessions.create();
+ insertData.write("foo", 22, 3.14);
+ sessions.commit();
+
+ sessions.apply();
+
+ ASSERT_THAT(fetchData(), ElementsAre(HasData("foo", 22, 3.14)));
+}
+
+TEST_F(Sessions, ApplySessionAfterAddingNewEntries)
+{
+ sessions.create();
+ insertData.write("foo", 22, 3.14);
+ sessions.commit();
+ insertData.write("bar", "foo", 99);
+
+ sessions.apply();
+
+ ASSERT_THAT(fetchData(),
+ UnorderedElementsAre(HasData("foo", 22, 3.14), HasData("bar", "foo", 99)));
+}
+
+TEST_F(Sessions, ApplyOverridesEntriesWithUniqueConstraint)
+{
+ sessions.create();
+ insertData.write("foo", 22, 3.14);
+ sessions.commit();
+ insertData.write("foo", "bar", 3.14);
+
+ sessions.apply();
+
+ ASSERT_THAT(fetchData(), ElementsAre(HasData("foo", 22, 3.14)));
+}
+
+TEST_F(Sessions, ApplyDoesNotOverrideDeletedEntries)
+{
+ insertData.write("foo", "bar", 3.14);
+ sessions.create();
+ insertData.write("foo", 22, 3.14);
+ sessions.commit();
+ deleteData.write("foo");
+
+ sessions.apply();
+
+ ASSERT_THAT(fetchData(), IsEmpty());
+}
+
+TEST_F(Sessions, ApplyDoesOnlyOverwriteUpdatedValues)
+{
+ insertData.write("foo", "bar", 3.14);
+ sessions.create();
+ updateValue.write("foo", 1234);
+ sessions.commit();
+ insertData.write("foo", "poo", 891);
+
+ sessions.apply();
+
+ ASSERT_THAT(fetchData(), ElementsAre(HasData("foo", "poo", 1234)));
+}
+
+TEST_F(Sessions, ApplyDoesDoesNotOverrideForeignKeyIfReferenceIsDeleted)
+{
+ insertData.write("foo2", "bar", 3.14);
+ insertData.write("foo", "bar", 3.14);
+ sessions.create();
+ insertTag.write("foo2", 4321);
+ insertTag.write("foo", 1234);
+ sessions.commit();
+ deleteData.write("foo");
+
+ sessions.apply();
+
+ ASSERT_THAT(fetchTags(), ElementsAre(HasTag("foo2", 4321)));
+}
+
+TEST_F(Sessions, ApplyDoesDoesNotOverrideIfConstraintsIsApplied)
+{
+ insertData.write("foo", "bar", 3.14);
+ sessions.create();
+ deleteData.write("foo");
+ sessions.commit();
+ sessions.revert();
+ insertTag.write("foo", 1234);
+
+ sessions.apply();
+
+ ASSERT_THAT(fetchTags(), IsEmpty());
+}
+
+TEST_F(Sessions, ApplyDoesDoesNotOverrideForeignKeyIfReferenceIsDeletedDeferred)
+{
+ Sqlite::DeferredTransaction transaction{database};
+ insertData.write("foo2", "bar", 3.14);
+ insertData.write("foo", "bar", 3.14);
+ sessions.create();
+ insertTag.write("foo2", 4321);
+ insertTag.write("foo", 1234);
+ sessions.commit();
+ deleteData.write("foo");
+
+ sessions.apply();
+
+ transaction.commit();
+ ASSERT_THAT(fetchTags(), ElementsAre(HasTag("foo2", 4321)));
+}
+
+TEST_F(Sessions, EndSessionOnRollback)
+{
+ insertData.write("foo", "bar", 3.14);
+ sessions.create();
+ updateValue.write("foo", 99);
+ sessions.rollback();
+ sessions.commit();
+ sessions.create();
+ updateNumber.write("foo", 333);
+ sessions.commit();
+ updateValue.write("foo", 666);
+
+ sessions.apply();
+
+ ASSERT_THAT(fetchData(), ElementsAre(HasData("foo", 333, 666)));
+}
+
+TEST_F(Sessions, EndSessionOnCommit)
+{
+ insertData.write("foo", "bar", 3.14);
+ sessions.create();
+ updateValue.write("foo", 99);
+ sessions.commit();
+ updateValue.write("foo", 666);
+ sessions.commit();
+
+ sessions.apply();
+
+ ASSERT_THAT(fetchData(), ElementsAre(HasData("foo", "bar", 99)));
+}
+
+TEST_F(Sessions, DeleteSessions)
+{
+ insertData.write("foo", "bar", 3.14);
+ sessions.create();
+ updateValue.write("foo", 99);
+ sessions.commit();
+ sessions.revert();
+
+ sessions.deleteAll();
+
+ sessions.apply();
+ ASSERT_THAT(fetchData(), ElementsAre(HasData("foo", "bar", 3.14)));
+}
+
+TEST_F(Sessions, DeleteAllSessions)
+{
+ insertData.write("foo", "bar", 3.14);
+ sessions.create();
+ updateValue.write("foo", 99);
+ sessions.commit();
+ sessions.revert();
+
+ sessions.deleteAll();
+
+ sessions.apply();
+ ASSERT_THAT(fetchData(), ElementsAre(HasData("foo", "bar", 3.14)));
+}
+
+TEST_F(Sessions, ApplyAndUpdateSessions)
+{
+ insertData.write("foo", "bar", 3.14);
+ sessions.create();
+ updateValue.write("foo", 99);
+ sessions.commit();
+ updateValue.write("foo", 99);
+
+ sessions.applyAndUpdateSessions();
+
+ updateValue.write("foo", 22);
+ sessions.apply();
+ ASSERT_THAT(fetchData(), ElementsAre(HasData("foo", "bar", 22)));
+}
+
+TEST_F(Sessions, ApplyAndUpdateSessionsHasOnlyOneChangeSet)
+{
+ insertData.write("foo", "bar", 3.14);
+ sessions.create();
+ updateValue.write("foo", 99);
+ sessions.commit();
+ updateValue.write("foo", 99);
+
+ sessions.applyAndUpdateSessions();
+
+ ASSERT_THAT(fetchChangeSets(), SizeIs(1));
+}
+
+} // namespace
diff --git a/tests/unit/unittest/sqlitestatement-test.cpp b/tests/unit/unittest/sqlitestatement-test.cpp
index c7da3971e4..a7dd5d5f9b 100644
--- a/tests/unit/unittest/sqlitestatement-test.cpp
+++ b/tests/unit/unittest/sqlitestatement-test.cpp
@@ -38,6 +38,14 @@
#include <vector>
+namespace Sqlite {
+bool operator==(Utils::span<const byte> first, Utils::span<const byte> second)
+{
+ return first.size() == second.size()
+ && std::memcmp(first.data(), second.data(), first.size()) == 0;
+}
+} // namespace Sqlite
+
namespace {
using Sqlite::Database;
@@ -66,11 +74,33 @@ MATCHER_P3(HasValues, value1, value2, rowid,
&& statement.fetchSmallStringViewValue(1) == value2;
}
+MATCHER_P(HasNullValues, rowid, std::string(negation ? "isn't null" : "is null"))
+{
+ Database &database = arg.database();
+
+ SqliteTestStatement statement("SELECT name, number FROM test WHERE rowid=?", database);
+ statement.bind(1, rowid);
+
+ statement.next();
+
+ return statement.fetchValueView(0).isNull() && statement.fetchValueView(1).isNull();
+}
+
class SqliteStatement : public ::testing::Test
{
protected:
- void SetUp() override;
- void TearDown() override;
+ void SetUp() override
+ {
+ database.execute("CREATE TABLE test(name TEXT UNIQUE, number NUMERIC, value NUMERIC)");
+ database.execute("INSERT INTO test VALUES ('bar', 'blah', 1)");
+ database.execute("INSERT INTO test VALUES ('foo', 23.3, 2)");
+ database.execute("INSERT INTO test VALUES ('poo', 40, 3)");
+ }
+ void TearDown() override
+ {
+ if (database.isOpen())
+ database.close();
+ }
protected:
Database database{":memory:", Sqlite::JournalMode::Memory};
@@ -148,37 +178,6 @@ TEST_F(SqliteStatement, Value)
ASSERT_THAT(statement.fetchValueView(2), Eq(2));
}
-TEST_F(SqliteStatement, ThrowNoValuesToFetchForNotSteppedStatement)
-{
- SqliteTestStatement statement("SELECT name, number FROM test", database);
-
- ASSERT_THROW(statement.fetchValue<int>(0), Sqlite::NoValuesToFetch);
-}
-
-TEST_F(SqliteStatement, ThrowNoValuesToFetchForDoneStatement)
-{
- SqliteTestStatement statement("SELECT name, number FROM test", database);
- while (statement.next()) {}
-
- ASSERT_THROW(statement.fetchValue<int>(0), Sqlite::NoValuesToFetch);
-}
-
-TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForNegativeColumn)
-{
- SqliteTestStatement statement("SELECT name, number FROM test", database);
- statement.next();
-
- ASSERT_THROW(statement.fetchValue<int>(-1), Sqlite::InvalidColumnFetched);
-}
-
-TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForNotExistingColumn)
-{
- SqliteTestStatement statement("SELECT name, number FROM test", database);
- statement.next();
-
- ASSERT_THROW(statement.fetchValue<int>(2), Sqlite::InvalidColumnFetched);
-}
-
TEST_F(SqliteStatement, ToIntegerValue)
{
auto value = ReadStatement::toValue<int>("SELECT number FROM test WHERE name='foo'", database);
@@ -201,13 +200,16 @@ TEST_F(SqliteStatement, ToStringValue)
ASSERT_THAT(ReadStatement::toValue<Utils::SmallString>("SELECT name FROM test WHERE name='foo'", database), "foo");
}
-TEST_F(SqliteStatement, ColumnNames)
+TEST_F(SqliteStatement, BindNull)
{
- SqliteTestStatement statement("SELECT name, number FROM test", database);
+ database.execute("INSERT INTO test VALUES (NULL, 323, 344)");
+ SqliteTestStatement statement("SELECT name, number FROM test WHERE name IS ?", database);
- auto columnNames = statement.columnNames();
+ statement.bind(1, Sqlite::NullValue{});
+ statement.next();
- ASSERT_THAT(columnNames, ElementsAre("name", "number"));
+ ASSERT_TRUE(statement.fetchValueView(0).isNull());
+ ASSERT_THAT(statement.fetchValue<int>(1), 323);
}
TEST_F(SqliteStatement, BindString)
@@ -216,7 +218,6 @@ TEST_F(SqliteStatement, BindString)
SqliteTestStatement statement("SELECT name, number FROM test WHERE name=?", database);
statement.bind(1, "foo");
-
statement.next();
ASSERT_THAT(statement.fetchSmallStringViewValue(0), "foo");
@@ -253,55 +254,96 @@ TEST_F(SqliteStatement, BindDouble)
ASSERT_THAT(statement.fetchSmallStringViewValue(0), "foo");
}
-TEST_F(SqliteStatement, BindIntegerByParameter)
+TEST_F(SqliteStatement, BindPointer)
{
- SqliteTestStatement statement("SELECT name, number FROM test WHERE number=@number", database);
+ SqliteTestStatement statement("SELECT value FROM carray(?, 5, 'int64')", database);
+ std::vector<long long> values{1, 1, 2, 3, 5};
- statement.bind("@number", 40);
+ statement.bind(1, values.data());
statement.next();
- ASSERT_THAT(statement.fetchSmallStringViewValue(0), "poo");
+ ASSERT_THAT(statement.fetchIntValue(0), 1);
}
-TEST_F(SqliteStatement, BindLongIntegerByParameter)
+TEST_F(SqliteStatement, BindBlob)
{
- SqliteTestStatement statement("SELECT name, number FROM test WHERE number=@number", database);
+ SqliteTestStatement statement("WITH T(blob) AS (VALUES (?)) SELECT blob FROM T", database);
+ const unsigned char chars[] = "aaafdfdlll";
+ auto bytePointer = reinterpret_cast<const Sqlite::byte *>(chars);
+ Utils::span<const Sqlite::byte> bytes{bytePointer, sizeof(chars) - 1};
- statement.bind("@number", int64_t(40));
+ statement.bind(1, bytes);
statement.next();
- ASSERT_THAT(statement.fetchSmallStringViewValue(0), "poo");
+ ASSERT_THAT(statement.fetchBlobValue(0), Eq(bytes));
}
-TEST_F(SqliteStatement, BindDoubleByIndex)
+TEST_F(SqliteStatement, BindEmptyBlob)
{
- SqliteTestStatement statement("SELECT name, number FROM test WHERE number=@number", database);
+ SqliteTestStatement statement("WITH T(blob) AS (VALUES (?)) SELECT blob FROM T", database);
+ Utils::span<const Sqlite::byte> bytes;
- statement.bind(statement.bindingIndexForName("@number"), 23.3);
+ statement.bind(1, bytes);
statement.next();
- ASSERT_THAT(statement.fetchSmallStringViewValue(0), "foo");
+ ASSERT_THAT(statement.fetchBlobValue(0), IsEmpty());
}
-TEST_F(SqliteStatement, BindIndexIsZeroIsThrowingBindingIndexIsOutOfBound)
+TEST_F(SqliteStatement, BindIndexIsZeroIsThrowingBindingIndexIsOutOfBoundInt)
{
SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database);
ASSERT_THROW(statement.bind(0, 40), Sqlite::BindingIndexIsOutOfRange);
}
-TEST_F(SqliteStatement, BindIndexIsTpLargeIsThrowingBindingIndexIsOutOfBound)
+TEST_F(SqliteStatement, BindIndexIsZeroIsThrowingBindingIndexIsOutOfBoundNull)
+{
+ SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database);
+
+ ASSERT_THROW(statement.bind(0, Sqlite::NullValue{}), Sqlite::BindingIndexIsOutOfRange);
+}
+
+TEST_F(SqliteStatement, BindIndexIsToLargeIsThrowingBindingIndexIsOutOfBoundLongLong)
+{
+ SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database);
+
+ ASSERT_THROW(statement.bind(2, 40LL), Sqlite::BindingIndexIsOutOfRange);
+}
+
+TEST_F(SqliteStatement, BindIndexIsToLargeIsThrowingBindingIndexIsOutOfBoundStringView)
{
SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database);
- ASSERT_THROW(statement.bind(2, 40), Sqlite::BindingIndexIsOutOfRange);
+ ASSERT_THROW(statement.bind(2, "foo"), Sqlite::BindingIndexIsOutOfRange);
}
-TEST_F(SqliteStatement, WrongBindingNameThrowingBindingIndexIsOutOfBound)
+TEST_F(SqliteStatement, BindIndexIsToLargeIsThrowingBindingIndexIsOutOfBoundStringFloat)
{
- SqliteTestStatement statement("SELECT name, number FROM test WHERE number=@name", database);
+ SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database);
+
+ ASSERT_THROW(statement.bind(2, 2.), Sqlite::BindingIndexIsOutOfRange);
+}
+
+TEST_F(SqliteStatement, BindIndexIsToLargeIsThrowingBindingIndexIsOutOfBoundPointer)
+{
+ SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database);
+
+ ASSERT_THROW(statement.bind(2, nullptr), Sqlite::BindingIndexIsOutOfRange);
+}
+
+TEST_F(SqliteStatement, BindIndexIsToLargeIsThrowingBindingIndexIsOutOfBoundValue)
+{
+ SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database);
- ASSERT_THROW(statement.bind("@name2", 40), Sqlite::WrongBindingName);
+ ASSERT_THROW(statement.bind(2, Sqlite::Value{1}), Sqlite::BindingIndexIsOutOfRange);
+}
+
+TEST_F(SqliteStatement, BindIndexIsToLargeIsThrowingBindingIndexIsOutOfBoundBlob)
+{
+ SqliteTestStatement statement("WITH T(blob) AS (VALUES (?)) SELECT blob FROM T", database);
+ Utils::span<const Sqlite::byte> bytes;
+
+ ASSERT_THROW(statement.bind(2, bytes), Sqlite::BindingIndexIsOutOfRange);
}
TEST_F(SqliteStatement, BindValues)
@@ -314,6 +356,16 @@ TEST_F(SqliteStatement, BindValues)
ASSERT_THAT(statement, HasValues("see", "7.23", 1));
}
+TEST_F(SqliteStatement, BindNullValues)
+{
+ SqliteTestStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database);
+
+ statement.bindValues(Sqlite::NullValue{}, Sqlite::Value{}, 1);
+ statement.execute();
+
+ ASSERT_THAT(statement, HasNullValues(1));
+}
+
TEST_F(SqliteStatement, WriteValues)
{
WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database);
@@ -323,6 +375,25 @@ TEST_F(SqliteStatement, WriteValues)
ASSERT_THAT(statement, HasValues("see", "7.23", 1));
}
+TEST_F(SqliteStatement, WritePointerValues)
+{
+ SqliteTestStatement statement("SELECT value FROM carray(?, ?, 'int64')", database);
+ std::vector<long long> values{1, 1, 2, 3, 5};
+
+ statement.write(values.data(), int(values.size()));
+
+ ASSERT_THAT(statement.template values<int>(5), ElementsAre(1, 1, 2, 3, 5));
+}
+
+TEST_F(SqliteStatement, WriteNullValues)
+{
+ WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database);
+
+ statement.write(Sqlite::NullValue{}, Sqlite::Value{}, 1);
+
+ ASSERT_THAT(statement, HasNullValues(1));
+}
+
TEST_F(SqliteStatement, WriteSqliteValues)
{
WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database);
@@ -332,23 +403,38 @@ TEST_F(SqliteStatement, WriteSqliteValues)
ASSERT_THAT(statement, HasValues("see", "7.23", 1));
}
-TEST_F(SqliteStatement, BindNamedValues)
+TEST_F(SqliteStatement, WriteEmptyBlobs)
{
- SqliteTestStatement statement("UPDATE test SET name=@name, number=@number WHERE rowid=@id", database);
+ SqliteTestStatement statement("WITH T(blob) AS (VALUES (?)) SELECT blob FROM T", database);
- statement.bindNameValues("@name", "see", "@number", 7.23, "@id", 1);
- statement.execute();
+ Utils::span<const Sqlite::byte> bytes;
- ASSERT_THAT(statement, HasValues("see", "7.23", 1));
+ statement.write(bytes);
+
+ ASSERT_THAT(statement.fetchBlobValue(0), IsEmpty());
}
-TEST_F(SqliteStatement, WriteNamedValues)
+class Blob
{
- WriteStatement statement("UPDATE test SET name=@name, number=@number WHERE rowid=@id", database);
+public:
+ Blob(Utils::span<const Sqlite::byte> bytes)
+ : bytes(bytes.begin(), bytes.end())
+ {}
- statement.writeNamed("@name", "see", "@number", 7.23, "@id", 1);
+ std::vector<Sqlite::byte> bytes;
+};
- ASSERT_THAT(statement, HasValues("see", "7.23", 1));
+TEST_F(SqliteStatement, WriteBlobs)
+{
+ SqliteTestStatement statement("INSERT INTO test VALUES ('blob', 40, ?)", database);
+ SqliteTestStatement readStatement("SELECT value FROM test WHERE name = 'blob'", database);
+ const unsigned char chars[] = "aaafdfdlll";
+ auto bytePointer = reinterpret_cast<const Sqlite::byte *>(chars);
+ Utils::span<const Sqlite::byte> bytes{bytePointer, sizeof(chars) - 1};
+
+ statement.write(bytes);
+
+ ASSERT_THAT(readStatement.template value<Blob>(), Optional(Field(&Blob::bytes, Eq(bytes))));
}
TEST_F(SqliteStatement, CannotWriteToClosedDatabase)
@@ -374,9 +460,8 @@ TEST_F(SqliteStatement, GetTupleValuesWithoutArguments)
auto values = statement.values<Tuple, 3>(3);
- ASSERT_THAT(values, ElementsAre(Tuple{"bar", 0, 1},
- Tuple{"foo", 23.3, 2},
- Tuple{"poo", 40.0, 3}));
+ ASSERT_THAT(values,
+ UnorderedElementsAre(Tuple{"bar", 0, 1}, Tuple{"foo", 23.3, 2}, Tuple{"poo", 40.0, 3}));
}
TEST_F(SqliteStatement, GetSingleValuesWithoutArguments)
@@ -385,7 +470,7 @@ TEST_F(SqliteStatement, GetSingleValuesWithoutArguments)
std::vector<Utils::SmallString> values = statement.values<Utils::SmallString>(3);
- ASSERT_THAT(values, ElementsAre("bar", "foo", "poo"));
+ ASSERT_THAT(values, UnorderedElementsAre("bar", "foo", "poo"));
}
class FooValue
@@ -407,10 +492,11 @@ public:
TEST_F(SqliteStatement, GetSingleSqliteValuesWithoutArguments)
{
ReadStatement statement("SELECT number FROM test", database);
+ database.execute("INSERT INTO test VALUES (NULL, NULL, NULL)");
std::vector<FooValue> values = statement.values<FooValue>(3);
- ASSERT_THAT(values, ElementsAre(Eq("blah"), Eq(23.3), Eq(40)));
+ ASSERT_THAT(values, UnorderedElementsAre(Eq("blah"), Eq(23.3), Eq(40), IsNull()));
}
TEST_F(SqliteStatement, GetStructValuesWithoutArguments)
@@ -419,9 +505,10 @@ TEST_F(SqliteStatement, GetStructValuesWithoutArguments)
auto values = statement.values<Output, 3>(3);
- ASSERT_THAT(values, ElementsAre(Output{"bar", "blah", 1},
- Output{"foo", "23.3", 2},
- Output{"poo", "40", 3}));
+ ASSERT_THAT(values,
+ UnorderedElementsAre(Output{"bar", "blah", 1},
+ Output{"foo", "23.3", 2},
+ Output{"poo", "40", 3}));
}
TEST_F(SqliteStatement, GetValuesForSingleOutputWithBindingMultipleTimes)
@@ -442,18 +529,17 @@ TEST_F(SqliteStatement, GetValuesForMultipleOutputValuesAndContainerQueryValues)
auto values = statement.values<Tuple, 3>(3, queryValues);
- ASSERT_THAT(values, ElementsAre(Tuple{"poo", 40, 3.},
- Tuple{"foo", 23.3, 2.}));
+ ASSERT_THAT(values, UnorderedElementsAre(Tuple{"poo", 40, 3.}, Tuple{"foo", 23.3, 2.}));
}
TEST_F(SqliteStatement, GetValuesForSingleOutputValuesAndContainerQueryValues)
{
std::vector<double> queryValues = {40, 23.3};
- ReadStatement statement("SELECT name, number FROM test WHERE number=?", database);
+ ReadStatement statement("SELECT name FROM test WHERE number=?", database);
std::vector<Utils::SmallString> values = statement.values<Utils::SmallString>(3, queryValues);
- ASSERT_THAT(values, ElementsAre("poo", "foo"));
+ ASSERT_THAT(values, UnorderedElementsAre("poo", "foo"));
}
TEST_F(SqliteStatement, GetValuesForMultipleOutputValuesAndContainerQueryTupleValues)
@@ -465,19 +551,18 @@ TEST_F(SqliteStatement, GetValuesForMultipleOutputValuesAndContainerQueryTupleVa
auto values = statement.values<ResultTuple, 3>(3, queryValues);
- ASSERT_THAT(values, ElementsAre(ResultTuple{"poo", 40, 3},
- ResultTuple{"bar", 0, 1}));
+ ASSERT_THAT(values, UnorderedElementsAre(ResultTuple{"poo", 40, 3}, ResultTuple{"bar", 0, 1}));
}
TEST_F(SqliteStatement, GetValuesForSingleOutputValuesAndContainerQueryTupleValues)
{
using Tuple = std::tuple<Utils::SmallString, Utils::SmallString>;
std::vector<Tuple> queryValues = {{"poo", "40"}, {"bar", "blah"}};
- ReadStatement statement("SELECT name, number FROM test WHERE name= ? AND number=?", database);
+ ReadStatement statement("SELECT name FROM test WHERE name= ? AND number=?", database);
std::vector<Utils::SmallString> values = statement.values<Utils::SmallString>(3, queryValues);
- ASSERT_THAT(values, ElementsAre("poo", "bar"));
+ ASSERT_THAT(values, UnorderedElementsAre("poo", "bar"));
}
TEST_F(SqliteStatement, GetValuesForMultipleOutputValuesAndMultipleQueryValue)
@@ -529,8 +614,47 @@ TEST_F(SqliteStatement, GetStructOutputValuesAndContainerQueryTupleValues)
auto values = statement.values<Output, 3>(3, queryValues);
- ASSERT_THAT(values, ElementsAre(Output{"poo", "40", 3},
- Output{"bar", "blah", 1}));
+ ASSERT_THAT(values, UnorderedElementsAre(Output{"poo", "40", 3}, Output{"bar", "blah", 1}));
+}
+
+TEST_F(SqliteStatement, GetBlobValues)
+{
+ database.execute("INSERT INTO test VALUES ('blob', 40, x'AABBCCDD')");
+ ReadStatement statement("SELECT value FROM test WHERE name='blob'", database);
+ const int value = 0xDDCCBBAA;
+ auto bytePointer = reinterpret_cast<const Sqlite::byte *>(&value);
+ Utils::span<const Sqlite::byte> bytes{bytePointer, 4};
+
+ auto values = statement.values<Blob>(1);
+
+ ASSERT_THAT(values, ElementsAre(Field(&Blob::bytes, Eq(bytes))));
+}
+
+TEST_F(SqliteStatement, GetEmptyBlobValueForInteger)
+{
+ ReadStatement statement("SELECT value FROM test WHERE name='poo'", database);
+
+ auto value = statement.value<Blob>();
+
+ ASSERT_THAT(value, Optional(Field(&Blob::bytes, IsEmpty())));
+}
+
+TEST_F(SqliteStatement, GetEmptyBlobValueForFloat)
+{
+ ReadStatement statement("SELECT number FROM test WHERE name='foo'", database);
+
+ auto value = statement.value<Blob>();
+
+ ASSERT_THAT(value, Optional(Field(&Blob::bytes, IsEmpty())));
+}
+
+TEST_F(SqliteStatement, GetEmptyBlobValueForText)
+{
+ ReadStatement statement("SELECT number FROM test WHERE name='bar'", database);
+
+ auto value = statement.value<Blob>();
+
+ ASSERT_THAT(value, Optional(Field(&Blob::bytes, IsEmpty())));
}
TEST_F(SqliteStatement, GetOptionalSingleValueAndMultipleQueryValue)
@@ -688,41 +812,56 @@ TEST_F(SqliteStatement, ResetIfWriteIsThrowingException)
ASSERT_ANY_THROW(mockStatement.write("bar"));
}
-TEST_F(SqliteStatement, ResetIfWriteNamedIsThrowingException)
+TEST_F(SqliteStatement, ResetIfExecuteThrowsException)
{
MockSqliteStatement mockStatement;
- EXPECT_CALL(mockStatement, bindingIndexForName(TypedEq<Utils::SmallStringView>("@foo")))
- .WillOnce(Return(1));
- EXPECT_CALL(mockStatement, bind(1, TypedEq<Utils::SmallStringView>("bar")))
- .WillOnce(Throw(Sqlite::StatementIsBusy("")));
+ EXPECT_CALL(mockStatement, next()).WillOnce(Throw(Sqlite::StatementIsBusy("")));
EXPECT_CALL(mockStatement, reset());
- ASSERT_ANY_THROW(mockStatement.writeNamed("@foo", "bar"));
+ ASSERT_ANY_THROW(mockStatement.execute());
}
-TEST_F(SqliteStatement, ResetIfExecuteThrowsException)
+TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForToManyArgumentsForValue)
{
- MockSqliteStatement mockStatement;
+ SqliteTestStatement statement("SELECT name, number FROM test", database);
- EXPECT_CALL(mockStatement, next()).WillOnce(Throw(Sqlite::StatementIsBusy("")));
- EXPECT_CALL(mockStatement, reset());
+ ASSERT_THROW(statement.value<int>(), Sqlite::ColumnCountDoesNotMatch);
+}
- ASSERT_ANY_THROW(mockStatement.execute());
+TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForToManyArgumentsForValues)
+{
+ SqliteTestStatement statement("SELECT name, number FROM test", database);
+
+ ASSERT_THROW(statement.values<int>(1), Sqlite::ColumnCountDoesNotMatch);
+}
+
+TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForToManyArgumentsForValuesWithArguments)
+{
+ SqliteTestStatement statement("SELECT name, number FROM test WHERE name=?", database);
+
+ ASSERT_THROW(statement.values<int>(1, 2), Sqlite::ColumnCountDoesNotMatch);
}
-void SqliteStatement::SetUp()
+TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForToManyArgumentsForValuesWithVectorArguments)
{
- database.execute("CREATE TABLE test(name TEXT UNIQUE, number NUMERIC, value NUMERIC)");
- database.execute("INSERT INTO test VALUES ('bar', 'blah', 1)");
- database.execute("INSERT INTO test VALUES ('foo', 23.3, 2)");
- database.execute("INSERT INTO test VALUES ('poo', 40, 3)");
+ SqliteTestStatement statement("SELECT name, number FROM test", database);
+
+ ASSERT_THROW(statement.values<int>(1, std::vector<int>{}), Sqlite::ColumnCountDoesNotMatch);
}
-void SqliteStatement::TearDown()
+TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForToManyArgumentsForValuesWithTupleArguments)
{
- if (database.isOpen())
- database.close();
+ SqliteTestStatement statement("SELECT name, number FROM test", database);
+
+ ASSERT_THROW(statement.values<int>(1, std::vector<std::tuple<int>>{}),
+ Sqlite::ColumnCountDoesNotMatch);
}
+TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForToManyArgumentsForToValues)
+{
+ ASSERT_THROW(SqliteTestStatement::toValue<int>("SELECT name, number FROM test", database),
+ Sqlite::ColumnCountDoesNotMatch);
}
+
+} // namespace
diff --git a/tests/unit/unittest/sqlitetable-test.cpp b/tests/unit/unittest/sqlitetable-test.cpp
index c5ce8e325d..f96b451785 100644
--- a/tests/unit/unittest/sqlitetable-test.cpp
+++ b/tests/unit/unittest/sqlitetable-test.cpp
@@ -32,11 +32,15 @@
namespace {
+using Sqlite::Column;
using Sqlite::ColumnType;
+using Sqlite::ConstraintType;
+using Sqlite::Database;
+using Sqlite::Enforment;
+using Sqlite::ForeignKey;
+using Sqlite::ForeignKeyAction;
using Sqlite::JournalMode;
using Sqlite::OpenMode;
-using Sqlite::Column;
-using Sqlite::Database;
class SqliteTable : public ::testing::Test
{
@@ -110,21 +114,195 @@ TEST_F(SqliteTable, InitializeTableWithIndex)
table.initialize(mockDatabase);
}
+TEST_F(SqliteTable, AddForeignKeyColumnWithTableCalls)
+{
+ Sqlite::Table foreignTable;
+ foreignTable.setName("foreignTable");
+ table.setName(tableName);
+ table.addForeignKeyColumn("name",
+ foreignTable,
+ ForeignKeyAction::SetNull,
+ ForeignKeyAction::Cascade,
+ Enforment::Deferred);
+
+ EXPECT_CALL(mockDatabase,
+ execute(Eq("CREATE TABLE testTable(name INTEGER REFERENCES foreignTable ON UPDATE "
+ "SET NULL ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)")));
-TEST_F(SqliteTable, InitializeTableWithUniqueIndex)
+ table.initialize(mockDatabase);
+}
+
+TEST_F(SqliteTable, AddForeignKeyColumnWithColumnCalls)
{
- InSequence sequence;
- table.setName(tableName.clone());
- auto &column = table.addColumn("name");
- auto &column2 = table.addColumn("value");
- table.addUniqueIndex({column});
- table.addIndex({column2});
+ Sqlite::Table foreignTable;
+ foreignTable.setName("foreignTable");
+ auto &foreignColumn = foreignTable.addColumn("foreignColumn", ColumnType::Text, {Sqlite::Unique{}});
+ table.setName(tableName);
+ table.addForeignKeyColumn("name",
+ foreignColumn,
+ ForeignKeyAction::SetDefault,
+ ForeignKeyAction::Restrict,
+ Enforment::Deferred);
- EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE testTable(name NUMERIC, value NUMERIC)")));
- EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_testTable_name ON testTable(name)")));
- EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_testTable_value ON testTable(value)")));
+ EXPECT_CALL(
+ mockDatabase,
+ execute(
+ Eq("CREATE TABLE testTable(name TEXT REFERENCES foreignTable(foreignColumn) ON UPDATE "
+ "SET DEFAULT ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED)")));
table.initialize(mockDatabase);
}
+TEST_F(SqliteTable, AddColumn)
+{
+ table.setName(tableName);
+
+ auto &column = table.addColumn("name", ColumnType::Text, {Sqlite::Unique{}});
+
+ ASSERT_THAT(column,
+ AllOf(Field(&Column::name, Eq("name")),
+ Field(&Column::tableName, Eq(tableName)),
+ Field(&Column::type, ColumnType::Text),
+ Field(&Column::constraints,
+ ElementsAre(VariantWith<Sqlite::Unique>(Eq(Sqlite::Unique{}))))));
+}
+
+TEST_F(SqliteTable, AddForeignKeyColumnWithTable)
+{
+ Sqlite::Table foreignTable;
+ foreignTable.setName("foreignTable");
+
+ table.setName(tableName);
+
+ auto &column = table.addForeignKeyColumn("name",
+ foreignTable,
+ ForeignKeyAction::SetNull,
+ ForeignKeyAction::Cascade,
+ Enforment::Deferred);
+
+ ASSERT_THAT(column,
+ AllOf(Field(&Column::name, Eq("name")),
+ Field(&Column::tableName, Eq(tableName)),
+ Field(&Column::type, ColumnType::Integer),
+ Field(&Column::constraints,
+ ElementsAre(VariantWith<ForeignKey>(
+ AllOf(Field(&ForeignKey::table, Eq("foreignTable")),
+ Field(&ForeignKey::column, IsEmpty()),
+ Field(&ForeignKey::updateAction, ForeignKeyAction::SetNull),
+ Field(&ForeignKey::deleteAction, ForeignKeyAction::Cascade),
+ Field(&ForeignKey::enforcement, Enforment::Deferred)))))));
+}
+
+TEST_F(SqliteTable, AddForeignKeyColumnWithColumn)
+{
+ Sqlite::Table foreignTable;
+ foreignTable.setName("foreignTable");
+ auto &foreignColumn = foreignTable.addColumn("foreignColumn", ColumnType::Text, {Sqlite::Unique{}});
+ table.setName(tableName);
+
+ auto &column = table.addForeignKeyColumn("name",
+ foreignColumn,
+ ForeignKeyAction::SetNull,
+ ForeignKeyAction::Cascade,
+ Enforment::Deferred);
+
+ ASSERT_THAT(column,
+ AllOf(Field(&Column::name, Eq("name")),
+ Field(&Column::tableName, Eq(tableName)),
+ Field(&Column::type, ColumnType::Text),
+ Field(&Column::constraints,
+ ElementsAre(VariantWith<ForeignKey>(
+ AllOf(Field(&ForeignKey::table, Eq("foreignTable")),
+ Field(&ForeignKey::column, Eq("foreignColumn")),
+ Field(&ForeignKey::updateAction, ForeignKeyAction::SetNull),
+ Field(&ForeignKey::deleteAction, ForeignKeyAction::Cascade),
+ Field(&ForeignKey::enforcement, Enforment::Deferred)))))));
+}
+
+TEST_F(SqliteTable, AddForeignKeyWhichIsNotUniqueThrowsAnExceptions)
+{
+ Sqlite::Table foreignTable;
+ foreignTable.setName("foreignTable");
+ auto &foreignColumn = foreignTable.addColumn("foreignColumn", ColumnType::Text);
+ table.setName(tableName);
+
+ ASSERT_THROW(table.addForeignKeyColumn("name",
+ foreignColumn,
+ ForeignKeyAction::SetNull,
+ ForeignKeyAction::Cascade,
+ Enforment::Deferred),
+ Sqlite::ForeignKeyColumnIsNotUnique);
+}
+
+TEST_F(SqliteTable, AddForeignKeyColumnWithTableAndNotNull)
+{
+ Sqlite::Table foreignTable;
+ foreignTable.setName("foreignTable");
+
+ table.setName(tableName);
+
+ auto &column = table.addForeignKeyColumn("name",
+ foreignTable,
+ ForeignKeyAction::SetNull,
+ ForeignKeyAction::Cascade,
+ Enforment::Deferred,
+ {Sqlite::NotNull{}});
+
+ ASSERT_THAT(column,
+ AllOf(Field(&Column::name, Eq("name")),
+ Field(&Column::tableName, Eq(tableName)),
+ Field(&Column::type, ColumnType::Integer),
+ Field(&Column::constraints,
+ UnorderedElementsAre(
+ VariantWith<ForeignKey>(
+ AllOf(Field(&ForeignKey::table, Eq("foreignTable")),
+ Field(&ForeignKey::column, IsEmpty()),
+ Field(&ForeignKey::updateAction, ForeignKeyAction::SetNull),
+ Field(&ForeignKey::deleteAction, ForeignKeyAction::Cascade),
+ Field(&ForeignKey::enforcement, Enforment::Deferred))),
+ VariantWith<Sqlite::NotNull>(Eq(Sqlite::NotNull{}))))));
+}
+
+TEST_F(SqliteTable, AddForeignKeyColumnWithColumnAndNotNull)
+{
+ Sqlite::Table foreignTable;
+ foreignTable.setName("foreignTable");
+ auto &foreignColumn = foreignTable.addColumn("foreignColumn", ColumnType::Text, {Sqlite::Unique{}});
+ table.setName(tableName);
+
+ auto &column = table.addForeignKeyColumn("name",
+ foreignColumn,
+ ForeignKeyAction::SetNull,
+ ForeignKeyAction::Cascade,
+ Enforment::Deferred,
+ {Sqlite::NotNull{}});
+
+ ASSERT_THAT(column,
+ AllOf(Field(&Column::name, Eq("name")),
+ Field(&Column::tableName, Eq(tableName)),
+ Field(&Column::type, ColumnType::Text),
+ Field(&Column::constraints,
+ UnorderedElementsAre(
+ VariantWith<ForeignKey>(
+ AllOf(Field(&ForeignKey::table, Eq("foreignTable")),
+ Field(&ForeignKey::column, Eq("foreignColumn")),
+ Field(&ForeignKey::updateAction, ForeignKeyAction::SetNull),
+ Field(&ForeignKey::deleteAction, ForeignKeyAction::Cascade),
+ Field(&ForeignKey::enforcement, Enforment::Deferred))),
+ VariantWith<Sqlite::NotNull>(Eq(Sqlite::NotNull{}))))));
+}
+
+TEST_F(SqliteTable, AddPrimaryTableContraint)
+{
+ table.setName(tableName.clone());
+ const auto &idColumn = table.addColumn("id");
+ const auto &nameColumn = table.addColumn("name");
+ table.addPrimaryKeyContraint({idColumn, nameColumn});
+
+ EXPECT_CALL(mockDatabase,
+ execute(
+ Eq("CREATE TABLE testTable(id NUMERIC, name NUMERIC, PRIMARY KEY(id, name))")));
+
+ table.initialize(mockDatabase);
}
+} // namespace
diff --git a/tests/unit/unittest/sqlitetransaction-test.cpp b/tests/unit/unittest/sqlitetransaction-test.cpp
index dc3e5bba70..0aa426db67 100644
--- a/tests/unit/unittest/sqlitetransaction-test.cpp
+++ b/tests/unit/unittest/sqlitetransaction-test.cpp
@@ -33,12 +33,13 @@
namespace {
+using Sqlite::DeferredNonThrowingDestructorTransaction;
using Sqlite::DeferredTransaction;
-using Sqlite::ImmediateTransaction;
+using Sqlite::ExclusiveNonThrowingDestructorTransaction;
using Sqlite::ExclusiveTransaction;
-using Sqlite::DeferredNonThrowingDestructorTransaction;
using Sqlite::ImmediateNonThrowingDestructorTransaction;
-using Sqlite::ExclusiveNonThrowingDestructorTransaction;
+using Sqlite::ImmediateSessionTransaction;
+using Sqlite::ImmediateTransaction;
class SqliteTransaction : public testing::Test
{
@@ -316,4 +317,56 @@ TEST_F(SqliteTransaction, TransactionRollbackInDestructorDontThrows)
ASSERT_NO_THROW(ExclusiveNonThrowingDestructorTransaction{mockTransactionBackend});
}
+TEST_F(SqliteTransaction, ImmediateSessionTransactionCommit)
+{
+ InSequence s;
+
+ EXPECT_CALL(mockTransactionBackend, lock());
+ EXPECT_CALL(mockTransactionBackend, immediateSessionBegin());
+ EXPECT_CALL(mockTransactionBackend, sessionCommit());
+ EXPECT_CALL(mockTransactionBackend, unlock());
+
+ ImmediateSessionTransaction transaction{mockTransactionBackend};
+ transaction.commit();
+}
+
+TEST_F(SqliteTransaction, ImmediateSessionTransactionRollBack)
+{
+ InSequence s;
+
+ EXPECT_CALL(mockTransactionBackend, lock());
+ EXPECT_CALL(mockTransactionBackend, immediateSessionBegin());
+ EXPECT_CALL(mockTransactionBackend, sessionRollback());
+ EXPECT_CALL(mockTransactionBackend, unlock());
+
+ ImmediateSessionTransaction transaction{mockTransactionBackend};
+}
+
+TEST_F(SqliteTransaction, SessionTransactionRollbackInDestructorThrows)
+{
+ ON_CALL(mockTransactionBackend, sessionRollback()).WillByDefault(Throw(Sqlite::Exception("foo")));
+
+ ASSERT_THROW(ImmediateSessionTransaction{mockTransactionBackend}, Sqlite::Exception);
+}
+
+TEST_F(SqliteTransaction, ImmidiateSessionTransactionBeginThrows)
+{
+ ON_CALL(mockTransactionBackend, immediateSessionBegin())
+ .WillByDefault(Throw(Sqlite::Exception("foo")));
+
+ ASSERT_THROW(ImmediateSessionTransaction{mockTransactionBackend}, Sqlite::Exception);
}
+
+TEST_F(SqliteTransaction, ImmediateSessionTransactionBeginThrowsAndNotRollback)
+{
+ InSequence s;
+
+ EXPECT_CALL(mockTransactionBackend, lock());
+ EXPECT_CALL(mockTransactionBackend, immediateSessionBegin()).WillOnce(Throw(Sqlite::Exception("foo")));
+ EXPECT_CALL(mockTransactionBackend, sessionRollback()).Times(0);
+ EXPECT_CALL(mockTransactionBackend, unlock());
+
+ ASSERT_ANY_THROW(ImmediateSessionTransaction{mockTransactionBackend});
+}
+
+} // namespace
diff --git a/tests/unit/unittest/sqlitevalue-test.cpp b/tests/unit/unittest/sqlitevalue-test.cpp
index e9cc5c9e40..1a90c330f0 100644
--- a/tests/unit/unittest/sqlitevalue-test.cpp
+++ b/tests/unit/unittest/sqlitevalue-test.cpp
@@ -29,6 +29,20 @@
namespace {
+TEST(SqliteValue, ConstructDefault)
+{
+ Sqlite::Value value{};
+
+ ASSERT_TRUE(value.isNull());
+}
+
+TEST(SqliteValue, ConstructNullValue)
+{
+ Sqlite::Value value{Sqlite::NullValue{}};
+
+ ASSERT_TRUE(value.isNull());
+}
+
TEST(SqliteValue, ConstructLongLong)
{
Sqlite::Value value{1LL};
@@ -36,7 +50,7 @@ TEST(SqliteValue, ConstructLongLong)
ASSERT_THAT(value.toInteger(), Eq(1LL));
}
-TEST(SqliteValue, Construct)
+TEST(SqliteValue, ConstructInteger)
{
Sqlite::Value value{1};
@@ -71,6 +85,24 @@ TEST(SqliteValue, ConstructStringFromQString)
ASSERT_THAT(value.toStringView(), Eq("foo"));
}
+TEST(SqliteValue, ConstructStringFromBlob)
+{
+ // Utils::span<const Sqlite::byte> bytes{reinterpret_cast<const Sqlite::byte *>("abcd"), 4};
+
+ // Sqlite::Value value{bytes};
+
+ //ASSERT_THAT(value.toBlob(), Eq(bytes));
+}
+
+TEST(SqliteValue, ConstructNullFromNullQVariant)
+{
+ QVariant variant{};
+
+ Sqlite::Value value{variant};
+
+ ASSERT_TRUE(value.isNull());
+}
+
TEST(SqliteValue, ConstructStringFromIntQVariant)
{
QVariant variant{1};
@@ -116,6 +148,15 @@ TEST(SqliteValue, ConstructStringFromStringQVariant)
ASSERT_THAT(value.toStringView(), Eq("foo"));
}
+TEST(SqliteValue, ConvertToNullQVariant)
+{
+ Sqlite::Value value{};
+
+ auto variant = QVariant{value};
+
+ ASSERT_TRUE(variant.isNull());
+}
+
TEST(SqliteValue, ConvertToStringQVariant)
{
Sqlite::Value value{"foo"};
@@ -192,6 +233,13 @@ TEST(SqliteValue, IntegerAndFloatAreNotEquals)
ASSERT_FALSE(isEqual);
}
+TEST(SqliteValue, NullValuesNeverEqual)
+{
+ bool isEqual = Sqlite::Value{} == Sqlite::Value{};
+
+ ASSERT_FALSE(isEqual);
+}
+
TEST(SqliteValue, IntegerValuesAreEquals)
{
bool isEqual = Sqlite::Value{1} == Sqlite::Value{1};
@@ -248,6 +296,13 @@ TEST(SqliteValue, IntegersAreUnequalInverse)
ASSERT_TRUE(isUnequal);
}
+TEST(SqliteValue, NullType)
+{
+ auto type = Sqlite::Value{}.type();
+
+ ASSERT_THAT(type, Sqlite::ValueType::Null);
+}
+
TEST(SqliteValue, IntegerType)
{
auto type = Sqlite::Value{1}.type();
@@ -269,6 +324,20 @@ TEST(SqliteValue, StringType)
ASSERT_THAT(type, Sqlite::ValueType::String);
}
+TEST(SqliteValue, NullValueAndValueViewAreNotEqual)
+{
+ bool isEqual = Sqlite::ValueView::create(Sqlite::NullValue{}) == Sqlite::Value{};
+
+ ASSERT_FALSE(isEqual);
+}
+
+TEST(SqliteValue, NullValueViewAndValueAreNotEqual)
+{
+ bool isEqual = Sqlite::Value{} == Sqlite::ValueView::create(Sqlite::NullValue{});
+
+ ASSERT_FALSE(isEqual);
+}
+
TEST(SqliteValue, StringValueAndValueViewEquals)
{
bool isEqual = Sqlite::ValueView::create("foo") == Sqlite::Value{"foo"};
@@ -318,6 +387,15 @@ TEST(SqliteValue, StringValueAndIntergerValueViewAreNotEqual)
ASSERT_FALSE(isEqual);
}
+TEST(SqliteValue, ConvertNullValueViewIntoValue)
+{
+ auto view = Sqlite::ValueView::create(Sqlite::NullValue{});
+
+ Sqlite::Value value{view};
+
+ ASSERT_TRUE(value.isNull());
+}
+
TEST(SqliteValue, ConvertStringValueViewIntoValue)
{
auto view = Sqlite::ValueView::create("foo");
diff --git a/tests/unit/unittest/symbolquery-test.cpp b/tests/unit/unittest/symbolquery-test.cpp
index 8a7fad4272..3ff541564e 100644
--- a/tests/unit/unittest/symbolquery-test.cpp
+++ b/tests/unit/unittest/symbolquery-test.cpp
@@ -74,15 +74,18 @@ class SymbolQuerySlowTest : public testing::Test
protected:
void SetUp() override
{
- database.execute("INSERT INTO sources VALUES (1, 1, \"filename.h\")");
- database.execute("INSERT INTO sources VALUES (2, 1, \"filename.cpp\")");
- database.execute("INSERT INTO directories VALUES (1, \"/path/to\")");
+ database.execute("INSERT INTO sources VALUES (1, 1, 'filename.h')");
+ database.execute("INSERT INTO sources VALUES (2, 1, 'filename.cpp')");
+ database.execute("INSERT INTO directories VALUES (1, '/path/to')");
database.execute("INSERT INTO locations VALUES (1, 2, 3, 1, 2)");
database.execute("INSERT INTO locations VALUES (1, 4, 6, 2, 1)");
database.execute("INSERT INTO locations VALUES (1, 20, 36, 2, 3)");
- database.execute("INSERT INTO symbols VALUES (1, \"functionusr\", \"Function\", 3, \"void function(int)\")");
- database.execute("INSERT INTO symbols VALUES (2, \"classusr\", \"Class\", 2, \"class Class final\")");
- database.execute("INSERT INTO symbols VALUES (3, \"enumusr\", \"Enum\", 1, \"enum Enum : char\")");
+ database.execute(
+ "INSERT INTO symbols VALUES (1, 'functionusr', 'Function', 3, 'void function(int)')");
+ database.execute(
+ "INSERT INTO symbols VALUES (2, 'classusr', 'Class', 2, 'class Class final')");
+ database.execute(
+ "INSERT INTO symbols VALUES (3, 'enumusr', 'Enum', 1, 'enum Enum : char')");
}
protected:
diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro
index 6155cf3212..03f04f3982 100644
--- a/tests/unit/unittest/unittest.pro
+++ b/tests/unit/unittest/unittest.pro
@@ -63,6 +63,7 @@ SOURCES += \
filepathview-test.cpp \
gtest-creator-printing.cpp \
gtest-qt-printing.cpp \
+ lastchangedrowid-test.cpp \
lineprefixer-test.cpp \
locatorfilter-test.cpp \
matchingtext-test.cpp \
@@ -80,6 +81,7 @@ SOURCES += \
smallstring-test.cpp \
sourcerangefilter-test.cpp \
spydummy.cpp \
+ sqlitesessions-test.cpp \
sqlitevalue-test.cpp \
symbolindexer-test.cpp \
symbolsfindfilter-test.cpp \
diff --git a/tests/unit/unittest/unittests-main.cpp b/tests/unit/unittest/unittests-main.cpp
index f5eaa8846c..6704a08034 100644
--- a/tests/unit/unittest/unittests-main.cpp
+++ b/tests/unit/unittest/unittests-main.cpp
@@ -25,8 +25,8 @@
#include "googletest.h"
+#include <sqlitedatabase.h>
#include <sqliteglobal.h>
-
#include <utils/temporarydirectory.h>
#include <QCoreApplication>
@@ -38,6 +38,7 @@
int main(int argc, char *argv[])
{
+ Sqlite::Database::activateLogging();
const QString temporayDirectoryPath = QDir::tempPath() +"/QtCreator-UnitTests-XXXXXX";
Utils::TemporaryDirectory::setMasterTemporaryDirectory(temporayDirectoryPath);
qputenv("TMPDIR", Utils::TemporaryDirectory::masterDirectoryPath().toUtf8());