From f02934458e95bb12e974ac9c04d1c668c03306eb Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Tue, 5 May 2020 14:05:17 +0200 Subject: Sqlite: Add foreign key support It is still only support references in columns but so far it is enough. Change-Id: Iebb4866cf738d651270e54357b5e4a2837f05417 Reviewed-by: Tim Jenssen --- .../createtablesqlstatementbuilder-test.cpp | 210 ++++++++++++++++++++- tests/unit/unittest/sqlitecolumn-test.cpp | 115 +++++++---- tests/unit/unittest/sqlitetable-test.cpp | 144 ++++++++++++-- 3 files changed, 414 insertions(+), 55 deletions(-) (limited to 'tests/unit') diff --git a/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp b/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp index 9a56777a17..39e927797b 100644 --- a/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp +++ b/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp @@ -30,13 +30,14 @@ namespace { +using Sqlite::Column; using Sqlite::ColumnType; using Sqlite::Contraint; +using Sqlite::Enforment; +using Sqlite::ForeignKeyAction; using Sqlite::JournalMode; using Sqlite::OpenMode; -using Sqlite::Column; using Sqlite::SqliteColumns; - using Sqlite::SqlStatementBuilderException; class CreateTableSqlStatementBuilder : public ::testing::Test @@ -199,11 +200,210 @@ void CreateTableSqlStatementBuilder::bindValues() SqliteColumns CreateTableSqlStatementBuilder::createColumns() { SqliteColumns columns; - columns.emplace_back("id", ColumnType::Integer, Contraint::PrimaryKey); - columns.emplace_back("name", ColumnType::Text); - columns.emplace_back("number", ColumnType::Numeric); + columns.emplace_back("", "id", ColumnType::Integer, Contraint::PrimaryKey); + columns.emplace_back("", "name", ColumnType::Text); + columns.emplace_back("", "number", ColumnType::Numeric); return columns; } +TEST_F(CreateTableSqlStatementBuilder, ForeignKeyWithoutColumn) +{ + builder.clear(); + builder.setTableName("test"); + + builder.addColumn("id", ColumnType::Integer, Contraint::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, Contraint::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, Contraint::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, + Contraint::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, + Contraint::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::ForeignKey, + {"otherTable", "otherColumn", ForeignKeyAction::SetDefault}); + + ASSERT_THAT( + builder.sqlStatement(), + "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON UPDATE SET DEFAULT)"); +} + +TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateCascade) +{ + builder.clear(); + builder.setTableName("test"); + + builder.addColumn("id", + ColumnType::Integer, + Contraint::ForeignKey, + {"otherTable", "otherColumn", ForeignKeyAction::Cascade}); + + 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, Contraint::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, + Contraint::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, + Contraint::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, + Contraint::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, + Contraint::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, + Contraint::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, + Contraint::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)"); } +} // namespace diff --git a/tests/unit/unittest/sqlitecolumn-test.cpp b/tests/unit/unittest/sqlitecolumn-test.cpp index 3daa32bd23..0d6b1401ad 100644 --- a/tests/unit/unittest/sqlitecolumn-test.cpp +++ b/tests/unit/unittest/sqlitecolumn-test.cpp @@ -29,70 +29,111 @@ namespace { -using testing::AllOf; -using testing::Contains; -using testing::Property; - using Sqlite::ColumnType; using Sqlite::Contraint; 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::constraint, Contraint::NoConstraint), + Field(&Column::foreignKey, + AllOf(Field(&ForeignKey::table, IsEmpty()), + Field(&ForeignKey::column, IsEmpty()), + Field(&ForeignKey::updateAction, ForeignKeyAction::NoAction), + Field(&ForeignKey::deleteAction, ForeignKeyAction::NoAction), + Field(&ForeignKey::enforcement, Enforment::Immediate))))); } -TEST_F(SqliteColumn, ChangeType) +TEST_F(SqliteColumn, Clear) { - column.setType(ColumnType::Text); + column.name = "foo"; + column.name = "foo"; + column.type = ColumnType::Text; + column.constraint = Contraint::ForeignKey; + column.foreignKey.table = "bar"; + column.foreignKey.column = "hmm"; + column.foreignKey.updateAction = ForeignKeyAction::Cascade; + column.foreignKey.deleteAction = ForeignKeyAction::SetNull; - 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::constraint, Contraint::NoConstraint), + Field(&Column::foreignKey, + AllOf(Field(&ForeignKey::table, IsEmpty()), + Field(&ForeignKey::column, IsEmpty()), + Field(&ForeignKey::updateAction, ForeignKeyAction::NoAction), + Field(&ForeignKey::deleteAction, ForeignKeyAction::NoAction), + Field(&ForeignKey::enforcement, Enforment::Immediate))))); } -TEST_F(SqliteColumn, SetConstraint) +TEST_F(SqliteColumn, Constructor) { - column.setContraint(Contraint::PrimaryKey); + column = Sqlite::Column{"table", + "column", + ColumnType::Text, + Contraint::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::constraint, Contraint::ForeignKey), + Field(&Column::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, + Contraint::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::constraint, Contraint::ForeignKey), + Field(&Column::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/sqlitetable-test.cpp b/tests/unit/unittest/sqlitetable-test.cpp index c5ce8e325d..89dfb7f867 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::Contraint; +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,135 @@ TEST_F(SqliteTable, InitializeTableWithIndex) table.initialize(mockDatabase); } - -TEST_F(SqliteTable, InitializeTableWithUniqueIndex) +TEST_F(SqliteTable, AddForeignKeyColumnWithTableCalls) { - 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"); + 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)"))); - 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)"))); + table.initialize(mockDatabase); +} + +TEST_F(SqliteTable, AddForeignKeyColumnWithColumnCalls) +{ + Sqlite::Table foreignTable; + foreignTable.setName("foreignTable"); + auto &foreignColumn = foreignTable.addColumn("foreignColumn", + ColumnType::Text, + Sqlite::Contraint::Unique); + table.setName(tableName); + table.addForeignKeyColumn("name", + foreignColumn, + ForeignKeyAction::SetDefault, + ForeignKeyAction::Restrict, + Enforment::Deferred); + + 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::Contraint::Unique); + + ASSERT_THAT(column, + AllOf(Field(&Column::name, Eq("name")), + Field(&Column::tableName, Eq(tableName)), + Field(&Column::type, ColumnType::Text), + Field(&Column::constraint, Contraint::Unique), + Field(&Column::foreignKey, + AllOf(Field(&ForeignKey::table, IsEmpty()), + Field(&ForeignKey::column, IsEmpty()), + Field(&ForeignKey::updateAction, ForeignKeyAction::NoAction), + Field(&ForeignKey::deleteAction, ForeignKeyAction::NoAction), + Field(&ForeignKey::enforcement, Enforment::Immediate))))); } + +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::constraint, Contraint::ForeignKey), + Field(&Column::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::Contraint::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::constraint, Contraint::ForeignKey), + Field(&Column::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, + Sqlite::Contraint::NoConstraint); + table.setName(tableName); + + ASSERT_THROW(table.addForeignKeyColumn("name", + foreignColumn, + ForeignKeyAction::SetNull, + ForeignKeyAction::Cascade, + Enforment::Deferred), + Sqlite::ForeignKeyColumnIsNotUnique); +} + +} // namespace -- cgit v1.2.3 From a4b00a7742bd7f0ecee2d8dc567079440a1e88f0 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Tue, 12 May 2020 12:54:18 +0200 Subject: Sqlite: Add update hook and use it to get the last changed id Sqlite has a function to get the last inserted rowid but very often you want to get the updated rowid too. Change-Id: Ie276a5039682813ad16597433996a2959f54d9ba Reviewed-by: Tim Jenssen --- tests/unit/unittest/lastchangedrowid-test.cpp | 108 ++++++++++++++++++++++++++ tests/unit/unittest/mocksqlitedatabase.h | 4 + tests/unit/unittest/sqlitedatabase-test.cpp | 87 +++++++++++++++++++++ tests/unit/unittest/unittest.pro | 1 + 4 files changed, 200 insertions(+) create mode 100644 tests/unit/unittest/lastchangedrowid-test.cpp (limited to 'tests/unit') diff --git a/tests/unit/unittest/lastchangedrowid-test.cpp b/tests/unit/unittest/lastchangedrowid-test.cpp new file mode 100644 index 0000000000..10b83a9795 --- /dev/null +++ b/tests/unit/unittest/lastchangedrowid-test.cpp @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** 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 + +namespace { + +class LastChangedRowId : public testing::Test +{ +protected: + NiceMock 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, "temp", "foo", 42); + + ASSERT_THAT(lastRowId.lastRowId, -1); +} + +TEST_F(LastChangedRowId, CallbackChecksTableName) +{ + lastRowId.callback(Sqlite::ChangeType::Update, "main", "bar", 42); + + ASSERT_THAT(lastRowId.lastRowId, -1); +} + +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); +} + +} // namespace diff --git a/tests/unit/unittest/mocksqlitedatabase.h b/tests/unit/unittest/mocksqlitedatabase.h index 05f6f4e958..97d5394339 100644 --- a/tests/unit/unittest/mocksqlitedatabase.h +++ b/tests/unit/unittest/mocksqlitedatabase.h @@ -59,5 +59,9 @@ public: void (bool)); MOCK_METHOD0(walCheckpointFull, void()); + + MOCK_METHOD1(setUpdateHook, void(Sqlite::DatabaseInterface::UpdateCallback &)); + + MOCK_METHOD0(resetUpdateHook, void()); }; diff --git a/tests/unit/unittest/sqlitedatabase-test.cpp b/tests/unit/unittest/sqlitedatabase-test.cpp index 66c1aa8387..ff3436c459 100644 --- a/tests/unit/unittest/sqlitedatabase-test.cpp +++ b/tests/unit/unittest/sqlitedatabase-test.cpp @@ -71,6 +71,8 @@ protected: QString databaseFilePath{":memory:"}; Sqlite::Database database; Sqlite::TransactionInterface &transactionInterface = database; + MockFunction callbackMock; + Sqlite::Database::UpdateCallback callback = callbackMock.AsStdFunction(); }; TEST_F(SqliteDatabase, SetDatabaseFilePath) @@ -220,4 +222,89 @@ 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); +} + +} // namespace diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index 6155cf3212..7340f00775 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 \ -- cgit v1.2.3 From a86fd58e40ea8b1a1a80f69d878b2073ad9ebef0 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Tue, 12 May 2020 17:05:33 +0200 Subject: Sqlite: Improve LastChangedRowId Sometimes we want not only the row id from one table but two or three. Change-Id: I6d5444a71ecbfe6c1af8073be80b04932ea9268d Reviewed-by: Tim Jenssen --- tests/unit/unittest/lastchangedrowid-test.cpp | 186 +++++++++++++++++++++++++- 1 file changed, 184 insertions(+), 2 deletions(-) (limited to 'tests/unit') diff --git a/tests/unit/unittest/lastchangedrowid-test.cpp b/tests/unit/unittest/lastchangedrowid-test.cpp index 10b83a9795..da33dd6098 100644 --- a/tests/unit/unittest/lastchangedrowid-test.cpp +++ b/tests/unit/unittest/lastchangedrowid-test.cpp @@ -64,16 +64,20 @@ TEST_F(LastChangedRowId, CallbackSetsLastRowId) TEST_F(LastChangedRowId, CallbackChecksDatabaseName) { + lastRowId.callback(Sqlite::ChangeType::Update, "main", "foo", 33); + lastRowId.callback(Sqlite::ChangeType::Update, "temp", "foo", 42); - ASSERT_THAT(lastRowId.lastRowId, -1); + 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, -1); + ASSERT_THAT(lastRowId.lastRowId, 33); } TEST_F(LastChangedRowId, LastCallSetsRowId) @@ -105,4 +109,182 @@ TEST_F(LastChangedRowId, TakeLastRowIdResetsRowIdToMinusOne) ASSERT_THAT(id, -1); } +class LastChangedRowIdWithTwoTables : public testing::Test +{ +protected: + NiceMock 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; + + 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); +} + } // namespace -- cgit v1.2.3 From c4bbc74e37ab74e000ba6979474d281f203feba2 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 13 May 2020 20:29:49 +0200 Subject: Sqlite: Improve constraint support Now you can add more than one constraint. And we added some new constraints too. Change-Id: I849d2d2ef6e44c897a65ff2bdfe8d172a345c991 Reviewed-by: Tim Jenssen --- .../createtablesqlstatementbuilder-test.cpp | 206 +++++++++++++++------ tests/unit/unittest/google-using-declarations.h | 18 +- tests/unit/unittest/sqlitecolumn-test.cpp | 74 +++----- tests/unit/unittest/sqlitedatabasebackend-test.cpp | 2 +- tests/unit/unittest/sqlitetable-test.cpp | 111 +++++++---- 5 files changed, 267 insertions(+), 144 deletions(-) (limited to 'tests/unit') diff --git a/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp b/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp index 39e927797b..c8ff7b47b2 100644 --- a/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp +++ b/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp @@ -32,19 +32,38 @@ 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::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; @@ -158,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)"); @@ -168,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); @@ -180,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); @@ -188,31 +207,12 @@ TEST_F(CreateTableSqlStatementBuilder, TemporaryTable) "CREATE TEMPORARY TABLE test(id INTEGER)"); } -void CreateTableSqlStatementBuilder::bindValues() -{ - builder.clear(); - builder.setTableName("test"); - builder.addColumn("id", ColumnType::Integer, Contraint::PrimaryKey); - builder.addColumn("name", ColumnType::Text); - builder.addColumn("number",ColumnType:: Numeric); -} - -SqliteColumns CreateTableSqlStatementBuilder::createColumns() -{ - SqliteColumns columns; - columns.emplace_back("", "id", ColumnType::Integer, Contraint::PrimaryKey); - columns.emplace_back("", "name", ColumnType::Text); - columns.emplace_back("", "number", ColumnType::Numeric); - - return columns; -} - TEST_F(CreateTableSqlStatementBuilder, ForeignKeyWithoutColumn) { builder.clear(); builder.setTableName("test"); - builder.addColumn("id", ColumnType::Integer, Contraint::ForeignKey, {"otherTable", ""}); + builder.addColumn("id", ColumnType::Integer, {ForeignKey{"otherTable", ""}}); ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER REFERENCES otherTable)"); } @@ -222,7 +222,7 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyWithColumn) builder.clear(); builder.setTableName("test"); - builder.addColumn("id", ColumnType::Integer, Contraint::ForeignKey, {"otherTable", "otherColumn"}); + builder.addColumn("id", ColumnType::Integer, {ForeignKey{"otherTable", "otherColumn"}}); ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn))"); @@ -233,7 +233,7 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateNoAction) builder.clear(); builder.setTableName("test"); - builder.addColumn("id", ColumnType::Integer, Contraint::ForeignKey, {"otherTable", "otherColumn"}); + builder.addColumn("id", ColumnType::Integer, {ForeignKey{"otherTable", "otherColumn"}}); ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn))"); @@ -246,8 +246,7 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateRestrict) builder.addColumn("id", ColumnType::Integer, - Contraint::ForeignKey, - {"otherTable", "otherColumn", ForeignKeyAction::Restrict}); + {ForeignKey{"otherTable", "otherColumn", ForeignKeyAction::Restrict}}); ASSERT_THAT( builder.sqlStatement(), @@ -261,8 +260,7 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateSetNull) builder.addColumn("id", ColumnType::Integer, - Contraint::ForeignKey, - {"otherTable", "otherColumn", ForeignKeyAction::SetNull}); + {ForeignKey{"otherTable", "otherColumn", ForeignKeyAction::SetNull}}); ASSERT_THAT( builder.sqlStatement(), @@ -276,8 +274,7 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateSetDefault) builder.addColumn("id", ColumnType::Integer, - Contraint::ForeignKey, - {"otherTable", "otherColumn", ForeignKeyAction::SetDefault}); + {ForeignKey{"otherTable", "otherColumn", ForeignKeyAction::SetDefault}}); ASSERT_THAT( builder.sqlStatement(), @@ -291,8 +288,7 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateCascade) builder.addColumn("id", ColumnType::Integer, - Contraint::ForeignKey, - {"otherTable", "otherColumn", ForeignKeyAction::Cascade}); + {ForeignKey{"otherTable", "otherColumn", ForeignKeyAction::Cascade}}); ASSERT_THAT( builder.sqlStatement(), @@ -304,7 +300,7 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteNoAction) builder.clear(); builder.setTableName("test"); - builder.addColumn("id", ColumnType::Integer, Contraint::ForeignKey, {"otherTable", "otherColumn"}); + builder.addColumn("id", ColumnType::Integer, {ForeignKey{"otherTable", "otherColumn"}}); ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn))"); @@ -317,8 +313,7 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteRestrict) builder.addColumn("id", ColumnType::Integer, - Contraint::ForeignKey, - {"otherTable", "otherColumn", {}, ForeignKeyAction::Restrict}); + {ForeignKey{"otherTable", "otherColumn", {}, ForeignKeyAction::Restrict}}); ASSERT_THAT( builder.sqlStatement(), @@ -332,8 +327,7 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteSetNull) builder.addColumn("id", ColumnType::Integer, - Contraint::ForeignKey, - {"otherTable", "otherColumn", {}, ForeignKeyAction::SetNull}); + {ForeignKey{"otherTable", "otherColumn", {}, ForeignKeyAction::SetNull}}); ASSERT_THAT( builder.sqlStatement(), @@ -347,8 +341,7 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteSetDefault) builder.addColumn("id", ColumnType::Integer, - Contraint::ForeignKey, - {"otherTable", "otherColumn", {}, ForeignKeyAction::SetDefault}); + {ForeignKey{"otherTable", "otherColumn", {}, ForeignKeyAction::SetDefault}}); ASSERT_THAT( builder.sqlStatement(), @@ -362,8 +355,7 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteCascade) builder.addColumn("id", ColumnType::Integer, - Contraint::ForeignKey, - {"otherTable", "otherColumn", {}, ForeignKeyAction::Cascade}); + {ForeignKey{"otherTable", "otherColumn", {}, ForeignKeyAction::Cascade}}); ASSERT_THAT( builder.sqlStatement(), @@ -377,11 +369,10 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteAndUpdateAction) builder.addColumn("id", ColumnType::Integer, - Contraint::ForeignKey, - {"otherTable", - "otherColumn", - ForeignKeyAction::SetDefault, - ForeignKeyAction::Cascade}); + {ForeignKey{"otherTable", + "otherColumn", + ForeignKeyAction::SetDefault, + ForeignKeyAction::Cascade}}); ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON UPDATE SET " @@ -395,15 +386,118 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeferred) builder.addColumn("id", ColumnType::Integer, - Contraint::ForeignKey, - {"otherTable", - "otherColumn", - ForeignKeyAction::SetDefault, - ForeignKeyAction::Cascade, - Enforment::Deferred}); + {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, 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)"); +} + } // namespace diff --git a/tests/unit/unittest/google-using-declarations.h b/tests/unit/unittest/google-using-declarations.h index e8bbd52800..a1975ae7a8 100644 --- a/tests/unit/unittest/google-using-declarations.h +++ b/tests/unit/unittest/google-using-declarations.h @@ -37,21 +37,27 @@ 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::Pair; using testing::PrintToString; using testing::Property; @@ -64,10 +70,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/sqlitecolumn-test.cpp b/tests/unit/unittest/sqlitecolumn-test.cpp index 0d6b1401ad..9753457c94 100644 --- a/tests/unit/unittest/sqlitecolumn-test.cpp +++ b/tests/unit/unittest/sqlitecolumn-test.cpp @@ -30,7 +30,7 @@ namespace { using Sqlite::ColumnType; -using Sqlite::Contraint; +using Sqlite::ConstraintType; using Sqlite::JournalMode; using Sqlite::OpenMode; using Column = Sqlite::Column; @@ -51,13 +51,7 @@ TEST_F(SqliteColumn, DefaultConstruct) AllOf(Field(&Column::name, IsEmpty()), Field(&Column::tableName, IsEmpty()), Field(&Column::type, ColumnType::Numeric), - Field(&Column::constraint, Contraint::NoConstraint), - Field(&Column::foreignKey, - AllOf(Field(&ForeignKey::table, IsEmpty()), - Field(&ForeignKey::column, IsEmpty()), - Field(&ForeignKey::updateAction, ForeignKeyAction::NoAction), - Field(&ForeignKey::deleteAction, ForeignKeyAction::NoAction), - Field(&ForeignKey::enforcement, Enforment::Immediate))))); + Field(&Column::constraints, IsEmpty()))); } TEST_F(SqliteColumn, Clear) @@ -65,11 +59,7 @@ TEST_F(SqliteColumn, Clear) column.name = "foo"; column.name = "foo"; column.type = ColumnType::Text; - column.constraint = Contraint::ForeignKey; - column.foreignKey.table = "bar"; - column.foreignKey.column = "hmm"; - column.foreignKey.updateAction = ForeignKeyAction::Cascade; - column.foreignKey.deleteAction = ForeignKeyAction::SetNull; + column.constraints = {Sqlite::PrimaryKey{}}; column.clear(); @@ -77,13 +67,7 @@ TEST_F(SqliteColumn, Clear) AllOf(Field(&Column::name, IsEmpty()), Field(&Column::tableName, IsEmpty()), Field(&Column::type, ColumnType::Numeric), - Field(&Column::constraint, Contraint::NoConstraint), - Field(&Column::foreignKey, - AllOf(Field(&ForeignKey::table, IsEmpty()), - Field(&ForeignKey::column, IsEmpty()), - Field(&ForeignKey::updateAction, ForeignKeyAction::NoAction), - Field(&ForeignKey::deleteAction, ForeignKeyAction::NoAction), - Field(&ForeignKey::enforcement, Enforment::Immediate))))); + Field(&Column::constraints, IsEmpty()))); } TEST_F(SqliteColumn, Constructor) @@ -91,24 +75,23 @@ TEST_F(SqliteColumn, Constructor) column = Sqlite::Column{"table", "column", ColumnType::Text, - Contraint::ForeignKey, - {"referencedTable", - "referencedColumn", - ForeignKeyAction::SetNull, - ForeignKeyAction::Cascade, - Enforment::Deferred}}; + {ForeignKey{"referencedTable", + "referencedColumn", + ForeignKeyAction::SetNull, + ForeignKeyAction::Cascade, + Enforment::Deferred}}}; ASSERT_THAT(column, AllOf(Field(&Column::name, Eq("column")), Field(&Column::tableName, Eq("table")), Field(&Column::type, ColumnType::Text), - Field(&Column::constraint, Contraint::ForeignKey), - Field(&Column::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))))); + Field(&Column::constraints, + ElementsAre(VariantWith( + 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, FlatConstructor) @@ -116,24 +99,23 @@ TEST_F(SqliteColumn, FlatConstructor) column = Sqlite::Column{"table", "column", ColumnType::Text, - Contraint::ForeignKey, - "referencedTable", - "referencedColumn", - ForeignKeyAction::SetNull, - ForeignKeyAction::Cascade, - Enforment::Deferred}; + {ForeignKey{"referencedTable", + "referencedColumn", + ForeignKeyAction::SetNull, + ForeignKeyAction::Cascade, + Enforment::Deferred}}}; ASSERT_THAT(column, AllOf(Field(&Column::name, Eq("column")), Field(&Column::tableName, Eq("table")), Field(&Column::type, ColumnType::Text), - Field(&Column::constraint, Contraint::ForeignKey), - Field(&Column::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))))); + Field(&Column::constraints, + ElementsAre(VariantWith( + 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/sqlitedatabasebackend-test.cpp b/tests/unit/unittest/sqlitedatabasebackend-test.cpp index 40227148bc..9957d3d4c7 100644 --- a/tests/unit/unittest/sqlitedatabasebackend-test.cpp +++ b/tests/unit/unittest/sqlitedatabasebackend-test.cpp @@ -39,7 +39,7 @@ namespace { using Backend = Sqlite::DatabaseBackend; using Sqlite::ColumnType; -using Sqlite::Contraint; +using Sqlite::ConstraintType; using Sqlite::JournalMode; using Sqlite::OpenMode; using Sqlite::TextEncoding; diff --git a/tests/unit/unittest/sqlitetable-test.cpp b/tests/unit/unittest/sqlitetable-test.cpp index 89dfb7f867..05d3e73462 100644 --- a/tests/unit/unittest/sqlitetable-test.cpp +++ b/tests/unit/unittest/sqlitetable-test.cpp @@ -34,7 +34,7 @@ namespace { using Sqlite::Column; using Sqlite::ColumnType; -using Sqlite::Contraint; +using Sqlite::ConstraintType; using Sqlite::Database; using Sqlite::Enforment; using Sqlite::ForeignKey; @@ -136,9 +136,7 @@ TEST_F(SqliteTable, AddForeignKeyColumnWithColumnCalls) { Sqlite::Table foreignTable; foreignTable.setName("foreignTable"); - auto &foreignColumn = foreignTable.addColumn("foreignColumn", - ColumnType::Text, - Sqlite::Contraint::Unique); + auto &foreignColumn = foreignTable.addColumn("foreignColumn", ColumnType::Text, {Sqlite::Unique{}}); table.setName(tableName); table.addForeignKeyColumn("name", foreignColumn, @@ -159,19 +157,14 @@ TEST_F(SqliteTable, AddColumn) { table.setName(tableName); - auto &column = table.addColumn("name", ColumnType::Text, Sqlite::Contraint::Unique); + 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::constraint, Contraint::Unique), - Field(&Column::foreignKey, - AllOf(Field(&ForeignKey::table, IsEmpty()), - Field(&ForeignKey::column, IsEmpty()), - Field(&ForeignKey::updateAction, ForeignKeyAction::NoAction), - Field(&ForeignKey::deleteAction, ForeignKeyAction::NoAction), - Field(&ForeignKey::enforcement, Enforment::Immediate))))); + Field(&Column::constraints, + ElementsAre(VariantWith(Eq(Sqlite::Unique{})))))); } TEST_F(SqliteTable, AddForeignKeyColumnWithTable) @@ -191,22 +184,20 @@ TEST_F(SqliteTable, AddForeignKeyColumnWithTable) AllOf(Field(&Column::name, Eq("name")), Field(&Column::tableName, Eq(tableName)), Field(&Column::type, ColumnType::Integer), - Field(&Column::constraint, Contraint::ForeignKey), - Field(&Column::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))))); + Field(&Column::constraints, + ElementsAre(VariantWith( + 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::Contraint::Unique); + auto &foreignColumn = foreignTable.addColumn("foreignColumn", ColumnType::Text, {Sqlite::Unique{}}); table.setName(tableName); auto &column = table.addForeignKeyColumn("name", @@ -219,22 +210,20 @@ TEST_F(SqliteTable, AddForeignKeyColumnWithColumn) AllOf(Field(&Column::name, Eq("name")), Field(&Column::tableName, Eq(tableName)), Field(&Column::type, ColumnType::Text), - Field(&Column::constraint, Contraint::ForeignKey), - Field(&Column::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))))); + Field(&Column::constraints, + ElementsAre(VariantWith( + 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, - Sqlite::Contraint::NoConstraint); + auto &foreignColumn = foreignTable.addColumn("foreignColumn", ColumnType::Text); table.setName(tableName); ASSERT_THROW(table.addForeignKeyColumn("name", @@ -245,4 +234,62 @@ TEST_F(SqliteTable, AddForeignKeyWhichIsNotUniqueThrowsAnExceptions) 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( + 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(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( + 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(Eq(Sqlite::NotNull{})))))); +} + } // namespace -- cgit v1.2.3 From 77c81aa8b0f52173925709bd4fe5876ba64e2982 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 13 May 2020 18:58:27 +0200 Subject: ClangPchManager: Fix tests Change-Id: Ide9adf326dda4b995636d629a6b2eed829f42b34 Reviewed-by: Tim Jenssen --- tests/unit/unittest/commandlinebuilder-test.cpp | 4 ++-- tests/unit/unittest/pchtaskqueue-test.cpp | 9 --------- tests/unit/unittest/pchtasksmerger-test.cpp | 5 ----- 3 files changed, 2 insertions(+), 16 deletions(-) (limited to 'tests/unit') 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/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}, -- cgit v1.2.3 From 4b7aeae749bd0e9b23d7d03fd7b8792042748c79 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Thu, 14 May 2020 12:13:51 +0200 Subject: Sqlite: Add check constraint Change-Id: Ib4b909da40c7fe07dcb6a07c4650a720313391c2 Reviewed-by: Tim Jenssen --- tests/unit/unittest/createtablesqlstatementbuilder-test.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'tests/unit') diff --git a/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp b/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp index c8ff7b47b2..c80ce9d96f 100644 --- a/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp +++ b/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp @@ -417,6 +417,16 @@ TEST_F(CreateTableSqlStatementBuilder, NotNullAndUniqueConstraint) 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(); -- cgit v1.2.3 From 33a833d18764816a4d3c22e72e5b8f23faba6eae Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Thu, 14 May 2020 12:50:34 +0200 Subject: Sqlite: Add null value So we can distingish between a null value and zero or an empty string. Change-Id: I9122fdafdf85cf04dcf8bca7bf294be9b28ee251 Reviewed-by: Tim Jenssen --- tests/unit/unittest/sqlitestatement-test.cpp | 78 +++++++++++++++++++++------- tests/unit/unittest/sqlitevalue-test.cpp | 71 ++++++++++++++++++++++++- 2 files changed, 128 insertions(+), 21 deletions(-) (limited to 'tests/unit') diff --git a/tests/unit/unittest/sqlitestatement-test.cpp b/tests/unit/unittest/sqlitestatement-test.cpp index c7da3971e4..6775d9e168 100644 --- a/tests/unit/unittest/sqlitestatement-test.cpp +++ b/tests/unit/unittest/sqlitestatement-test.cpp @@ -66,11 +66,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}; @@ -210,13 +232,24 @@ TEST_F(SqliteStatement, ColumnNames) ASSERT_THAT(columnNames, ElementsAre("name", "number")); } +TEST_F(SqliteStatement, BindNull) +{ + database.execute("INSERT INTO test VALUES (NULL, 323, 344)"); + SqliteTestStatement statement("SELECT name, number FROM test WHERE name IS ?", database); + + statement.bind(1, Sqlite::NullValue{}); + statement.next(); + + ASSERT_TRUE(statement.fetchValueView(0).isNull()); + ASSERT_THAT(statement.fetchValue(1), 323); +} + 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"); @@ -314,6 +347,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 +366,15 @@ TEST_F(SqliteStatement, WriteValues) ASSERT_THAT(statement, HasValues("see", "7.23", 1)); } +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); @@ -407,10 +459,11 @@ public: TEST_F(SqliteStatement, GetSingleSqliteValuesWithoutArguments) { ReadStatement statement("SELECT number FROM test", database); + database.execute("INSERT INTO test VALUES (NULL, NULL, NULL)"); std::vector values = statement.values(3); - ASSERT_THAT(values, ElementsAre(Eq("blah"), Eq(23.3), Eq(40))); + ASSERT_THAT(values, ElementsAre(Eq("blah"), Eq(23.3), Eq(40), IsNull())); } TEST_F(SqliteStatement, GetStructValuesWithoutArguments) @@ -710,19 +763,4 @@ TEST_F(SqliteStatement, ResetIfExecuteThrowsException) ASSERT_ANY_THROW(mockStatement.execute()); } - -void SqliteStatement::SetUp() -{ - 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 SqliteStatement::TearDown() -{ - if (database.isOpen()) - database.close(); -} - -} +} // namespace diff --git a/tests/unit/unittest/sqlitevalue-test.cpp b/tests/unit/unittest/sqlitevalue-test.cpp index e9cc5c9e40..ab4d628ec8 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,15 @@ TEST(SqliteValue, ConstructStringFromQString) ASSERT_THAT(value.toStringView(), Eq("foo")); } +TEST(SqliteValue, ConstructNullFromNullQVariant) +{ + QVariant variant{}; + + Sqlite::Value value{variant}; + + ASSERT_TRUE(value.isNull()); +} + TEST(SqliteValue, ConstructStringFromIntQVariant) { QVariant variant{1}; @@ -116,6 +139,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 +224,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 +287,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 +315,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 +378,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"); -- cgit v1.2.3 From dc2192ef8a6e4979482ed0e032c7b79ac35948ba Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Sat, 16 May 2020 01:29:22 +0200 Subject: Sqlite: Dont compile Utf-16 support We don't support it anyway. Change-Id: I35fa859f3c9d7389e3d00d584832a814acb39c80 Reviewed-by: Tim Jenssen --- tests/unit/unittest/sqlitedatabasebackend-test.cpp | 44 ---------------------- tests/unit/unittest/sqlitestatement-test.cpp | 9 ----- 2 files changed, 53 deletions(-) (limited to 'tests/unit') diff --git a/tests/unit/unittest/sqlitedatabasebackend-test.cpp b/tests/unit/unittest/sqlitedatabasebackend-test.cpp index 9957d3d4c7..2390bd4a3c 100644 --- a/tests/unit/unittest/sqlitedatabasebackend-test.cpp +++ b/tests/unit/unittest/sqlitedatabasebackend-test.cpp @@ -42,7 +42,6 @@ using Sqlite::ColumnType; 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/sqlitestatement-test.cpp b/tests/unit/unittest/sqlitestatement-test.cpp index 6775d9e168..d2e5377ba4 100644 --- a/tests/unit/unittest/sqlitestatement-test.cpp +++ b/tests/unit/unittest/sqlitestatement-test.cpp @@ -223,15 +223,6 @@ TEST_F(SqliteStatement, ToStringValue) ASSERT_THAT(ReadStatement::toValue("SELECT name FROM test WHERE name='foo'", database), "foo"); } -TEST_F(SqliteStatement, ColumnNames) -{ - SqliteTestStatement statement("SELECT name, number FROM test", database); - - auto columnNames = statement.columnNames(); - - ASSERT_THAT(columnNames, ElementsAre("name", "number")); -} - TEST_F(SqliteStatement, BindNull) { database.execute("INSERT INTO test VALUES (NULL, 323, 344)"); -- cgit v1.2.3 From 2f6a226dd39f7084003864d58b7830cc7da38c77 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Sat, 16 May 2020 01:52:40 +0200 Subject: Sqlite: Forbid double quotes which are not part of the SQL standard It's anyway easier to write single quotes. Change-Id: Ie71c39d9cdd83e0b898efe70a1912d8257ac991e Reviewed-by: Tim Jenssen --- tests/unit/unittest/symbolquery-test.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'tests/unit') 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: -- cgit v1.2.3 From 36fd58fbe97c2159eaec9bfebfb992531eb1e0ac Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Sat, 16 May 2020 14:27:41 +0200 Subject: Sqlite: Add carray extension from Sqlite and a pointer binding Change-Id: I96c160514ac80458cbcbff0151c685958de71fdd Reviewed-by: Tim Jenssen --- tests/unit/unittest/sqlitestatement-test.cpp | 62 ++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 3 deletions(-) (limited to 'tests/unit') diff --git a/tests/unit/unittest/sqlitestatement-test.cpp b/tests/unit/unittest/sqlitestatement-test.cpp index d2e5377ba4..94eb003c4d 100644 --- a/tests/unit/unittest/sqlitestatement-test.cpp +++ b/tests/unit/unittest/sqlitestatement-test.cpp @@ -277,6 +277,17 @@ TEST_F(SqliteStatement, BindDouble) ASSERT_THAT(statement.fetchSmallStringViewValue(0), "foo"); } +TEST_F(SqliteStatement, BindPointer) +{ + SqliteTestStatement statement("SELECT value FROM carray(?, 5, 'int64')", database); + std::vector values{1, 1, 2, 3, 5}; + + statement.bind(1, values.data()); + statement.next(); + + ASSERT_THAT(statement.fetchIntValue(0), 1); +} + TEST_F(SqliteStatement, BindIntegerByParameter) { SqliteTestStatement statement("SELECT name, number FROM test WHERE number=@number", database); @@ -307,18 +318,53 @@ TEST_F(SqliteStatement, BindDoubleByIndex) ASSERT_THAT(statement.fetchSmallStringViewValue(0), "foo"); } -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, BindIndexIsTpLargeIsThrowingBindingIndexIsOutOfBoundLongLong) +{ + SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database); + + ASSERT_THROW(statement.bind(2, 40LL), Sqlite::BindingIndexIsOutOfRange); +} + +TEST_F(SqliteStatement, BindIndexIsTpLargeIsThrowingBindingIndexIsOutOfBoundStringView) +{ + SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database); + + ASSERT_THROW(statement.bind(2, "foo"), Sqlite::BindingIndexIsOutOfRange); +} + +TEST_F(SqliteStatement, BindIndexIsTpLargeIsThrowingBindingIndexIsOutOfBoundStringFloat) +{ + SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database); + + ASSERT_THROW(statement.bind(2, 2.), Sqlite::BindingIndexIsOutOfRange); +} + +TEST_F(SqliteStatement, BindIndexIsTpLargeIsThrowingBindingIndexIsOutOfBoundPointer) +{ + SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database); + + ASSERT_THROW(statement.bind(2, nullptr), Sqlite::BindingIndexIsOutOfRange); +} + +TEST_F(SqliteStatement, BindIndexIsTpLargeIsThrowingBindingIndexIsOutOfBoundValue) { SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database); - ASSERT_THROW(statement.bind(2, 40), Sqlite::BindingIndexIsOutOfRange); + ASSERT_THROW(statement.bind(2, Sqlite::Value{1}), Sqlite::BindingIndexIsOutOfRange); } TEST_F(SqliteStatement, WrongBindingNameThrowingBindingIndexIsOutOfBound) @@ -357,6 +403,16 @@ 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 values{1, 1, 2, 3, 5}; + + statement.write(values.data(), int(values.size())); + + ASSERT_THAT(statement.template values(5), ElementsAre(1, 1, 2, 3, 5)); +} + TEST_F(SqliteStatement, WriteNullValues) { WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); -- cgit v1.2.3 From 55d1f6b46e2797a6027ff99860743639594c94ce Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Sat, 16 May 2020 14:53:58 +0200 Subject: Sqlite: Relax LastChangedRowId Change-Id: Ibc4637ebafd4c0cdedfcea5c52da5025435bc4ab Reviewed-by: Tim Jenssen --- tests/unit/unittest/lastchangedrowid-test.cpp | 155 ++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) (limited to 'tests/unit') diff --git a/tests/unit/unittest/lastchangedrowid-test.cpp b/tests/unit/unittest/lastchangedrowid-test.cpp index da33dd6098..d23d81ae73 100644 --- a/tests/unit/unittest/lastchangedrowid-test.cpp +++ b/tests/unit/unittest/lastchangedrowid-test.cpp @@ -287,4 +287,159 @@ TEST_F(LastChangedRowIdWithThreeTables, TakeLastRowIdResetsRowIdToMinusOne) ASSERT_THAT(id, -1); } +class LastChangedRowIdWithNoDatabaseAndTable : public testing::Test +{ +protected: + NiceMock 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; + Sqlite::LastChangedRowId lastRowId{mockSqliteDatabase}; +}; + +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); +} } // namespace -- cgit v1.2.3 From 75da71e1fad596d6926ac2800b812f2025d55102 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Sat, 16 May 2020 14:54:11 +0200 Subject: Sqlite: Fix test Change-Id: I04de9c429b7779c5c4ecde4a4a44e3b5e60699b3 Reviewed-by: Tim Jenssen --- tests/unit/unittest/createtablesqlstatementbuilder-test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests/unit') diff --git a/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp b/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp index c80ce9d96f..33231d92c3 100644 --- a/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp +++ b/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp @@ -454,7 +454,7 @@ TEST_F(CreateTableSqlStatementBuilder, DefaultValueString) builder.addColumn("id", ColumnType::Text, {Sqlite::DefaultValue{"foo"}}); - ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id TEXT DEFAULT \"foo\")"); + ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id TEXT DEFAULT 'foo')"); } TEST_F(CreateTableSqlStatementBuilder, DefaultExpression) -- cgit v1.2.3 From 64cbffe959c2dd10730818577a61d7fabeb734ea Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Fri, 22 May 2020 19:04:03 +0200 Subject: UnitTests: Fix LastChangedRowId Change-Id: I538d068168488eee2662618dede598135c45e396 Reviewed-by: Thomas Hartmann --- tests/unit/unittest/lastchangedrowid-test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests/unit') diff --git a/tests/unit/unittest/lastchangedrowid-test.cpp b/tests/unit/unittest/lastchangedrowid-test.cpp index d23d81ae73..7214955eda 100644 --- a/tests/unit/unittest/lastchangedrowid-test.cpp +++ b/tests/unit/unittest/lastchangedrowid-test.cpp @@ -369,7 +369,7 @@ class LastChangedRowIdWithNoTable : public testing::Test { protected: NiceMock mockSqliteDatabase; - Sqlite::LastChangedRowId lastRowId{mockSqliteDatabase}; + Sqlite::LastChangedRowId lastRowId{mockSqliteDatabase, "main"}; }; TEST_F(LastChangedRowIdWithNoTable, SetUpdateHookInContructor) -- cgit v1.2.3 From 22c33fb859a4c0d9d694edca2076708b1cf2f087 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Tue, 26 May 2020 20:31:07 +0200 Subject: Sqlite: Improve LastChangedRowId Change-Id: I2fe559d4b40f93561e44eb138119416291dc7d41 Reviewed-by: Thomas Hartmann --- tests/unit/unittest/lastchangedrowid-test.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'tests/unit') diff --git a/tests/unit/unittest/lastchangedrowid-test.cpp b/tests/unit/unittest/lastchangedrowid-test.cpp index 7214955eda..07b29bee57 100644 --- a/tests/unit/unittest/lastchangedrowid-test.cpp +++ b/tests/unit/unittest/lastchangedrowid-test.cpp @@ -442,4 +442,30 @@ TEST_F(LastChangedRowIdWithNoTable, TakeLastRowIdResetsRowIdToMinusOne) 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 -- cgit v1.2.3 From 9c44f8d88d7ad80d22842545925f3e694afed182 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Tue, 26 May 2020 20:31:41 +0200 Subject: Sqlite: Add blob support Change-Id: Ic2ec5f20c8585241b9e9aaa8465e70b6ab4f004c Reviewed-by: Thomas Hartmann --- tests/unit/unittest/google-using-declarations.h | 1 + tests/unit/unittest/gtest-creator-printing.h | 20 ++++ tests/unit/unittest/sqlitestatement-test.cpp | 124 +++++++++++++++++++++++- tests/unit/unittest/sqlitevalue-test.cpp | 9 ++ 4 files changed, 149 insertions(+), 5 deletions(-) (limited to 'tests/unit') diff --git a/tests/unit/unittest/google-using-declarations.h b/tests/unit/unittest/google-using-declarations.h index a1975ae7a8..1a92ff3388 100644 --- a/tests/unit/unittest/google-using-declarations.h +++ b/tests/unit/unittest/google-using-declarations.h @@ -58,6 +58,7 @@ using testing::Ne; using testing::NiceMock; using testing::Not; using testing::NotNull; +using testing::Optional; using testing::Pair; using testing::PrintToString; using testing::Property; diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h index b91c8d46be..ea33bc9d49 100644 --- a/tests/unit/unittest/gtest-creator-printing.h +++ b/tests/unit/unittest/gtest-creator-printing.h @@ -348,4 +348,24 @@ std::ostream &operator<<(std::ostream &out, const Diagnostic &diag); } // namespace Internal } // namespace CppTools +namespace std { +template +ostream &operator<<(ostream &out, const vector &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/sqlitestatement-test.cpp b/tests/unit/unittest/sqlitestatement-test.cpp index 94eb003c4d..ce40e0c3d8 100644 --- a/tests/unit/unittest/sqlitestatement-test.cpp +++ b/tests/unit/unittest/sqlitestatement-test.cpp @@ -38,6 +38,14 @@ #include +namespace Sqlite { +bool operator==(Utils::span first, Utils::span second) +{ + return first.size() == second.size() + && std::memcmp(first.data(), second.data(), first.size()) == 0; +} +} // namespace Sqlite + namespace { using Sqlite::Database; @@ -288,6 +296,30 @@ TEST_F(SqliteStatement, BindPointer) ASSERT_THAT(statement.fetchIntValue(0), 1); } +TEST_F(SqliteStatement, BindBlob) +{ + SqliteTestStatement statement("WITH T(blob) AS (VALUES (?)) SELECT blob FROM T", database); + const unsigned char chars[] = "aaafdfdlll"; + auto bytePointer = reinterpret_cast(chars); + Utils::span bytes{bytePointer, sizeof(chars) - 1}; + + statement.bind(1, bytes); + statement.next(); + + ASSERT_THAT(statement.fetchBlobValue(0), Eq(bytes)); +} + +TEST_F(SqliteStatement, BindEmptyBlob) +{ + SqliteTestStatement statement("WITH T(blob) AS (VALUES (?)) SELECT blob FROM T", database); + Utils::span bytes; + + statement.bind(1, bytes); + statement.next(); + + ASSERT_THAT(statement.fetchBlobValue(0), IsEmpty()); +} + TEST_F(SqliteStatement, BindIntegerByParameter) { SqliteTestStatement statement("SELECT name, number FROM test WHERE number=@number", database); @@ -332,41 +364,49 @@ TEST_F(SqliteStatement, BindIndexIsZeroIsThrowingBindingIndexIsOutOfBoundNull) ASSERT_THROW(statement.bind(0, Sqlite::NullValue{}), Sqlite::BindingIndexIsOutOfRange); } -TEST_F(SqliteStatement, BindIndexIsTpLargeIsThrowingBindingIndexIsOutOfBoundLongLong) +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, BindIndexIsTpLargeIsThrowingBindingIndexIsOutOfBoundStringView) +TEST_F(SqliteStatement, BindIndexIsToLargeIsThrowingBindingIndexIsOutOfBoundStringView) { SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database); ASSERT_THROW(statement.bind(2, "foo"), Sqlite::BindingIndexIsOutOfRange); } -TEST_F(SqliteStatement, BindIndexIsTpLargeIsThrowingBindingIndexIsOutOfBoundStringFloat) +TEST_F(SqliteStatement, BindIndexIsToLargeIsThrowingBindingIndexIsOutOfBoundStringFloat) { SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database); ASSERT_THROW(statement.bind(2, 2.), Sqlite::BindingIndexIsOutOfRange); } -TEST_F(SqliteStatement, BindIndexIsTpLargeIsThrowingBindingIndexIsOutOfBoundPointer) +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, BindIndexIsTpLargeIsThrowingBindingIndexIsOutOfBoundValue) +TEST_F(SqliteStatement, BindIndexIsToLargeIsThrowingBindingIndexIsOutOfBoundValue) { SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database); 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 bytes; + + ASSERT_THROW(statement.bind(2, bytes), Sqlite::BindingIndexIsOutOfRange); +} + TEST_F(SqliteStatement, WrongBindingNameThrowingBindingIndexIsOutOfBound) { SqliteTestStatement statement("SELECT name, number FROM test WHERE number=@name", database); @@ -431,6 +471,40 @@ TEST_F(SqliteStatement, WriteSqliteValues) ASSERT_THAT(statement, HasValues("see", "7.23", 1)); } +TEST_F(SqliteStatement, WriteEmptyBlobs) +{ + SqliteTestStatement statement("WITH T(blob) AS (VALUES (?)) SELECT blob FROM T", database); + + Utils::span bytes; + + statement.write(bytes); + + ASSERT_THAT(statement.fetchBlobValue(0), IsEmpty()); +} + +class Blob +{ +public: + Blob(Utils::span bytes) + : bytes(bytes.begin(), bytes.end()) + {} + + std::vector bytes; +}; + +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(chars); + Utils::span bytes{bytePointer, sizeof(chars) - 1}; + + statement.write(bytes); + + ASSERT_THAT(readStatement.template value(), Optional(Field(&Blob::bytes, Eq(bytes)))); +} + TEST_F(SqliteStatement, BindNamedValues) { SqliteTestStatement statement("UPDATE test SET name=@name, number=@number WHERE rowid=@id", database); @@ -633,6 +707,46 @@ TEST_F(SqliteStatement, GetStructOutputValuesAndContainerQueryTupleValues) 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(&value); + Utils::span bytes{bytePointer, 4}; + + auto values = statement.values(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(); + + 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(); + + 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(); + + ASSERT_THAT(value, Optional(Field(&Blob::bytes, IsEmpty()))); +} + TEST_F(SqliteStatement, GetOptionalSingleValueAndMultipleQueryValue) { ReadStatement statement("SELECT name FROM test WHERE name=? AND number=? AND value=?", database); diff --git a/tests/unit/unittest/sqlitevalue-test.cpp b/tests/unit/unittest/sqlitevalue-test.cpp index ab4d628ec8..1a90c330f0 100644 --- a/tests/unit/unittest/sqlitevalue-test.cpp +++ b/tests/unit/unittest/sqlitevalue-test.cpp @@ -85,6 +85,15 @@ TEST(SqliteValue, ConstructStringFromQString) ASSERT_THAT(value.toStringView(), Eq("foo")); } +TEST(SqliteValue, ConstructStringFromBlob) +{ + // Utils::span bytes{reinterpret_cast("abcd"), 4}; + + // Sqlite::Value value{bytes}; + + //ASSERT_THAT(value.toBlob(), Eq(bytes)); +} + TEST(SqliteValue, ConstructNullFromNullQVariant) { QVariant variant{}; -- cgit v1.2.3 From 9f9140b196bb28d0b4fcb13b1a37ea4e6e14fe56 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Tue, 26 May 2020 23:01:52 +0200 Subject: Sqlite: Remove unused code Binding by names is slower and we never used it. Change-Id: Ia6b9b78401f8c2711be34b667ac6f08b44418773 Reviewed-by: Thomas Hartmann --- tests/unit/unittest/mocksqlitestatement.h | 1 - tests/unit/unittest/sqlitestatement-test.cpp | 69 ---------------------------- 2 files changed, 70 deletions(-) (limited to 'tests/unit') diff --git a/tests/unit/unittest/mocksqlitestatement.h b/tests/unit/unittest/mocksqlitestatement.h index 26f5b0de6e..351c6708a5 100644 --- a/tests/unit/unittest/mocksqlitestatement.h +++ b/tests/unit/unittest/mocksqlitestatement.h @@ -52,7 +52,6 @@ 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)); }; diff --git a/tests/unit/unittest/sqlitestatement-test.cpp b/tests/unit/unittest/sqlitestatement-test.cpp index ce40e0c3d8..2b8942dbf1 100644 --- a/tests/unit/unittest/sqlitestatement-test.cpp +++ b/tests/unit/unittest/sqlitestatement-test.cpp @@ -320,36 +320,6 @@ TEST_F(SqliteStatement, BindEmptyBlob) ASSERT_THAT(statement.fetchBlobValue(0), IsEmpty()); } -TEST_F(SqliteStatement, BindIntegerByParameter) -{ - SqliteTestStatement statement("SELECT name, number FROM test WHERE number=@number", database); - - statement.bind("@number", 40); - statement.next(); - - ASSERT_THAT(statement.fetchSmallStringViewValue(0), "poo"); -} - -TEST_F(SqliteStatement, BindLongIntegerByParameter) -{ - SqliteTestStatement statement("SELECT name, number FROM test WHERE number=@number", database); - - statement.bind("@number", int64_t(40)); - statement.next(); - - ASSERT_THAT(statement.fetchSmallStringViewValue(0), "poo"); -} - -TEST_F(SqliteStatement, BindDoubleByIndex) -{ - SqliteTestStatement statement("SELECT name, number FROM test WHERE number=@number", database); - - statement.bind(statement.bindingIndexForName("@number"), 23.3); - statement.next(); - - ASSERT_THAT(statement.fetchSmallStringViewValue(0), "foo"); -} - TEST_F(SqliteStatement, BindIndexIsZeroIsThrowingBindingIndexIsOutOfBoundInt) { SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database); @@ -407,13 +377,6 @@ TEST_F(SqliteStatement, BindIndexIsToLargeIsThrowingBindingIndexIsOutOfBoundBlob ASSERT_THROW(statement.bind(2, bytes), Sqlite::BindingIndexIsOutOfRange); } -TEST_F(SqliteStatement, WrongBindingNameThrowingBindingIndexIsOutOfBound) -{ - SqliteTestStatement statement("SELECT name, number FROM test WHERE number=@name", database); - - ASSERT_THROW(statement.bind("@name2", 40), Sqlite::WrongBindingName); -} - TEST_F(SqliteStatement, BindValues) { SqliteTestStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); @@ -505,25 +468,6 @@ TEST_F(SqliteStatement, WriteBlobs) ASSERT_THAT(readStatement.template value(), Optional(Field(&Blob::bytes, Eq(bytes)))); } -TEST_F(SqliteStatement, BindNamedValues) -{ - SqliteTestStatement statement("UPDATE test SET name=@name, number=@number WHERE rowid=@id", database); - - statement.bindNameValues("@name", "see", "@number", 7.23, "@id", 1); - statement.execute(); - - ASSERT_THAT(statement, HasValues("see", "7.23", 1)); -} - -TEST_F(SqliteStatement, WriteNamedValues) -{ - WriteStatement statement("UPDATE test SET name=@name, number=@number WHERE rowid=@id", database); - - statement.writeNamed("@name", "see", "@number", 7.23, "@id", 1); - - ASSERT_THAT(statement, HasValues("see", "7.23", 1)); -} - TEST_F(SqliteStatement, CannotWriteToClosedDatabase) { database.close(); @@ -902,19 +846,6 @@ TEST_F(SqliteStatement, ResetIfWriteIsThrowingException) ASSERT_ANY_THROW(mockStatement.write("bar")); } -TEST_F(SqliteStatement, ResetIfWriteNamedIsThrowingException) -{ - MockSqliteStatement mockStatement; - - EXPECT_CALL(mockStatement, bindingIndexForName(TypedEq("@foo"))) - .WillOnce(Return(1)); - EXPECT_CALL(mockStatement, bind(1, TypedEq("bar"))) - .WillOnce(Throw(Sqlite::StatementIsBusy(""))); - EXPECT_CALL(mockStatement, reset()); - - ASSERT_ANY_THROW(mockStatement.writeNamed("@foo", "bar")); -} - TEST_F(SqliteStatement, ResetIfExecuteThrowsException) { MockSqliteStatement mockStatement; -- cgit v1.2.3 From a9a205486d734fcdbba561f5fac248ca530b6d14 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 27 May 2020 00:09:19 +0200 Subject: Sqlite: Improve SqliteStatement column check We have done it for every getter. Now we do it only once as we ask for the values. It simplifies the code and the test and could even improve performance. Change-Id: Ia7d4a33a77ec7c0a5fda548424fbf8b192f07511 Reviewed-by: Thomas Hartmann --- tests/unit/unittest/mocksqlitestatement.h | 4 +- tests/unit/unittest/sqlitestatement-test.cpp | 78 ++++++++++++++++------------ 2 files changed, 48 insertions(+), 34 deletions(-) (limited to 'tests/unit') diff --git a/tests/unit/unittest/mocksqlitestatement.h b/tests/unit/unittest/mocksqlitestatement.h index 351c6708a5..7be7f3f05e 100644 --- a/tests/unit/unittest/mocksqlitestatement.h +++ b/tests/unit/unittest/mocksqlitestatement.h @@ -53,7 +53,9 @@ public: MOCK_METHOD2(bind, void (int, Utils::SmallStringView)); MOCK_METHOD2(bind, void (int, long)); - 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/sqlitestatement-test.cpp b/tests/unit/unittest/sqlitestatement-test.cpp index 2b8942dbf1..4b59d52af2 100644 --- a/tests/unit/unittest/sqlitestatement-test.cpp +++ b/tests/unit/unittest/sqlitestatement-test.cpp @@ -178,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(0), Sqlite::NoValuesToFetch); -} - -TEST_F(SqliteStatement, ThrowNoValuesToFetchForDoneStatement) -{ - SqliteTestStatement statement("SELECT name, number FROM test", database); - while (statement.next()) {} - - ASSERT_THROW(statement.fetchValue(0), Sqlite::NoValuesToFetch); -} - -TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForNegativeColumn) -{ - SqliteTestStatement statement("SELECT name, number FROM test", database); - statement.next(); - - ASSERT_THROW(statement.fetchValue(-1), Sqlite::InvalidColumnFetched); -} - -TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForNotExistingColumn) -{ - SqliteTestStatement statement("SELECT name, number FROM test", database); - statement.next(); - - ASSERT_THROW(statement.fetchValue(2), Sqlite::InvalidColumnFetched); -} - TEST_F(SqliteStatement, ToIntegerValue) { auto value = ReadStatement::toValue("SELECT number FROM test WHERE name='foo'", database); @@ -567,7 +536,7 @@ TEST_F(SqliteStatement, GetValuesForMultipleOutputValuesAndContainerQueryValues) TEST_F(SqliteStatement, GetValuesForSingleOutputValuesAndContainerQueryValues) { std::vector 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 values = statement.values(3, queryValues); @@ -591,7 +560,7 @@ TEST_F(SqliteStatement, GetValuesForSingleOutputValuesAndContainerQueryTupleValu { using Tuple = std::tuple; std::vector 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 values = statement.values(3, queryValues); @@ -855,4 +824,47 @@ TEST_F(SqliteStatement, ResetIfExecuteThrowsException) ASSERT_ANY_THROW(mockStatement.execute()); } + +TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForToManyArgumentsForValue) +{ + SqliteTestStatement statement("SELECT name, number FROM test", database); + + ASSERT_THROW(statement.value(), Sqlite::ColumnCountDoesNotMatch); +} + +TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForToManyArgumentsForValues) +{ + SqliteTestStatement statement("SELECT name, number FROM test", database); + + ASSERT_THROW(statement.values(1), Sqlite::ColumnCountDoesNotMatch); +} + +TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForToManyArgumentsForValuesWithArguments) +{ + SqliteTestStatement statement("SELECT name, number FROM test WHERE name=?", database); + + ASSERT_THROW(statement.values(1, 2), Sqlite::ColumnCountDoesNotMatch); +} + +TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForToManyArgumentsForValuesWithVectorArguments) +{ + SqliteTestStatement statement("SELECT name, number FROM test", database); + + ASSERT_THROW(statement.values(1, std::vector{}), Sqlite::ColumnCountDoesNotMatch); +} + +TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForToManyArgumentsForValuesWithTupleArguments) +{ + SqliteTestStatement statement("SELECT name, number FROM test", database); + + ASSERT_THROW(statement.values(1, std::vector>{}), + Sqlite::ColumnCountDoesNotMatch); +} + +TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForToManyArgumentsForToValues) +{ + ASSERT_THROW(SqliteTestStatement::toValue("SELECT name, number FROM test", database), + Sqlite::ColumnCountDoesNotMatch); +} + } // namespace -- cgit v1.2.3 From a61eff007900ba572a40fc4116e1f217cd83c36f Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 27 May 2020 23:48:03 +0200 Subject: Sqlite: Add session support Session are captured by hooking in the sqlite changes. They are saved in blobs and containing inserts, update and deletes. Because the are semantically coupled to translactions we add a Change-Id: Ie095558ebc50601fcaae32958ebeeb98b72d73b9 Reviewed-by: Tim Jenssen --- .../createtablesqlstatementbuilder-test.cpp | 20 + tests/unit/unittest/data/sqlite_database.db | Bin 4096 -> 12288 bytes tests/unit/unittest/gtest-creator-printing.cpp | 87 ++++ tests/unit/unittest/gtest-creator-printing.h | 2 + tests/unit/unittest/mocksqlitedatabase.h | 4 + tests/unit/unittest/mocksqlitetransactionbackend.h | 3 + tests/unit/unittest/sqlitedatabase-test.cpp | 43 +- tests/unit/unittest/sqlitesessions-test.cpp | 443 +++++++++++++++++++++ tests/unit/unittest/sqlitestatement-test.cpp | 29 +- tests/unit/unittest/sqlitetransaction-test.cpp | 59 ++- tests/unit/unittest/unittest.pro | 1 + tests/unit/unittest/unittests-main.cpp | 3 +- 12 files changed, 671 insertions(+), 23 deletions(-) create mode 100644 tests/unit/unittest/sqlitesessions-test.cpp (limited to 'tests/unit') diff --git a/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp b/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp index 33231d92c3..49099081a0 100644 --- a/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp +++ b/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp @@ -510,4 +510,24 @@ TEST_F(CreateTableSqlStatementBuilder, GeneratedAlwaysVirtual) "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)"); +} + } // namespace diff --git a/tests/unit/unittest/data/sqlite_database.db b/tests/unit/unittest/data/sqlite_database.db index 9c5879579e..5a7284d087 100644 Binary files a/tests/unit/unittest/data/sqlite_database.db and b/tests/unit/unittest/data/sqlite_database.db differ diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp index 6d5f7a2cf3..eab506e344 100644 --- a/tests/unit/unittest/gtest-creator-printing.cpp +++ b/tests/unit/unittest/gtest-creator-printing.cpp @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,8 @@ #include #include +#include + 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(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 ea33bc9d49..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 { diff --git a/tests/unit/unittest/mocksqlitedatabase.h b/tests/unit/unittest/mocksqlitedatabase.h index 97d5394339..c627f995a4 100644 --- a/tests/unit/unittest/mocksqlitedatabase.h +++ b/tests/unit/unittest/mocksqlitedatabase.h @@ -63,5 +63,9 @@ public: 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/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/sqlitedatabase-test.cpp b/tests/unit/unittest/sqlitedatabase-test.cpp index ff3436c459..5d7fdb1e54 100644 --- a/tests/unit/unittest/sqlitedatabase-test.cpp +++ b/tests/unit/unittest/sqlitedatabase-test.cpp @@ -28,6 +28,7 @@ #include "spydummy.h" #include +#include #include #include #include @@ -50,26 +51,33 @@ 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 names() const + { + return Sqlite::ReadStatement("SELECT name FROM test", database).values(8); + } + +protected: SpyDummy spyDummy; QString databaseFilePath{":memory:"}; - Sqlite::Database database; + mutable Sqlite::Database database; Sqlite::TransactionInterface &transactionInterface = database; MockFunction callbackMock; Sqlite::Database::UpdateCallback callback = callbackMock.AsStdFunction(); @@ -307,4 +315,33 @@ TEST_F(SqliteDatabase, TableUpdateHookCall) 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/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 +#include +#include +#include +#include +#include + +#include + +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 fetchData() { return selectData.values(8); } + std::vector fetchTags() { return selectTags.values(8); } + SessionChangeSets fetchChangeSets() { return selectChangeSets.values(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 4b59d52af2..a7dd5d5f9b 100644 --- a/tests/unit/unittest/sqlitestatement-test.cpp +++ b/tests/unit/unittest/sqlitestatement-test.cpp @@ -460,9 +460,8 @@ TEST_F(SqliteStatement, GetTupleValuesWithoutArguments) auto values = statement.values(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) @@ -471,7 +470,7 @@ TEST_F(SqliteStatement, GetSingleValuesWithoutArguments) std::vector values = statement.values(3); - ASSERT_THAT(values, ElementsAre("bar", "foo", "poo")); + ASSERT_THAT(values, UnorderedElementsAre("bar", "foo", "poo")); } class FooValue @@ -497,7 +496,7 @@ TEST_F(SqliteStatement, GetSingleSqliteValuesWithoutArguments) std::vector values = statement.values(3); - ASSERT_THAT(values, ElementsAre(Eq("blah"), Eq(23.3), Eq(40), IsNull())); + ASSERT_THAT(values, UnorderedElementsAre(Eq("blah"), Eq(23.3), Eq(40), IsNull())); } TEST_F(SqliteStatement, GetStructValuesWithoutArguments) @@ -506,9 +505,10 @@ TEST_F(SqliteStatement, GetStructValuesWithoutArguments) auto values = statement.values(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) @@ -529,8 +529,7 @@ TEST_F(SqliteStatement, GetValuesForMultipleOutputValuesAndContainerQueryValues) auto values = statement.values(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) @@ -540,7 +539,7 @@ TEST_F(SqliteStatement, GetValuesForSingleOutputValuesAndContainerQueryValues) std::vector values = statement.values(3, queryValues); - ASSERT_THAT(values, ElementsAre("poo", "foo")); + ASSERT_THAT(values, UnorderedElementsAre("poo", "foo")); } TEST_F(SqliteStatement, GetValuesForMultipleOutputValuesAndContainerQueryTupleValues) @@ -552,8 +551,7 @@ TEST_F(SqliteStatement, GetValuesForMultipleOutputValuesAndContainerQueryTupleVa auto values = statement.values(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) @@ -564,7 +562,7 @@ TEST_F(SqliteStatement, GetValuesForSingleOutputValuesAndContainerQueryTupleValu std::vector values = statement.values(3, queryValues); - ASSERT_THAT(values, ElementsAre("poo", "bar")); + ASSERT_THAT(values, UnorderedElementsAre("poo", "bar")); } TEST_F(SqliteStatement, GetValuesForMultipleOutputValuesAndMultipleQueryValue) @@ -616,8 +614,7 @@ TEST_F(SqliteStatement, GetStructOutputValuesAndContainerQueryTupleValues) auto values = statement.values(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) 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/unittest.pro b/tests/unit/unittest/unittest.pro index 7340f00775..03f04f3982 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -81,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 #include - #include #include @@ -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()); -- cgit v1.2.3 From cf441e8198b4bb7ccf41a41506dbddbab2048f24 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Tue, 2 Jun 2020 22:16:06 +0200 Subject: Sqlite: Add primary key table constraint to table builder Change-Id: I60c158eb76db2217a2d045053bb8e47eef75ff7a Reviewed-by: Tim Jenssen --- tests/unit/unittest/createtablesqlstatementbuilder-test.cpp | 13 +++++++++++++ tests/unit/unittest/sqlitetable-test.cpp | 13 +++++++++++++ 2 files changed, 26 insertions(+) (limited to 'tests/unit') diff --git a/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp b/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp index 49099081a0..0e92b06897 100644 --- a/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp +++ b/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp @@ -530,4 +530,17 @@ TEST_F(CreateTableSqlStatementBuilder, BlobType) 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/sqlitetable-test.cpp b/tests/unit/unittest/sqlitetable-test.cpp index 05d3e73462..f96b451785 100644 --- a/tests/unit/unittest/sqlitetable-test.cpp +++ b/tests/unit/unittest/sqlitetable-test.cpp @@ -292,4 +292,17 @@ TEST_F(SqliteTable, AddForeignKeyColumnWithColumnAndNotNull) VariantWith(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 -- cgit v1.2.3 From 42cad8970819c650c73f5daa4b6ea2f775ff7ad0 Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Mon, 8 Jun 2020 15:00:46 +0200 Subject: fix tests Change-Id: I5a0f10e6afb85dc0306e224710d2c103f24404f3 Reviewed-by: Tim Jenssen --- tests/unit/unittest/pchcreator-test.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'tests/unit') diff --git a/tests/unit/unittest/pchcreator-test.cpp b/tests/unit/unittest/pchcreator-test.cpp index ad5b57b4f5..a59814d30f 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}}, -- cgit v1.2.3