diff options
author | Marco Bubke <marco.bubke@qt.io> | 2020-09-16 13:44:43 +0200 |
---|---|---|
committer | Tim Jenssen <tim.jenssen@qt.io> | 2020-10-16 10:01:21 +0000 |
commit | d1b0c12d6b6c4698492851716b3931bc9cae5fd3 (patch) | |
tree | 9aa7d8fddbafced065e392b84939c59d6ae8726e /tests | |
parent | 58e612c85fb8320fd99a28d573372220cbfe309a (diff) |
QmlDesigner: Add image cache
The image cache is saving images and icon of this images in a sqlite
database. If there are no images they are generated in the backgound.
The icons are fetched by item library.
Task-number: QDS-2782
Task-number: QDS-2783
Task-number: QDS-2858
Change-Id: I5a32cccfef7f8fd8eb78902605a09f5da18ce88e
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
Diffstat (limited to 'tests')
26 files changed, 1725 insertions, 39 deletions
diff --git a/tests/unit/mockup/qmldesigner/designercore/include/nodeinstanceview.h b/tests/unit/mockup/qmldesigner/designercore/include/nodeinstanceview.h index 50d0e22a2d..50dcf529b6 100644 --- a/tests/unit/mockup/qmldesigner/designercore/include/nodeinstanceview.h +++ b/tests/unit/mockup/qmldesigner/designercore/include/nodeinstanceview.h @@ -28,6 +28,10 @@ #include "qmldesignercorelib_global.h" #include "abstractview.h" +namespace ProjectExplorer { +class Target; +} + namespace QmlDesigner { class NodeInstanceView : public AbstractView @@ -88,6 +92,8 @@ public: void requestModelNodePreviewImage(const ModelNode &node) {} void sendToken(const QString &token, int number, const QVector<ModelNode> &nodeVector) {} + void setTarget(ProjectExplorer::Target *newTarget) {} + void setCrashCallback(std::function<void()>) {} }; } // namespace QmlDesigner diff --git a/tests/unit/unittest/CMakeLists.txt b/tests/unit/unittest/CMakeLists.txt index ff0c1abaad..13741ae478 100644 --- a/tests/unit/unittest/CMakeLists.txt +++ b/tests/unit/unittest/CMakeLists.txt @@ -174,6 +174,19 @@ add_qtc_test(unittest GTEST sqlstatementbuilder-test.cpp createtablesqlstatementbuilder-test.cpp sqlitevalue-test.cpp + imagecache-test.cpp + imagecachegenerator-test.cpp + imagecachestorage-test.cpp + sqlitedatabasemock.h + sqlitereadstatementmock.cpp sqlitereadstatementmock.h + sqlitestatementmock.h + sqlitetransactionbackendmock.h + sqlitewritestatementmock.cpp sqlitewritestatementmock.h + notification.h + mocktimestampprovider.h + imagecachecollectormock.h + mockimagecachegenerator.h + mockimagecachestorage.h ) function(extend_qtc_test_with_target_sources target) @@ -335,6 +348,7 @@ extend_qtc_test(unittest "${QmlDesignerDir}" "${QmlDesignerDir}/designercore" "${QmlDesignerDir}/designercore/include" + "${QmlDesignerDir}/designercore/imagecache" "${QmlDesignerDir}/../../../share/qtcreator/qml/qmlpuppet/interfaces" "${QmlDesignerDir}/../../../share/qtcreator/qml/qmlpuppet/types" DEFINES @@ -382,6 +396,13 @@ extend_qtc_test(unittest model/signalhandlerproperty.cpp include/signalhandlerproperty.h model/variantproperty.cpp include/variantproperty.h rewritertransaction.cpp rewritertransaction.h + imagecache/imagecache.cpp include/imagecache.h + imagecache/imagecachecollectorinterface.h + imagecache/imagecachegenerator.cpp imagecache/imagecachegenerator.h + imagecache/imagecachegeneratorinterface.h + imagecache/imagecachestorage.h + imagecache/imagecachestorageinterface.h + imagecache/timestampproviderinterface.h include/qmldesignercorelib_global.h diff --git a/tests/unit/unittest/gmock_dependency.pri b/tests/unit/unittest/gmock_dependency.pri index 1af7b95f09..614c6379d3 100644 --- a/tests/unit/unittest/gmock_dependency.pri +++ b/tests/unit/unittest/gmock_dependency.pri @@ -14,10 +14,8 @@ defineTest(setGoogleTestDirectories) { } isEmpty(GOOGLETEST_DIR) { - exists($$PWD/../../../../googletest) { - setGoogleTestDirectories($$PWD/../../../../googletest) - } else: exists($$PWD/../../../../../googletest) { - setGoogleTestDirectories($$PWD/../../../../../googletest) + exists($$PWD/3rdparty/googletest) { + setGoogleTestDirectories($$PWD/3rdparty/googletest) } else: linux { GTEST_INCLUDE_DIR = /usr/include/gtest GMOCK_INCLUDE_DIR = /usr/include/gmock diff --git a/tests/unit/unittest/google-using-declarations.h b/tests/unit/unittest/google-using-declarations.h index 99514fe9b4..4419c8236d 100644 --- a/tests/unit/unittest/google-using-declarations.h +++ b/tests/unit/unittest/google-using-declarations.h @@ -35,12 +35,16 @@ using testing::An; using testing::AnyNumber; using testing::AnyOf; using testing::Assign; +using testing::AtLeast; +using testing::AtMost; +using testing::Between; using testing::ByMove; using testing::ByRef; using testing::ContainerEq; using testing::Contains; using testing::ElementsAre; using testing::Eq; +using testing::Exactly; using testing::Field; using testing::Ge; using testing::Gt; diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp index 8d84ad4d2e..c9c871475d 100644 --- a/tests/unit/unittest/gtest-creator-printing.cpp +++ b/tests/unit/unittest/gtest-creator-printing.cpp @@ -70,6 +70,7 @@ #include <usedmacro.h> #include <utils/link.h> #include <variantproperty.h> +#include <qmldesigner/designercore/imagecache/imagecachestorageinterface.h> #include <sqlite3ext.h> @@ -1468,6 +1469,15 @@ std::ostream &operator<<(std::ostream &out, const VariantProperty &property) return out << "(" << property.parentModelNode() << ", " << property.name() << ", " << property.value() << ")"; } + +namespace Internal { +std::ostream &operator<<(std::ostream &out, const ImageCacheStorageEntry &entry) +{ + return out << "(" << entry.image << ", " << entry.hasEntry << ")"; +} + +} // namespace Internal + } // namespace QmlDesigner void setFilePathCache(ClangBackEnd::FilePathCaching *cache) diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h index 565479be03..cdef782578 100644 --- a/tests/unit/unittest/gtest-creator-printing.h +++ b/tests/unit/unittest/gtest-creator-printing.h @@ -356,6 +356,13 @@ class VariantProperty; std::ostream &operator<<(std::ostream &out, const ModelNode &node); std::ostream &operator<<(std::ostream &out, const VariantProperty &property); + +namespace Internal { +class ImageCacheStorageEntry; + +std::ostream &operator<<(std::ostream &out, const ImageCacheStorageEntry &entry); + +} // namespace Internal } // namespace QmlDesigner void setFilePathCache(ClangBackEnd::FilePathCaching *filePathCache); diff --git a/tests/unit/unittest/gtest-qt-printing.cpp b/tests/unit/unittest/gtest-qt-printing.cpp index c097fd0b4c..445ebf7f51 100644 --- a/tests/unit/unittest/gtest-qt-printing.cpp +++ b/tests/unit/unittest/gtest-qt-printing.cpp @@ -85,6 +85,11 @@ std::ostream &operator<<(std::ostream &out, const QTextCharFormat &format) return out; } +std::ostream &operator<<(std::ostream &out, const QImage &image) +{ + return out << "(" << image.width() << ", " << image.height() << ", " << image.format() << ")"; +} + void PrintTo(const QString &text, std::ostream *os) { *os << text; diff --git a/tests/unit/unittest/gtest-qt-printing.h b/tests/unit/unittest/gtest-qt-printing.h index ebaeb2c785..54db4ee105 100644 --- a/tests/unit/unittest/gtest-qt-printing.h +++ b/tests/unit/unittest/gtest-qt-printing.h @@ -34,11 +34,13 @@ QT_BEGIN_NAMESPACE class QVariant; class QString; class QTextCharFormat; +class QImage; std::ostream &operator<<(std::ostream &out, const QVariant &QVariant); std::ostream &operator<<(std::ostream &out, const QString &text); std::ostream &operator<<(std::ostream &out, const QByteArray &byteArray); std::ostream &operator<<(std::ostream &out, const QTextCharFormat &format); +std::ostream &operator<<(std::ostream &out, const QImage &image); void PrintTo(const QString &text, std::ostream *os); void PrintTo(const QVariant &variant, std::ostream *os); diff --git a/tests/unit/unittest/imagecache-test.cpp b/tests/unit/unittest/imagecache-test.cpp new file mode 100644 index 0000000000..4219335774 --- /dev/null +++ b/tests/unit/unittest/imagecache-test.cpp @@ -0,0 +1,326 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "mockimagecachegenerator.h" +#include "mockimagecachestorage.h" +#include "mocktimestampprovider.h" +#include "notification.h" + +#include <imagecache.h> + +namespace { + +class ImageCache : public testing::Test +{ +protected: + Notification notification; + Notification waitInThread; + NiceMock<MockImageCacheStorage> mockStorage; + NiceMock<MockImageCacheGenerator> mockGenerator; + NiceMock<MockTimeStampProvider> mockTimeStampProvider; + QmlDesigner::ImageCache cache{mockStorage, mockGenerator, mockTimeStampProvider}; + NiceMock<MockFunction<void()>> mockAbortCallback; + NiceMock<MockFunction<void(const QImage &image)>> mockCaptureCallback; + QImage image1{10, 10, QImage::Format_ARGB32}; +}; + +TEST_F(ImageCache, RequestImageFetchesImageFromStorage) +{ + EXPECT_CALL(mockStorage, fetchImage(Eq("/path/to/Component.qml"), _)) + .WillRepeatedly([&](Utils::SmallStringView, auto) { + notification.notify(); + return QmlDesigner::ImageCacheStorageInterface::Entry{{}, false}; + }); + + cache.requestImage("/path/to/Component.qml", + mockCaptureCallback.AsStdFunction(), + mockAbortCallback.AsStdFunction()); + notification.wait(); +} + +TEST_F(ImageCache, RequestImageFetchesImageFromStorageWithTimeStamp) +{ + EXPECT_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml"))) + .WillRepeatedly(Return(Sqlite::TimeStamp{123})); + EXPECT_CALL(mockStorage, fetchImage(Eq("/path/to/Component.qml"), Eq(Sqlite::TimeStamp{123}))) + .WillRepeatedly([&](Utils::SmallStringView, auto) { + notification.notify(); + return QmlDesigner::ImageCacheStorageInterface::Entry{QImage{}, false}; + }); + + cache.requestImage("/path/to/Component.qml", + mockCaptureCallback.AsStdFunction(), + mockAbortCallback.AsStdFunction()); + notification.wait(); +} + +TEST_F(ImageCache, RequestImageCallsCaptureCallbackWithImageFromStorage) +{ + ON_CALL(mockStorage, fetchImage(Eq("/path/to/Component.qml"), _)) + .WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::Entry{image1, true})); + + EXPECT_CALL(mockCaptureCallback, Call(Eq(image1))).WillRepeatedly([&](const QImage &) { + notification.notify(); + }); + + cache.requestImage("/path/to/Component.qml", + mockCaptureCallback.AsStdFunction(), + mockAbortCallback.AsStdFunction()); + notification.wait(); +} + +TEST_F(ImageCache, RequestImageCallsAbortCallbackWithoutImage) +{ + ON_CALL(mockStorage, fetchImage(Eq("/path/to/Component.qml"), _)) + .WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::Entry{QImage{}, true})); + + EXPECT_CALL(mockAbortCallback, Call()).WillRepeatedly([&] { notification.notify(); }); + + cache.requestImage("/path/to/Component.qml", + mockCaptureCallback.AsStdFunction(), + mockAbortCallback.AsStdFunction()); + notification.wait(); +} + +TEST_F(ImageCache, RequestImageRequestImageFromGenerator) +{ + ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml"))) + .WillByDefault(Return(Sqlite::TimeStamp{123})); + + EXPECT_CALL(mockGenerator, + generateImage(Eq("/path/to/Component.qml"), Eq(Sqlite::TimeStamp{123}), _, _)) + .WillRepeatedly([&](auto &&, auto, auto &&callback, auto) { notification.notify(); }); + + cache.requestImage("/path/to/Component.qml", + mockCaptureCallback.AsStdFunction(), + mockAbortCallback.AsStdFunction()); + notification.wait(); +} + +TEST_F(ImageCache, RequestImageCallsCaptureCallbackWithImageFromGenerator) +{ + ON_CALL(mockGenerator, generateImage(Eq("/path/to/Component.qml"), _, _, _)) + .WillByDefault([&](auto &&, auto, auto &&callback, auto) { + callback(QImage{image1}); + notification.notify(); + }); + + EXPECT_CALL(mockCaptureCallback, Call(Eq(image1))); + + cache.requestImage("/path/to/Component.qml", + mockCaptureCallback.AsStdFunction(), + mockAbortCallback.AsStdFunction()); + notification.wait(); +} + +TEST_F(ImageCache, RequestImageCallsAbortCallbackFromGenerator) +{ + ON_CALL(mockGenerator, generateImage(Eq("/path/to/Component.qml"), _, _, _)) + .WillByDefault([&](auto &&, auto, auto &&, auto &&abortCallback) { + abortCallback(); + notification.notify(); + }); + + EXPECT_CALL(mockAbortCallback, Call()); + + cache.requestImage("/path/to/Component.qml", + mockCaptureCallback.AsStdFunction(), + mockAbortCallback.AsStdFunction()); + notification.wait(); +} + +TEST_F(ImageCache, RequestIconFetchesIconFromStorage) +{ + EXPECT_CALL(mockStorage, fetchIcon(Eq("/path/to/Component.qml"), _)) + .WillRepeatedly([&](Utils::SmallStringView, auto) { + notification.notify(); + return QmlDesigner::ImageCacheStorageInterface::Entry{{}, false}; + }); + + cache.requestIcon("/path/to/Component.qml", + mockCaptureCallback.AsStdFunction(), + mockAbortCallback.AsStdFunction()); + notification.wait(); +} + +TEST_F(ImageCache, RequestIconFetchesIconFromStorageWithTimeStamp) +{ + EXPECT_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml"))) + .WillRepeatedly(Return(Sqlite::TimeStamp{123})); + EXPECT_CALL(mockStorage, fetchIcon(Eq("/path/to/Component.qml"), Eq(Sqlite::TimeStamp{123}))) + .WillRepeatedly([&](Utils::SmallStringView, auto) { + notification.notify(); + return QmlDesigner::ImageCacheStorageInterface::Entry{QImage{}, false}; + }); + + cache.requestIcon("/path/to/Component.qml", + mockCaptureCallback.AsStdFunction(), + mockAbortCallback.AsStdFunction()); + notification.wait(); +} + +TEST_F(ImageCache, RequestIconCallsCaptureCallbackWithImageFromStorage) +{ + ON_CALL(mockStorage, fetchIcon(Eq("/path/to/Component.qml"), _)) + .WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::Entry{image1, true})); + + EXPECT_CALL(mockCaptureCallback, Call(Eq(image1))).WillRepeatedly([&](const QImage &) { + notification.notify(); + }); + + cache.requestIcon("/path/to/Component.qml", + mockCaptureCallback.AsStdFunction(), + mockAbortCallback.AsStdFunction()); + notification.wait(); +} + +TEST_F(ImageCache, RequestIconCallsAbortCallbackWithoutIcon) +{ + ON_CALL(mockStorage, fetchIcon(Eq("/path/to/Component.qml"), _)) + .WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::Entry{QImage{}, true})); + + EXPECT_CALL(mockAbortCallback, Call()).WillRepeatedly([&] { notification.notify(); }); + + cache.requestIcon("/path/to/Component.qml", + mockCaptureCallback.AsStdFunction(), + mockAbortCallback.AsStdFunction()); + notification.wait(); +} + +TEST_F(ImageCache, RequestIconRequestImageFromGenerator) +{ + ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml"))) + .WillByDefault(Return(Sqlite::TimeStamp{123})); + + EXPECT_CALL(mockGenerator, + generateImage(Eq("/path/to/Component.qml"), Eq(Sqlite::TimeStamp{123}), _, _)) + .WillRepeatedly([&](auto &&, auto, auto &&callback, auto) { notification.notify(); }); + + cache.requestIcon("/path/to/Component.qml", + mockCaptureCallback.AsStdFunction(), + mockAbortCallback.AsStdFunction()); + notification.wait(); +} + +TEST_F(ImageCache, RequestIconCallsCaptureCallbackWithImageFromGenerator) +{ + ON_CALL(mockGenerator, generateImage(Eq("/path/to/Component.qml"), _, _, _)) + .WillByDefault([&](auto &&, auto, auto &&callback, auto) { + callback(QImage{image1}); + notification.notify(); + }); + + EXPECT_CALL(mockCaptureCallback, Call(Eq(image1))); + + cache.requestIcon("/path/to/Component.qml", + mockCaptureCallback.AsStdFunction(), + mockAbortCallback.AsStdFunction()); + notification.wait(); +} + +TEST_F(ImageCache, RequestIconCallsAbortCallbackFromGenerator) +{ + ON_CALL(mockGenerator, generateImage(Eq("/path/to/Component.qml"), _, _, _)) + .WillByDefault([&](auto &&, auto, auto &&, auto &&abortCallback) { + abortCallback(); + notification.notify(); + }); + + EXPECT_CALL(mockAbortCallback, Call()); + + cache.requestIcon("/path/to/Component.qml", + mockCaptureCallback.AsStdFunction(), + mockAbortCallback.AsStdFunction()); + notification.wait(); +} + +TEST_F(ImageCache, CleanRemovesEntries) +{ + EXPECT_CALL(mockGenerator, generateImage(Eq("/path/to/Component1.qml"), _, _, _)) + .WillRepeatedly([&](auto &&, auto, auto &&mockCaptureCallback, auto &&) { + mockCaptureCallback(QImage{}); + waitInThread.wait(); + }); + EXPECT_CALL(mockGenerator, generateImage(_, _, _, _)) + .WillRepeatedly([&](auto &&, auto, auto &&mockCaptureCallback, auto &&) { + mockCaptureCallback(QImage{}); + }); + cache.requestIcon("/path/to/Component1.qml", + mockCaptureCallback.AsStdFunction(), + mockAbortCallback.AsStdFunction()); + + EXPECT_CALL(mockCaptureCallback, Call(_)).Times(AtMost(1)); + + cache.requestIcon("/path/to/Component3.qml", + mockCaptureCallback.AsStdFunction(), + mockAbortCallback.AsStdFunction()); + cache.clean(); + waitInThread.notify(); +} + +TEST_F(ImageCache, CleanCallsAbort) +{ + ON_CALL(mockGenerator, generateImage(Eq("/path/to/Component1.qml"), _, _, _)) + .WillByDefault( + [&](auto &&, auto, auto &&mockCaptureCallback, auto &&) { waitInThread.wait(); }); + cache.requestIcon("/path/to/Component1.qml", + mockCaptureCallback.AsStdFunction(), + mockAbortCallback.AsStdFunction()); + cache.requestIcon("/path/to/Component2.qml", + mockCaptureCallback.AsStdFunction(), + mockAbortCallback.AsStdFunction()); + + EXPECT_CALL(mockAbortCallback, Call()).Times(AtLeast(2)); + + cache.requestIcon("/path/to/Component3.qml", + mockCaptureCallback.AsStdFunction(), + mockAbortCallback.AsStdFunction()); + cache.clean(); + waitInThread.notify(); +} + +TEST_F(ImageCache, CleanCallsGeneratorClean) +{ + EXPECT_CALL(mockGenerator, clean()).Times(AtLeast(1)); + + cache.clean(); +} + +TEST_F(ImageCache, AfterCleanNewJobsWorks) +{ + cache.clean(); + + EXPECT_CALL(mockGenerator, generateImage(Eq("/path/to/Component.qml"), _, _, _)) + .WillRepeatedly([&](auto &&, auto, auto &&, auto &&) { notification.notify(); }); + + cache.requestIcon("/path/to/Component.qml", + mockCaptureCallback.AsStdFunction(), + mockAbortCallback.AsStdFunction()); + notification.wait(); +} + +} // namespace diff --git a/tests/unit/unittest/imagecachecollectormock.h b/tests/unit/unittest/imagecachecollectormock.h new file mode 100644 index 0000000000..93520c418d --- /dev/null +++ b/tests/unit/unittest/imagecachecollectormock.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#pragma once + +#include "googletest.h" + +#include <imagecachecollectorinterface.h> + +class ImageCacheCollectorMock : public QmlDesigner::ImageCacheCollectorInterface +{ +public: + MOCK_METHOD(void, + start, + (Utils::SmallStringView filePath, + ImageCacheCollectorInterface::CaptureCallback captureCallback, + ImageCacheCollectorInterface::AbortCallback abortCallback), + (override)); +}; diff --git a/tests/unit/unittest/imagecachegenerator-test.cpp b/tests/unit/unittest/imagecachegenerator-test.cpp new file mode 100644 index 0000000000..f152bd83ad --- /dev/null +++ b/tests/unit/unittest/imagecachegenerator-test.cpp @@ -0,0 +1,240 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "imagecachecollectormock.h" +#include "mockimagecachestorage.h" +#include "notification.h" + +#include <imagecachegenerator.h> + +#include <mutex> + +namespace { + +class ImageCacheGenerator : public testing::Test +{ +protected: + template<typename Callable, typename... Arguments> + static void executeAsync(Callable &&call, Arguments... arguments) + { + std::thread thread( + [](Callable &&call, Arguments... arguments) { + call(std::forward<Arguments>(arguments)...); + }, + std::forward<Callable>(call), + std::forward<Arguments>(arguments)...); + thread.detach(); + } + +protected: + Notification waitInThread; + Notification notification; + QImage image1{10, 10, QImage::Format_ARGB32}; + NiceMock<MockFunction<void(const QImage &)>> imageCallbackMock; + NiceMock<MockFunction<void()>> abortCallbackMock; + NiceMock<ImageCacheCollectorMock> collectorMock; + NiceMock<MockImageCacheStorage> storageMock; + QmlDesigner::ImageCacheGenerator generator{collectorMock, storageMock}; +}; + +TEST_F(ImageCacheGenerator, CallsCollectorWithCaptureCallback) +{ + EXPECT_CALL(collectorMock, start(Eq("name"), _, _)) + .WillRepeatedly([&](auto, auto captureCallback, auto) { captureCallback(QImage{image1}); }); + EXPECT_CALL(imageCallbackMock, Call(_)).WillRepeatedly([&](const QImage &) { + notification.notify(); + }); + + generator.generateImage("name", {}, imageCallbackMock.AsStdFunction(), {}); + notification.wait(); +} + +TEST_F(ImageCacheGenerator, CallsCollectorOnlyIfNotProcessing) +{ + EXPECT_CALL(collectorMock, start(Eq("name"), _, _)).WillRepeatedly([&](auto, auto, auto) { + notification.notify(); + }); + + generator.generateImage("name", {}, imageCallbackMock.AsStdFunction(), {}); + generator.generateImage("name", {}, imageCallbackMock.AsStdFunction(), {}); + notification.wait(2); +} + +TEST_F(ImageCacheGenerator, ProcessTaskAfterFirstFinished) +{ + ON_CALL(imageCallbackMock, Call(_)).WillByDefault([&](const QImage &) { notification.notify(); }); + + EXPECT_CALL(collectorMock, start(Eq("name"), _, _)).WillOnce([&](auto, auto captureCallback, auto) { + captureCallback(QImage{image1}); + }); + EXPECT_CALL(collectorMock, start(Eq("name2"), _, _)).WillOnce([&](auto, auto captureCallback, auto) { + captureCallback(QImage{image1}); + }); + + generator.generateImage("name", {}, imageCallbackMock.AsStdFunction(), {}); + generator.generateImage("name2", {}, imageCallbackMock.AsStdFunction(), {}); + notification.wait(2); +} + +TEST_F(ImageCacheGenerator, DontCrashAtDestructingGenerator) +{ + ON_CALL(collectorMock, start(Eq("name"), _, _)).WillByDefault([&](auto, auto captureCallback, auto) { + captureCallback(QImage{image1}); + }); + + generator.generateImage("name", {}, imageCallbackMock.AsStdFunction(), {}); + generator.generateImage("name2", {}, imageCallbackMock.AsStdFunction(), {}); + generator.generateImage("name3", {}, imageCallbackMock.AsStdFunction(), {}); + generator.generateImage("name4", {}, imageCallbackMock.AsStdFunction(), {}); +} + +TEST_F(ImageCacheGenerator, StoreImage) +{ + ON_CALL(collectorMock, start(Eq("name"), _, _)).WillByDefault([&](auto, auto captureCallback, auto) { + captureCallback(QImage{image1}); + }); + + EXPECT_CALL(storageMock, storeImage(Eq("name"), Eq(Sqlite::TimeStamp{11}), Eq(image1))) + .WillRepeatedly([&](auto, auto, auto) { notification.notify(); }); + + generator.generateImage("name", {11}, imageCallbackMock.AsStdFunction(), {}); + notification.wait(); +} + +TEST_F(ImageCacheGenerator, StoreNullImage) +{ + ON_CALL(collectorMock, start(Eq("name"), _, _)).WillByDefault([&](auto, auto captureCallback, auto) { + captureCallback(QImage{}); + }); + + EXPECT_CALL(storageMock, storeImage(Eq("name"), Eq(Sqlite::TimeStamp{11}), Eq(QImage{}))) + .WillRepeatedly([&](auto, auto, auto) { notification.notify(); }); + + generator.generateImage("name", + {11}, + imageCallbackMock.AsStdFunction(), + abortCallbackMock.AsStdFunction()); + notification.wait(); +} + +TEST_F(ImageCacheGenerator, AbortCallback) +{ + ON_CALL(collectorMock, start(Eq("name"), _, _)).WillByDefault([&](auto, auto captureCallback, auto) { + captureCallback(QImage{image1}); + }); + ON_CALL(collectorMock, start(Eq("name2"), _, _)).WillByDefault([&](auto, auto, auto abortCallback) { + abortCallback(); + }); + + EXPECT_CALL(imageCallbackMock, Call(_)).WillOnce([&](const QImage &) { notification.notify(); }); + EXPECT_CALL(abortCallbackMock, Call()).WillOnce([&]() { notification.notify(); }); + + generator.generateImage("name", + {}, + imageCallbackMock.AsStdFunction(), + abortCallbackMock.AsStdFunction()); + generator.generateImage("name2", + {}, + imageCallbackMock.AsStdFunction(), + abortCallbackMock.AsStdFunction()); + notification.wait(2); +} + +TEST_F(ImageCacheGenerator, StoreNullImageForAbortCallback) +{ + ON_CALL(collectorMock, start(_, _, _)).WillByDefault([&](auto, auto, auto abortCallback) { + abortCallback(); + notification.notify(); + }); + + EXPECT_CALL(abortCallbackMock, Call()).WillOnce([&]() { notification.notify(); }); + EXPECT_CALL(storageMock, storeImage(Eq("name"), Eq(Sqlite::TimeStamp{11}), Eq(QImage{}))); + + generator.generateImage("name", + {11}, + imageCallbackMock.AsStdFunction(), + abortCallbackMock.AsStdFunction()); + notification.wait(); +} + +TEST_F(ImageCacheGenerator, AbortForEmptyImage) +{ + NiceMock<MockFunction<void()>> abortCallbackMock; + ON_CALL(collectorMock, start(Eq("name"), _, _)).WillByDefault([&](auto, auto captureCallback, auto) { + captureCallback(QImage{}); + }); + + EXPECT_CALL(abortCallbackMock, Call()).WillOnce([&]() { notification.notify(); }); + + generator.generateImage("name", + {}, + imageCallbackMock.AsStdFunction(), + abortCallbackMock.AsStdFunction()); + notification.wait(); +} + +TEST_F(ImageCacheGenerator, CallWalCheckpointFullIfQueueIsEmpty) +{ + ON_CALL(collectorMock, start(Eq("name"), _, _)).WillByDefault([&](auto, auto captureCallback, auto) { + captureCallback({}); + }); + + EXPECT_CALL(storageMock, walCheckpointFull()).WillRepeatedly([&]() { notification.notify(); }); + + generator.generateImage("name", + {11}, + imageCallbackMock.AsStdFunction(), + abortCallbackMock.AsStdFunction()); + generator.generateImage("name2", + {11}, + imageCallbackMock.AsStdFunction(), + abortCallbackMock.AsStdFunction()); + notification.wait(); +} + +TEST_F(ImageCacheGenerator, Clean) +{ + ON_CALL(collectorMock, start(_, _, _)).WillByDefault([&](auto, auto captureCallback, auto) { + captureCallback({}); + waitInThread.wait(); + }); + generator.generateImage("name", + {11}, + imageCallbackMock.AsStdFunction(), + abortCallbackMock.AsStdFunction()); + generator.generateImage("name2", + {11}, + imageCallbackMock.AsStdFunction(), + abortCallbackMock.AsStdFunction()); + + EXPECT_CALL(imageCallbackMock, Call(_)).Times(0); + + generator.clean(); + waitInThread.notify(); +} + +} // namespace diff --git a/tests/unit/unittest/imagecachestorage-test.cpp b/tests/unit/unittest/imagecachestorage-test.cpp new file mode 100644 index 0000000000..aaf30526b6 --- /dev/null +++ b/tests/unit/unittest/imagecachestorage-test.cpp @@ -0,0 +1,334 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "sqlitedatabasemock.h" + +#include <imagecachestorage.h> +#include <sqlitedatabase.h> + +namespace { + +MATCHER_P2(IsEntry, + image, + hasEntry, + std::string(negation ? "is't" : "is") + + PrintToString(QmlDesigner::ImageCacheStorageInterface::Entry{image, hasEntry})) +{ + const QmlDesigner::ImageCacheStorageInterface::Entry &entry = arg; + return entry.image == image && entry.hasEntry == hasEntry; +} + +class ImageCacheStorageTest : public testing::Test +{ +protected: + QImage createImage() + { + QImage image{150, 150, QImage::Format_ARGB32}; + image.fill(QColor{128, 64, 0, 11}); + image.setPixelColor(75, 75, QColor{1, 255, 33, 196}); + + return image; + } + +protected: + using ReadStatement = QmlDesigner::ImageCacheStorage<SqliteDatabaseMock>::ReadStatement; + using WriteStatement = QmlDesigner::ImageCacheStorage<SqliteDatabaseMock>::WriteStatement; + + NiceMock<SqliteDatabaseMock> databaseMock; + QmlDesigner::ImageCacheStorage<SqliteDatabaseMock> storage{databaseMock}; + ReadStatement &selectImageStatement = storage.selectImageStatement; + ReadStatement &selectIconStatement = storage.selectIconStatement; + WriteStatement &upsertImageStatement = storage.upsertImageStatement; + QImage image1{createImage()}; +}; + +TEST_F(ImageCacheStorageTest, Initialize) +{ + InSequence s; + + EXPECT_CALL(databaseMock, exclusiveBegin()); + EXPECT_CALL(databaseMock, + execute(Eq("CREATE TABLE IF NOT EXISTS images(id INTEGER PRIMARY KEY, name TEXT " + "NOT NULL UNIQUE, mtime INTEGER, image BLOB, icon BLOB)"))); + EXPECT_CALL(databaseMock, commit()); + EXPECT_CALL(databaseMock, immediateBegin()); + EXPECT_CALL(databaseMock, prepare(Eq(selectImageStatement.sqlStatement))); + EXPECT_CALL(databaseMock, prepare(Eq(selectIconStatement.sqlStatement))); + EXPECT_CALL(databaseMock, prepare(Eq(upsertImageStatement.sqlStatement))); + EXPECT_CALL(databaseMock, commit()); + + QmlDesigner::ImageCacheStorage<SqliteDatabaseMock> storage{databaseMock}; +} + +TEST_F(ImageCacheStorageTest, FetchImageCalls) +{ + InSequence s; + + EXPECT_CALL(databaseMock, deferredBegin()); + EXPECT_CALL(selectImageStatement, + valueReturnBlob(TypedEq<Utils::SmallStringView>("/path/to/component"), + TypedEq<long long>(123))); + EXPECT_CALL(databaseMock, commit()); + + storage.fetchImage("/path/to/component", {123}); +} + +TEST_F(ImageCacheStorageTest, FetchImageCallsIsBusy) +{ + InSequence s; + + EXPECT_CALL(databaseMock, deferredBegin()); + EXPECT_CALL(selectImageStatement, + valueReturnBlob(TypedEq<Utils::SmallStringView>("/path/to/component"), + TypedEq<long long>(123))) + .WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); + EXPECT_CALL(databaseMock, rollback()); + EXPECT_CALL(databaseMock, deferredBegin()); + EXPECT_CALL(selectImageStatement, + valueReturnBlob(TypedEq<Utils::SmallStringView>("/path/to/component"), + TypedEq<long long>(123))); + EXPECT_CALL(databaseMock, commit()); + + storage.fetchImage("/path/to/component", {123}); +} + +TEST_F(ImageCacheStorageTest, FetchIconCalls) +{ + InSequence s; + + EXPECT_CALL(databaseMock, deferredBegin()); + EXPECT_CALL(selectIconStatement, + valueReturnBlob(TypedEq<Utils::SmallStringView>("/path/to/component"), + TypedEq<long long>(123))); + EXPECT_CALL(databaseMock, commit()); + + storage.fetchIcon("/path/to/component", {123}); +} + +TEST_F(ImageCacheStorageTest, FetchIconCallsIsBusy) +{ + InSequence s; + + EXPECT_CALL(databaseMock, deferredBegin()); + EXPECT_CALL(selectIconStatement, + valueReturnBlob(TypedEq<Utils::SmallStringView>("/path/to/component"), + TypedEq<long long>(123))) + .WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); + EXPECT_CALL(databaseMock, rollback()); + EXPECT_CALL(databaseMock, deferredBegin()); + EXPECT_CALL(selectIconStatement, + valueReturnBlob(TypedEq<Utils::SmallStringView>("/path/to/component"), + TypedEq<long long>(123))); + EXPECT_CALL(databaseMock, commit()); + + storage.fetchIcon("/path/to/component", {123}); +} + +TEST_F(ImageCacheStorageTest, StoreImageCalls) +{ + InSequence s; + + EXPECT_CALL(databaseMock, immediateBegin()); + EXPECT_CALL(upsertImageStatement, + write(TypedEq<Utils::SmallStringView>("/path/to/component"), + TypedEq<long long>(123), + A<Sqlite::BlobView>(), + A<Sqlite::BlobView>())); + EXPECT_CALL(databaseMock, commit()); + + storage.storeImage("/path/to/component", {123}, image1); +} + +TEST_F(ImageCacheStorageTest, StoreEmptyImageCalls) +{ + InSequence s; + + EXPECT_CALL(databaseMock, immediateBegin()); + EXPECT_CALL(upsertImageStatement, + write(TypedEq<Utils::SmallStringView>("/path/to/component"), + TypedEq<long long>(123), + A<Sqlite::NullValue>(), + A<Sqlite::NullValue>())); + EXPECT_CALL(databaseMock, commit()); + + storage.storeImage("/path/to/component", {123}, QImage{}); +} + +TEST_F(ImageCacheStorageTest, StoreImageCallsIsBusy) +{ + InSequence s; + + EXPECT_CALL(databaseMock, immediateBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); + EXPECT_CALL(databaseMock, immediateBegin()); + EXPECT_CALL(upsertImageStatement, + write(TypedEq<Utils::SmallStringView>("/path/to/component"), + TypedEq<long long>(123), + A<Sqlite::NullValue>(), + A<Sqlite::NullValue>())); + EXPECT_CALL(databaseMock, commit()); + + storage.storeImage("/path/to/component", {123}, QImage{}); +} + +TEST_F(ImageCacheStorageTest, CallWalCheckointFull) +{ + EXPECT_CALL(databaseMock, walCheckpointFull()); + + storage.walCheckpointFull(); +} + +TEST_F(ImageCacheStorageTest, CallWalCheckointFullIsBusy) +{ + InSequence s; + + EXPECT_CALL(databaseMock, walCheckpointFull()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); + EXPECT_CALL(databaseMock, walCheckpointFull()); + + storage.walCheckpointFull(); +} + +class ImageCacheStorageSlowTest : public testing::Test +{ +protected: + QImage createImage() + { + QImage image{150, 150, QImage::Format_ARGB32}; + image.fill(QColor{128, 64, 0, 11}); + image.setPixelColor(1, 1, QColor{1, 255, 33, 196}); + + return image; + } + +protected: + Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; + QmlDesigner::ImageCacheStorage<Sqlite::Database> storage{database}; + QImage image1{createImage()}; + QImage image2{10, 10, QImage::Format_ARGB32}; + QImage icon1{image1.scaled(96, 96)}; +}; + +TEST_F(ImageCacheStorageSlowTest, StoreImage) +{ + storage.storeImage("/path/to/component", {123}, image1); + + ASSERT_THAT(storage.fetchImage("/path/to/component", {123}), IsEntry(image1, true)); +} + +TEST_F(ImageCacheStorageSlowTest, StoreEmptyImageAfterEntry) +{ + storage.storeImage("/path/to/component", {123}, image1); + + storage.storeImage("/path/to/component", {123}, QImage{}); + + ASSERT_THAT(storage.fetchImage("/path/to/component", {123}), IsEntry(QImage{}, true)); +} + +TEST_F(ImageCacheStorageSlowTest, StoreEmptyEntry) +{ + storage.storeImage("/path/to/component", {123}, QImage{}); + + ASSERT_THAT(storage.fetchImage("/path/to/component", {123}), IsEntry(QImage{}, true)); +} + +TEST_F(ImageCacheStorageSlowTest, FetchNonExistingImageIsEmpty) +{ + auto image = storage.fetchImage("/path/to/component", {123}); + + ASSERT_THAT(image, IsEntry(QImage{}, false)); +} + +TEST_F(ImageCacheStorageSlowTest, FetchSameTimeImage) +{ + storage.storeImage("/path/to/component", {123}, image1); + + auto image = storage.fetchImage("/path/to/component", {123}); + + ASSERT_THAT(image, IsEntry(image1, true)); +} + +TEST_F(ImageCacheStorageSlowTest, DoNotFetchOlderImage) +{ + storage.storeImage("/path/to/component", {123}, image1); + + auto image = storage.fetchImage("/path/to/component", {124}); + + ASSERT_THAT(image, IsEntry(QImage{}, false)); +} + +TEST_F(ImageCacheStorageSlowTest, FetchNewerImage) +{ + storage.storeImage("/path/to/component", {123}, image1); + + auto image = storage.fetchImage("/path/to/component", {122}); + + ASSERT_THAT(image, IsEntry(image1, true)); +} + +TEST_F(ImageCacheStorageSlowTest, FetchNonExistingIconIsEmpty) +{ + auto image = storage.fetchIcon("/path/to/component", {123}); + + ASSERT_THAT(image, IsEntry(QImage{}, false)); +} + +TEST_F(ImageCacheStorageSlowTest, FetchSameTimeIcon) +{ + storage.storeImage("/path/to/component", {123}, image1); + + auto image = storage.fetchIcon("/path/to/component", {123}); + + ASSERT_THAT(image, IsEntry(icon1, true)); +} + +TEST_F(ImageCacheStorageSlowTest, DoNotFetchOlderIcon) +{ + storage.storeImage("/path/to/component", {123}, image1); + + auto image = storage.fetchIcon("/path/to/component", {124}); + + ASSERT_THAT(image, IsEntry(QImage{}, false)); +} + +TEST_F(ImageCacheStorageSlowTest, FetchNewerIcon) +{ + storage.storeImage("/path/to/component", {123}, image1); + + auto image = storage.fetchIcon("/path/to/component", {122}); + + ASSERT_THAT(image, IsEntry(icon1, true)); +} + +TEST_F(ImageCacheStorageSlowTest, DontScaleSmallerIcon) +{ + storage.storeImage("/path/to/component", {123}, image2); + + auto image = storage.fetchImage("/path/to/component", {122}); + + ASSERT_THAT(image, IsEntry(image2, true)); +} + +} // namespace diff --git a/tests/unit/unittest/mockimagecachegenerator.h b/tests/unit/unittest/mockimagecachegenerator.h new file mode 100644 index 0000000000..ffe8d9c709 --- /dev/null +++ b/tests/unit/unittest/mockimagecachegenerator.h @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#pragma once + +#include "googletest.h" + +#include <imagecachegeneratorinterface.h> + +class MockImageCacheGenerator : public QmlDesigner::ImageCacheGeneratorInterface +{ +public: + MOCK_METHOD(void, + generateImage, + (Utils::SmallStringView name, + Sqlite::TimeStamp timeStamp, + CaptureCallback &&captureCallback, + AbortCallback &&abortCallback), + (override)); + MOCK_METHOD(void, clean, (), (override)); +}; diff --git a/tests/unit/unittest/mockimagecachestorage.h b/tests/unit/unittest/mockimagecachestorage.h new file mode 100644 index 0000000000..add2cfaa96 --- /dev/null +++ b/tests/unit/unittest/mockimagecachestorage.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#pragma once + +#include "googletest.h" + +#include <imagecachestorageinterface.h> + +class MockImageCacheStorage : public QmlDesigner::ImageCacheStorageInterface +{ +public: + MOCK_METHOD(QmlDesigner::ImageCacheStorageInterface::Entry, + fetchImage, + (Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp), + (const, override)); + + MOCK_METHOD(QmlDesigner::ImageCacheStorageInterface::Entry, + fetchIcon, + (Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp), + (const, override)); + + MOCK_METHOD(void, + storeImage, + (Utils::SmallStringView name, Sqlite::TimeStamp newTimeStamp, const QImage &image), + (override)); + MOCK_METHOD(void, walCheckpointFull, (), (override)); +}; diff --git a/tests/unit/unittest/mocktimestampprovider.h b/tests/unit/unittest/mocktimestampprovider.h new file mode 100644 index 0000000000..0adad4c030 --- /dev/null +++ b/tests/unit/unittest/mocktimestampprovider.h @@ -0,0 +1,36 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#pragma once + +#include "googletest.h" + +#include <timestampproviderinterface.h> + +class MockTimeStampProvider : public QmlDesigner::TimeStampProviderInterface +{ +public: + MOCK_METHOD(Sqlite::TimeStamp, timeStamp, (Utils::SmallStringView name), (const, override)); +}; diff --git a/tests/unit/unittest/notification.h b/tests/unit/unittest/notification.h new file mode 100644 index 0000000000..a27d9acb76 --- /dev/null +++ b/tests/unit/unittest/notification.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 <condition_variable> +#include <mutex> + +class Notification +{ +public: + void wait(int count = 1) + { + std::unique_lock<std::mutex> lock{m_mutex}; + m_waitCount += count; + if (m_waitCount > 0) + m_condition.wait(lock, [&] { return m_waitCount <= 0; }); + } + + void notify() + { + { + std::unique_lock<std::mutex> lock{m_mutex}; + --m_waitCount; + } + + m_condition.notify_all(); + } + +private: + std::mutex m_mutex; + std::condition_variable m_condition; + int m_waitCount = 0; +}; diff --git a/tests/unit/unittest/sqlitedatabasemock.h b/tests/unit/unittest/sqlitedatabasemock.h new file mode 100644 index 0000000000..8c1179e424 --- /dev/null +++ b/tests/unit/unittest/sqlitedatabasemock.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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. +** +****************************************************************************/ + +#pragma once + +#include "googletest.h" + +#include "sqlitereadstatementmock.h" +#include "sqlitetransactionbackendmock.h" +#include "sqlitewritestatementmock.h" + +#include <sqlitedatabaseinterface.h> +#include <sqlitetable.h> +#include <sqlitetransaction.h> + +#include <utils/smallstringview.h> + +class SqliteDatabaseMock : public SqliteTransactionBackendMock, public Sqlite::DatabaseInterface +{ +public: + using ReadStatement = NiceMock<SqliteReadStatementMock>; + using WriteStatement = NiceMock<SqliteWriteStatementMock>; + + MOCK_METHOD(void, prepare, (Utils::SmallStringView sqlStatement), ()); + + MOCK_METHOD(void, execute, (Utils::SmallStringView sqlStatement), ()); + + MOCK_METHOD(int64_t, lastInsertedRowId, (), (const)); + + MOCK_METHOD(void, setLastInsertedRowId, (int64_t), (const)); + + MOCK_METHOD(bool, isInitialized, (), (const)); + + MOCK_METHOD(void, setIsInitialized, (bool), ()); + + MOCK_METHOD(void, walCheckpointFull, (), (override)); + + MOCK_METHOD(void, + setUpdateHook, + (void *object, + void (*)(void *object, int, char const *database, char const *, long long rowId)), + (override)); + + MOCK_METHOD(void, resetUpdateHook, (), (override)); + + MOCK_METHOD(void, applyAndUpdateSessions, (), (override)); + + MOCK_METHOD(void, setAttachedTables, (const Utils::SmallStringVector &tables), (override)); +}; + diff --git a/tests/unit/unittest/sqlitereadstatementmock.cpp b/tests/unit/unittest/sqlitereadstatementmock.cpp new file mode 100644 index 0000000000..e3e22d4e16 --- /dev/null +++ b/tests/unit/unittest/sqlitereadstatementmock.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** 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 "sqlitereadstatementmock.h" + +#include "sqlitedatabasemock.h" + +SqliteReadStatementMock::SqliteReadStatementMock(Utils::SmallStringView sqlStatement, + SqliteDatabaseMock &databaseMock) + : sqlStatement(sqlStatement) +{ + databaseMock.prepare(sqlStatement); +} + +template<> +std::vector<Utils::SmallString> SqliteReadStatementMock::values<Utils::SmallString>(std::size_t reserveSize) +{ + return valuesReturnStringVector(reserveSize); +} + +template<> +std::vector<long long> SqliteReadStatementMock::values<long long>(std::size_t reserveSize) +{ + return valuesReturnRowIds(reserveSize); +} + +template<> +Utils::optional<long long> SqliteReadStatementMock::value<long long>() +{ + return valueReturnLongLong(); +} + +template<> +Utils::optional<Sqlite::ByteArrayBlob> SqliteReadStatementMock::value<Sqlite::ByteArrayBlob>( + const Utils::SmallStringView &name, const long long &blob) +{ + return valueReturnBlob(name, blob); +} diff --git a/tests/unit/unittest/sqlitereadstatementmock.h b/tests/unit/unittest/sqlitereadstatementmock.h new file mode 100644 index 0000000000..f74cce1e8e --- /dev/null +++ b/tests/unit/unittest/sqlitereadstatementmock.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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. +** +****************************************************************************/ + +#pragma once + +#include "googletest.h" + +#include <sqliteblob.h> +#include <utils/optional.h> +#include <utils/smallstring.h> + +#include <QImage> + +#include <cstdint> +#include <tuple> +#include <vector> + +class SqliteDatabaseMock; + +class SqliteReadStatementMock +{ +public: + SqliteReadStatementMock() = default; + SqliteReadStatementMock(Utils::SmallStringView sqlStatement, SqliteDatabaseMock &databaseMock); + + MOCK_METHOD(std::vector<Utils::SmallString>, valuesReturnStringVector, (std::size_t), ()); + + MOCK_METHOD(std::vector<long long>, valuesReturnRowIds, (std::size_t), ()); + MOCK_METHOD(Utils::optional<long long>, valueReturnLongLong, (), ()); + MOCK_METHOD(Utils::optional<Sqlite::ByteArrayBlob>, + valueReturnBlob, + (Utils::SmallStringView, long long), + ()); + + template<typename ResultType, int ResultTypeCount = 1, typename... QueryType> + std::vector<ResultType> values(std::size_t reserveSize, const QueryType &... queryValues); + + template <typename ResultType, + int ResultTypeCount = 1, + typename... QueryType> + std::vector<ResultType> values(std::size_t reserveSize); + + template <typename ResultType, + int ResultTypeCount = 1, + template <typename...> class QueryContainerType, + typename QueryElementType> + std::vector<ResultType> values(std::size_t reserveSize, + const QueryContainerType<QueryElementType> &queryValues); + + template <typename ResultType, + int ResultTypeCount = 1, + typename... QueryTypes> + Utils::optional<ResultType> value(const QueryTypes&... queryValues); + +public: + Utils::SmallString sqlStatement; +}; + +template<> +std::vector<Utils::SmallString> SqliteReadStatementMock::values<Utils::SmallString>( + std::size_t reserveSize); + +template<> +std::vector<long long> SqliteReadStatementMock::values<long long>(std::size_t reserveSize); + +template<> +Utils::optional<long long> SqliteReadStatementMock::value<long long>(); + +template<> +Utils::optional<Sqlite::ByteArrayBlob> SqliteReadStatementMock::value<Sqlite::ByteArrayBlob>( + const Utils::SmallStringView &name, const long long &blob); diff --git a/tests/unit/unittest/sqlitestatement-test.cpp b/tests/unit/unittest/sqlitestatement-test.cpp index 341679a903..19c897f7cb 100644 --- a/tests/unit/unittest/sqlitestatement-test.cpp +++ b/tests/unit/unittest/sqlitestatement-test.cpp @@ -27,6 +27,7 @@ #include "mocksqlitestatement.h" #include "sqliteteststatement.h" +#include <sqliteblob.h> #include <sqlitedatabase.h> #include <sqlitereadstatement.h> #include <sqlitereadwritestatement.h> @@ -38,14 +39,6 @@ #include <vector> -namespace Sqlite { -bool operator==(Utils::span<const byte> first, Utils::span<const byte> second) -{ - return first.size() == second.size() - && std::memcmp(first.data(), second.data(), first.size()) == 0; -} -} // namespace Sqlite - namespace { using Sqlite::Database; @@ -270,7 +263,7 @@ 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<const Sqlite::byte *>(chars); - Utils::span<const Sqlite::byte> bytes{bytePointer, sizeof(chars) - 1}; + Sqlite::BlobView bytes{bytePointer, sizeof(chars) - 1}; statement.bind(1, bytes); statement.next(); @@ -281,7 +274,7 @@ TEST_F(SqliteStatement, BindBlob) TEST_F(SqliteStatement, BindEmptyBlob) { SqliteTestStatement statement("WITH T(blob) AS (VALUES (?)) SELECT blob FROM T", database); - Utils::span<const Sqlite::byte> bytes; + Sqlite::BlobView bytes; statement.bind(1, bytes); statement.next(); @@ -341,7 +334,7 @@ TEST_F(SqliteStatement, BindIndexIsToLargeIsThrowingBindingIndexIsOutOfBoundValu TEST_F(SqliteStatement, BindIndexIsToLargeIsThrowingBindingIndexIsOutOfBoundBlob) { SqliteTestStatement statement("WITH T(blob) AS (VALUES (?)) SELECT blob FROM T", database); - Utils::span<const Sqlite::byte> bytes; + Sqlite::BlobView bytes; ASSERT_THROW(statement.bind(2, bytes), Sqlite::BindingIndexIsOutOfRange); } @@ -408,34 +401,25 @@ TEST_F(SqliteStatement, WriteEmptyBlobs) { SqliteTestStatement statement("WITH T(blob) AS (VALUES (?)) SELECT blob FROM T", database); - Utils::span<const Sqlite::byte> bytes; + Sqlite::BlobView bytes; statement.write(bytes); ASSERT_THAT(statement.fetchBlobValue(0), IsEmpty()); } -class Blob -{ -public: - Blob(Utils::span<const Sqlite::byte> bytes) - : bytes(bytes.begin(), bytes.end()) - {} - - std::vector<Sqlite::byte> 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<const Sqlite::byte *>(chars); - Utils::span<const Sqlite::byte> bytes{bytePointer, sizeof(chars) - 1}; + Sqlite::BlobView bytes{bytePointer, sizeof(chars) - 1}; statement.write(bytes); - ASSERT_THAT(readStatement.template value<Blob>(), Optional(Field(&Blob::bytes, Eq(bytes)))); + ASSERT_THAT(readStatement.template value<Sqlite::Blob>(), + Optional(Field(&Sqlite::Blob::bytes, Eq(bytes)))); } TEST_F(SqliteStatement, CannotWriteToClosedDatabase) @@ -624,38 +608,38 @@ TEST_F(SqliteStatement, GetBlobValues) ReadStatement statement("SELECT value FROM test WHERE name='blob'", database); const int value = 0xDDCCBBAA; auto bytePointer = reinterpret_cast<const Sqlite::byte *>(&value); - Utils::span<const Sqlite::byte> bytes{bytePointer, 4}; + Sqlite::BlobView bytes{bytePointer, 4}; - auto values = statement.values<Blob>(1); + auto values = statement.values<Sqlite::Blob>(1); - ASSERT_THAT(values, ElementsAre(Field(&Blob::bytes, Eq(bytes)))); + ASSERT_THAT(values, ElementsAre(Field(&Sqlite::Blob::bytes, Eq(bytes)))); } TEST_F(SqliteStatement, GetEmptyBlobValueForInteger) { ReadStatement statement("SELECT value FROM test WHERE name='poo'", database); - auto value = statement.value<Blob>(); + auto value = statement.value<Sqlite::Blob>(); - ASSERT_THAT(value, Optional(Field(&Blob::bytes, IsEmpty()))); + ASSERT_THAT(value, Optional(Field(&Sqlite::Blob::bytes, IsEmpty()))); } TEST_F(SqliteStatement, GetEmptyBlobValueForFloat) { ReadStatement statement("SELECT number FROM test WHERE name='foo'", database); - auto value = statement.value<Blob>(); + auto value = statement.value<Sqlite::Blob>(); - ASSERT_THAT(value, Optional(Field(&Blob::bytes, IsEmpty()))); + ASSERT_THAT(value, Optional(Field(&Sqlite::Blob::bytes, IsEmpty()))); } TEST_F(SqliteStatement, GetEmptyBlobValueForText) { ReadStatement statement("SELECT number FROM test WHERE name='bar'", database); - auto value = statement.value<Blob>(); + auto value = statement.value<Sqlite::Blob>(); - ASSERT_THAT(value, Optional(Field(&Blob::bytes, IsEmpty()))); + ASSERT_THAT(value, Optional(Field(&Sqlite::Blob::bytes, IsEmpty()))); } TEST_F(SqliteStatement, GetOptionalSingleValueAndMultipleQueryValue) diff --git a/tests/unit/unittest/sqlitestatementmock.h b/tests/unit/unittest/sqlitestatementmock.h new file mode 100644 index 0000000000..ad8a73e0a5 --- /dev/null +++ b/tests/unit/unittest/sqlitestatementmock.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#pragma once + +#include <googletest.h> + +#include <sqlitebasestatement.h> + +class BaseSqliteStatementMock +{ +public: + MOCK_METHOD(bool, next, ()); + MOCK_METHOD(void, step, ()); + MOCK_METHOD(void, reset, ()); + + MOCK_METHOD(int, fetchIntValue, (int), (const)); + MOCK_METHOD(long, fetchLongValue, (int), (const)); + MOCK_METHOD(long long, fetchLongLongValue, (int), (const)); + MOCK_METHOD(double, fetchDoubleValue, (int), (const)); + MOCK_METHOD(Utils::SmallString, fetchSmallStringValue, (int), (const)); + MOCK_METHOD(Utils::PathString, fetchPathStringValue, (int), (const)); + + template<typename Type> + Type fetchValue(int column) const; + + MOCK_METHOD(void, bind, (int, int), ()); + MOCK_METHOD(void, bind, (int, long long), ()); + MOCK_METHOD(void, bind, (int, double), ()); + MOCK_METHOD(void, bind, (int, Utils::SmallStringView), ()); + MOCK_METHOD(void, bind, (int, long) ); + MOCK_METHOD(int, bindingIndexForName, (Utils::SmallStringView name), (const)); + + MOCK_METHOD(void, prepare, (Utils::SmallStringView sqlStatement)); +}; + +template<> +int BaseSqliteStatementMock::fetchValue<int>(int column) const +{ + return fetchIntValue(column); +} + +template<> +long BaseSqliteStatementMock::fetchValue<long>(int column) const +{ + return fetchLongValue(column); +} + +template<> +long long BaseSqliteStatementMock::fetchValue<long long>(int column) const +{ + return fetchLongLongValue(column); +} + +template<> +double BaseSqliteStatementMock::fetchValue<double>(int column) const +{ + return fetchDoubleValue(column); +} + +template<> +Utils::SmallString BaseSqliteStatementMock::fetchValue<Utils::SmallString>(int column) const +{ + return fetchSmallStringValue(column); +} + +template<> +Utils::PathString BaseSqliteStatementMock::fetchValue<Utils::PathString>(int column) const +{ + return fetchPathStringValue(column); +} + +class SqliteStatementMock : public Sqlite::StatementImplementation<NiceMock<BaseSqliteStatementMock>> +{ +public: + explicit SqliteStatementMock() + : Sqlite::StatementImplementation<NiceMock<BaseSqliteStatementMock>>() + {} + + +protected: + void checkIsWritableStatement(); +}; diff --git a/tests/unit/unittest/sqlitetransactionbackendmock.h b/tests/unit/unittest/sqlitetransactionbackendmock.h new file mode 100644 index 0000000000..7aad4f1f6a --- /dev/null +++ b/tests/unit/unittest/sqlitetransactionbackendmock.h @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#pragma once + + +#include "googletest.h" + +#include <sqlitetransaction.h> + +class SqliteTransactionBackendMock : public Sqlite::TransactionInterface +{ +public: + MOCK_METHOD(void, deferredBegin, (), (override)); + MOCK_METHOD(void, immediateBegin, (), (override)); + MOCK_METHOD(void, exclusiveBegin, (), (override)); + MOCK_METHOD(void, commit, (), (override)); + MOCK_METHOD(void, rollback, (), (override)); + MOCK_METHOD(void, lock, (), (override)); + MOCK_METHOD(void, unlock, (), (override)); + MOCK_METHOD(void, immediateSessionBegin, (), (override)); + MOCK_METHOD(void, sessionCommit, (), (override)); + MOCK_METHOD(void, sessionRollback, (), (override)); +}; diff --git a/tests/unit/unittest/sqlitewritestatementmock.cpp b/tests/unit/unittest/sqlitewritestatementmock.cpp new file mode 100644 index 0000000000..a3612833b2 --- /dev/null +++ b/tests/unit/unittest/sqlitewritestatementmock.cpp @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** 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 "sqlitewritestatementmock.h" + +#include "sqlitedatabasemock.h" + +SqliteWriteStatementMock::SqliteWriteStatementMock(Utils::SmallStringView sqlStatement, + SqliteDatabaseMock &database) + : sqlStatement(sqlStatement) +{ + database.prepare(sqlStatement); +} diff --git a/tests/unit/unittest/sqlitewritestatementmock.h b/tests/unit/unittest/sqlitewritestatementmock.h new file mode 100644 index 0000000000..3a8d159329 --- /dev/null +++ b/tests/unit/unittest/sqlitewritestatementmock.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#pragma once + +#include "googletest.h" + +#include <sqliteblob.h> +#include <sqlitevalue.h> + +class SqliteDatabaseMock; + +class SqliteWriteStatementMock +{ +public: + SqliteWriteStatementMock() = default; + SqliteWriteStatementMock(Utils::SmallStringView sqlStatement, SqliteDatabaseMock &database); + + MOCK_METHOD(void, execute, (), ()); + + MOCK_METHOD(void, write, (Utils::SmallStringView), ()); + MOCK_METHOD(void, write, (long long), ()); + MOCK_METHOD(void, write, (Utils::SmallStringView, Utils::SmallStringView), ()); + MOCK_METHOD(void, write, (long long, Utils::SmallStringView), ()); + MOCK_METHOD(void, + write, + (Utils::SmallStringView, Utils::SmallStringView, Utils::SmallStringView), + ()); + MOCK_METHOD(void, write, (Utils::SmallStringView, Utils::SmallStringView, long long), ()); + MOCK_METHOD(void, write, (Utils::SmallStringView, Utils::SmallStringView, double), ()); + MOCK_METHOD(void, write, (long long, Utils::SmallStringView, Utils::SmallStringView), ()); + MOCK_METHOD(void, write, (long long, Utils::SmallStringView, const Sqlite::Value &), ()); + MOCK_METHOD(void, write, (Utils::SmallStringView, long long, Sqlite::BlobView, Sqlite::BlobView), ()); + MOCK_METHOD(void, + write, + (Utils::SmallStringView, long long, Sqlite::NullValue, Sqlite::NullValue), + ()); + MOCK_METHOD(void, + write, + (Utils::SmallStringView, + Utils::SmallStringView, + Utils::SmallStringView, + Utils::SmallStringView), + ()); + MOCK_METHOD(void, + write, + (long long, Utils::SmallStringView, Utils::SmallStringView, Utils::SmallStringView), + ()); + MOCK_METHOD(void, write, (long long, long long, Utils::SmallStringView, Utils::SmallStringView), ()); + MOCK_METHOD(void, + write, + (Utils::SmallStringView, + Utils::SmallStringView, + Utils::SmallStringView, + Utils::SmallStringView, + Utils::SmallStringView), + ()); + + MOCK_METHOD(void, write, (void *, long long), ()); + + Utils::SmallString sqlStatement; +}; diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index 967463bbdc..6200a24d7f 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -66,6 +66,9 @@ SOURCES += \ filepathview-test.cpp \ gtest-creator-printing.cpp \ gtest-qt-printing.cpp \ + imagecache-test.cpp \ + imagecachegenerator-test.cpp \ + imagecachestorage-test.cpp \ lastchangedrowid-test.cpp \ lineprefixer-test.cpp \ listmodeleditor-test.cpp \ @@ -134,7 +137,9 @@ SOURCES += \ sqlitestatement-test.cpp \ sqlitetable-test.cpp \ sqlstatementbuilder-test.cpp \ - createtablesqlstatementbuilder-test.cpp + createtablesqlstatementbuilder-test.cpp \ + sqlitereadstatementmock.cpp \ + sqlitewritestatementmock.cpp !isEmpty(QTC_UNITTEST_BUILD_CPP_PARSER):SOURCES += matchingtext-test.cpp @@ -240,12 +245,15 @@ HEADERS += \ gtest-llvm-printing.h \ gtest-qt-printing.h \ gtest-std-printing.h \ + imagecachecollectormock.h \ mimedatabase-utilities.h \ mockclangcodemodelclient.h \ mockclangcodemodelserver.h \ mockclangpathwatcher.h \ mockclangpathwatchernotifier.h \ mockfilesystem.h \ + mockimagecachegenerator.h \ + mockimagecachestorage.h \ mocklistmodeleditorview.h \ mockpchcreator.h \ mockpchmanagerclient.h \ @@ -258,6 +266,8 @@ HEADERS += \ mocksearchhandle.h \ mocksearchresult.h \ mocksyntaxhighligher.h \ + mocktimestampprovider.h \ + notification.h \ processevents-utilities.h \ sourcerangecontainer-matcher.h \ spydummy.h \ @@ -301,7 +311,12 @@ HEADERS += \ mockpchtaskgenerator.h \ ../mockup/qmldesigner/designercore/include/nodeinstanceview.h \ ../mockup/qmldesigner/designercore/include/rewriterview.h \ - ../mockup/qmldesigner/designercore/include/itemlibraryitem.h + ../mockup/qmldesigner/designercore/include/itemlibraryitem.h\ + sqlitedatabasemock.h \ + sqlitereadstatementmock.h \ + sqlitestatementmock.h \ + sqlitetransactionbackendmock.h \ + sqlitewritestatementmock.h !isEmpty(LIBCLANG_LIBS) { diff --git a/tests/unit/unittest/unittest.qbs b/tests/unit/unittest/unittest.qbs index 5ceb723b22..ac7eb08b82 100644 --- a/tests/unit/unittest/unittest.qbs +++ b/tests/unit/unittest/unittest.qbs @@ -333,6 +333,19 @@ Project { "unittests-main.cpp", "usedmacrofilter-test.cpp", "utf8-test.cpp", + "imagecache-test.cpp", + "imagecachegenerator-test.cpp", + "imagecachestorage-test.cpp", + "sqlitedatabasemock.h", + "sqlitereadstatementmock.h", + "sqlitestatementmock.h", + "sqlitetransactionbackendmock.h", + "sqlitewritestatementmock.h", + "notification.h", + "mocktimestampprovider.h", + "imagecachecollectormock.h", + "mockimagecachegenerator.h", + "mockimagecachestorage.h", ] Group { |