summaryrefslogtreecommitdiff
path: root/tests/unit/unittest
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit/unittest')
-rw-r--r--tests/unit/unittest/clangcodecompleteresultstest.cpp87
-rw-r--r--tests/unit/unittest/clangipcservertest.cpp382
-rw-r--r--tests/unit/unittest/clangstringtest.cpp70
-rw-r--r--tests/unit/unittest/clientserverinprocesstest.cpp234
-rw-r--r--tests/unit/unittest/clientserveroutsideprocess.cpp201
-rw-r--r--tests/unit/unittest/codecompletionsextractortest.cpp663
-rw-r--r--tests/unit/unittest/codecompletiontest.cpp148
-rw-r--r--tests/unit/unittest/completionchunkstotextconvertertest.cpp128
-rw-r--r--tests/unit/unittest/createtablesqlstatementbuildertest.cpp189
-rw-r--r--tests/unit/unittest/data/complete_completer.cpp101
-rw-r--r--tests/unit/unittest/data/complete_completer_unsaved.cpp100
-rw-r--r--tests/unit/unittest/data/complete_extractor_class.cpp21
-rw-r--r--tests/unit/unittest/data/complete_extractor_constructor.cpp22
-rw-r--r--tests/unit/unittest/data/complete_extractor_enumeration.cpp22
-rw-r--r--tests/unit/unittest/data/complete_extractor_function.cpp22
-rw-r--r--tests/unit/unittest/data/complete_extractor_function_unsaved.cpp22
-rw-r--r--tests/unit/unittest/data/complete_extractor_function_unsaved_2.cpp22
-rw-r--r--tests/unit/unittest/data/complete_extractor_namespace.cpp22
-rw-r--r--tests/unit/unittest/data/complete_extractor_variable.cpp36
-rw-r--r--tests/unit/unittest/data/complete_testfile_1.cpp50
-rw-r--r--tests/unit/unittest/data/complete_translationunit_parse_error.cpp2
-rw-r--r--tests/unit/unittest/gtest-qt-printing.cpp31
-rw-r--r--tests/unit/unittest/gtest-qt-printing.h68
-rw-r--r--tests/unit/unittest/main.cpp47
-rw-r--r--tests/unit/unittest/mockipclient.h52
-rw-r--r--tests/unit/unittest/mockipcserver.h53
-rw-r--r--tests/unit/unittest/projecttest.cpp188
-rw-r--r--tests/unit/unittest/readandwritecommandblocktest.cpp225
-rw-r--r--tests/unit/unittest/spydummy.cpp42
-rw-r--r--tests/unit/unittest/spydummy.h49
-rw-r--r--tests/unit/unittest/sqlitecolumntest.cpp95
-rw-r--r--tests/unit/unittest/sqlitedatabasebackendtest.cpp154
-rw-r--r--tests/unit/unittest/sqlitedatabasetest.cpp112
-rw-r--r--tests/unit/unittest/sqlitestatementtest.cpp570
-rw-r--r--tests/unit/unittest/sqlitetabletest.cpp123
-rw-r--r--tests/unit/unittest/sqlstatementbuildertest.cpp176
-rw-r--r--tests/unit/unittest/translationunitstest.cpp182
-rw-r--r--tests/unit/unittest/translationunittest.cpp155
-rw-r--r--tests/unit/unittest/unittest.pro89
-rw-r--r--tests/unit/unittest/unsavedfilestest.cpp154
-rw-r--r--tests/unit/unittest/utf8test.cpp273
41 files changed, 5382 insertions, 0 deletions
diff --git a/tests/unit/unittest/clangcodecompleteresultstest.cpp b/tests/unit/unittest/clangcodecompleteresultstest.cpp
new file mode 100644
index 0000000000..228ec8ce87
--- /dev/null
+++ b/tests/unit/unittest/clangcodecompleteresultstest.cpp
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "gtest/gtest.h"
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock.h"
+#include "gtest-qt-printing.h"
+
+#include <clang-c/Index.h>
+
+#include <clangcodecompleteresults.h>
+#include <translationunit.h>
+#include <projectpart.h>
+#include <unsavedfiles.h>
+#include <utf8string.h>
+
+namespace {
+
+using ClangBackEnd::ClangCodeCompleteResults;
+using ClangBackEnd::TranslationUnit;
+using ClangBackEnd::UnsavedFiles;
+using ClangBackEnd::ProjectPart;
+
+TEST(ClangCodeCompleteResults, GetData)
+{
+ ProjectPart projectPart(Utf8StringLiteral("projectPartId"));
+ UnsavedFiles unsavedFiles;
+ TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), unsavedFiles, projectPart);
+ CXCodeCompleteResults *cxCodeCompleteResults = clang_codeCompleteAt(translationUnit.cxTranslationUnit(), translationUnit.filePath().constData(), 49, 1, 0, 0, 0);
+
+ ClangCodeCompleteResults codeCompleteResults(cxCodeCompleteResults);
+
+ ASSERT_THAT(codeCompleteResults.data(), cxCodeCompleteResults);
+}
+
+TEST(ClangCodeCompleteResults, GetInvalidData)
+{
+ CXCodeCompleteResults *cxCodeCompleteResults = clang_codeCompleteAt(nullptr, "file.cpp", 49, 1, 0, 0, 0);
+
+ ClangCodeCompleteResults codeCompleteResults(cxCodeCompleteResults);
+
+ ASSERT_THAT(codeCompleteResults.data(), cxCodeCompleteResults);
+}
+
+TEST(ClangCodeCompleteResults, MoveClangCodeCompleteResults)
+{
+ ProjectPart projectPart(Utf8StringLiteral("projectPartId"));
+ UnsavedFiles unsavedFiles;
+ TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), unsavedFiles, projectPart);
+ CXCodeCompleteResults *cxCodeCompleteResults = clang_codeCompleteAt(translationUnit.cxTranslationUnit(), translationUnit.filePath().constData(), 49, 1, 0, 0, 0);
+
+ ClangCodeCompleteResults codeCompleteResults(cxCodeCompleteResults);
+
+ const ClangCodeCompleteResults codeCompleteResults2 = std::move(codeCompleteResults);
+
+ ASSERT_TRUE(codeCompleteResults.isNull());
+ ASSERT_FALSE(codeCompleteResults2.isNull());
+}
+
+}
diff --git a/tests/unit/unittest/clangipcservertest.cpp b/tests/unit/unittest/clangipcservertest.cpp
new file mode 100644
index 0000000000..4070ad0579
--- /dev/null
+++ b/tests/unit/unittest/clangipcservertest.cpp
@@ -0,0 +1,382 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "gtest/gtest.h"
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock.h"
+
+#include "gtest-qt-printing.h"
+
+#include <ipcclientproxy.h>
+#include <ipcserverproxy.h>
+#include <clangipcserver.h>
+#include <translationunitdoesnotexistexception.h>
+#include <translationunitparseerrorexception.h>
+
+#include <cmbcodecompletedcommand.h>
+#include <cmbcompletecodecommand.h>
+#include <cmbechocommand.h>
+#include <cmbregistertranslationunitsforcodecompletioncommand.h>
+#include <cmbunregistertranslationunitsforcodecompletioncommand.h>
+#include <cmbregisterprojectsforcodecompletioncommand.h>
+#include <cmbunregisterprojectsforcodecompletioncommand.h>
+#include <translationunitdoesnotexistcommand.h>
+#include <projectpartsdonotexistcommand.h>
+
+#include <QBuffer>
+#include <QFile>
+#include <projectpartsdonotexistcommand.h>
+
+#include "mockipclient.h"
+
+using testing::Property;
+using testing::Contains;
+using testing::Not;
+using testing::Eq;
+
+namespace {
+
+using ClangBackEnd::RegisterTranslationUnitForCodeCompletionCommand;
+using ClangBackEnd::UnregisterTranslationUnitsForCodeCompletionCommand;
+using ClangBackEnd::RegisterProjectPartsForCodeCompletionCommand;
+using ClangBackEnd::UnregisterProjectPartsForCodeCompletionCommand;
+using ClangBackEnd::CompleteCodeCommand;
+using ClangBackEnd::CodeCompletedCommand;
+using ClangBackEnd::CodeCompletion;
+using ClangBackEnd::FileContainer;
+using ClangBackEnd::ProjectPartContainer;
+using ClangBackEnd::TranslationUnitDoesNotExistCommand;
+using ClangBackEnd::ProjectPartsDoNotExistCommand;
+
+class ClangIpcServer : public ::testing::Test
+{
+protected:
+ void SetUp() override;
+
+ void registerFiles();
+ void registerProjectPart();
+ void changeProjectPartArguments();
+ void changeProjectPartArgumentsToWrongValues();
+ static const Utf8String unsavedContent(const QString &unsavedFilePath);
+
+protected:
+ MockIpcClient mockIpcClient;
+ ClangBackEnd::ClangIpcServer clangServer;
+ const Utf8String projectPartId = Utf8StringLiteral("pathToProjectPart.pro");
+ const Utf8String functionTestFilePath = Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_function.cpp");
+ const Utf8String variableTestFilePath = Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_variable.cpp");
+ const QString unsavedTestFilePath = QStringLiteral(TESTDATA_DIR) + QStringLiteral("/complete_extractor_function_unsaved.cpp");
+ const QString updatedUnsavedTestFilePath = QStringLiteral(TESTDATA_DIR) + QStringLiteral("/complete_extractor_function_unsaved_2.cpp");
+ const Utf8String parseErrorTestFilePath = Utf8StringLiteral(TESTDATA_DIR"/complete_translationunit_parse_error.cpp");
+};
+
+
+void ClangIpcServer::SetUp()
+{
+ clangServer.addClient(&mockIpcClient);
+ registerProjectPart();
+ registerFiles();
+}
+
+void ClangIpcServer::registerFiles()
+{
+ RegisterTranslationUnitForCodeCompletionCommand command({FileContainer(functionTestFilePath, projectPartId, unsavedContent(unsavedTestFilePath), true),
+ FileContainer(variableTestFilePath, projectPartId)});
+
+ clangServer.registerTranslationUnitsForCodeCompletion(command);
+}
+
+void ClangIpcServer::registerProjectPart()
+{
+ RegisterProjectPartsForCodeCompletionCommand command({ProjectPartContainer(projectPartId)});
+
+ clangServer.registerProjectPartsForCodeCompletion(command);
+}
+
+void ClangIpcServer::changeProjectPartArguments()
+{
+ RegisterProjectPartsForCodeCompletionCommand command({ProjectPartContainer(projectPartId, {Utf8StringLiteral("-DArgumentDefinition")})});
+
+ clangServer.registerProjectPartsForCodeCompletion(command);
+}
+
+void ClangIpcServer::changeProjectPartArgumentsToWrongValues()
+{
+ RegisterProjectPartsForCodeCompletionCommand command({ProjectPartContainer(projectPartId, {Utf8StringLiteral("-blah")})});
+
+ clangServer.registerProjectPartsForCodeCompletion(command);
+}
+
+const Utf8String ClangIpcServer::unsavedContent(const QString &unsavedFilePath)
+{
+ QFile unsavedFileContentFile(unsavedFilePath);
+ bool isOpen = unsavedFileContentFile.open(QIODevice::ReadOnly | QIODevice::Text);
+ if (!isOpen)
+ ADD_FAILURE() << "File with the unsaved content cannot be opened!";
+
+ return Utf8String::fromByteArray(unsavedFileContentFile.readAll());
+}
+
+TEST_F(ClangIpcServer, GetCodeCompletion)
+{
+ CompleteCodeCommand completeCodeCommand(functionTestFilePath,
+ 20,
+ 1,
+ projectPartId);
+ CodeCompletion codeCompletion(Utf8StringLiteral("Function"),
+ Utf8String(),
+ Utf8String(),
+ 34,
+ CodeCompletion::FunctionCompletionKind);
+
+ EXPECT_CALL(mockIpcClient, codeCompleted(Property(&CodeCompletedCommand::codeCompletions, Contains(codeCompletion))))
+ .Times(1);
+
+ clangServer.completeCode(completeCodeCommand);
+}
+
+TEST_F(ClangIpcServer, GetCodeCompletionDependingOnArgumets)
+{
+ CompleteCodeCommand completeCodeCommand(variableTestFilePath,
+ 35,
+ 1,
+ projectPartId);
+ CodeCompletion codeCompletion(Utf8StringLiteral("ArgumentDefinitionVariable"),
+ Utf8String(),
+ Utf8String(),
+ 34,
+ CodeCompletion::VariableCompletionKind);
+
+ EXPECT_CALL(mockIpcClient, codeCompleted(Property(&CodeCompletedCommand::codeCompletions, Contains(codeCompletion))))
+ .Times(1);
+
+ changeProjectPartArguments();
+ clangServer.completeCode(completeCodeCommand);
+}
+
+TEST_F(ClangIpcServer, GetTranslationUnitDoesNotExistForCodeCompletionOnNonExistingTranslationUnit)
+{
+ CompleteCodeCommand completeCodeCommand(Utf8StringLiteral("dontexists.cpp"),
+ 34,
+ 1,
+ projectPartId);
+ TranslationUnitDoesNotExistCommand translationUnitDoesNotExistCommand(Utf8StringLiteral("dontexists.cpp"), projectPartId);
+
+ EXPECT_CALL(mockIpcClient, translationUnitDoesNotExist(translationUnitDoesNotExistCommand))
+ .Times(1);
+
+ clangServer.completeCode(completeCodeCommand);
+}
+
+TEST_F(ClangIpcServer, GetTranslationUnitDoesNotExistForCompletingUnregisteredFile)
+{
+ CompleteCodeCommand completeCodeCommand(parseErrorTestFilePath,
+ 20,
+ 1,
+ projectPartId);
+ TranslationUnitDoesNotExistCommand translationUnitDoesNotExistCommand(parseErrorTestFilePath, projectPartId);
+
+ EXPECT_CALL(mockIpcClient, translationUnitDoesNotExist(translationUnitDoesNotExistCommand))
+ .Times(1);
+
+ clangServer.completeCode(completeCodeCommand);
+}
+
+TEST_F(ClangIpcServer, GetCodeCompletionForUnsavedFile)
+{
+ CompleteCodeCommand completeCodeCommand(functionTestFilePath,
+ 20,
+ 1,
+ projectPartId);
+ CodeCompletion codeCompletion(Utf8StringLiteral("Method2"),
+ Utf8String(),
+ Utf8String(),
+ 34,
+ CodeCompletion::FunctionCompletionKind);
+
+ EXPECT_CALL(mockIpcClient, codeCompleted(Property(&CodeCompletedCommand::codeCompletions, Contains(codeCompletion))))
+ .Times(1);
+
+ clangServer.completeCode(completeCodeCommand);
+}
+
+TEST_F(ClangIpcServer, GetNoCodeCompletionAfterRemovingUnsavedFile)
+{
+ clangServer.registerTranslationUnitsForCodeCompletion(RegisterTranslationUnitForCodeCompletionCommand({FileContainer(functionTestFilePath, projectPartId)}));
+ CompleteCodeCommand completeCodeCommand(functionTestFilePath,
+ 20,
+ 1,
+ projectPartId);
+ CodeCompletion codeCompletion(Utf8StringLiteral("Method2"),
+ Utf8String(),
+ Utf8String(),
+ 34,
+ CodeCompletion::FunctionCompletionKind);
+
+ EXPECT_CALL(mockIpcClient, codeCompleted(Property(&CodeCompletedCommand::codeCompletions, Not(Contains(codeCompletion)))))
+ .Times(1);
+
+ clangServer.completeCode(completeCodeCommand);
+}
+
+TEST_F(ClangIpcServer, GetNewCodeCompletionAfterUpdatingUnsavedFile)
+{
+ clangServer.registerTranslationUnitsForCodeCompletion(RegisterTranslationUnitForCodeCompletionCommand({FileContainer(functionTestFilePath,
+ projectPartId,
+ unsavedContent(updatedUnsavedTestFilePath),
+ true)}));
+ CompleteCodeCommand completeCodeCommand(functionTestFilePath,
+ 20,
+ 1,
+ projectPartId);
+ CodeCompletion codeCompletion(Utf8StringLiteral("Method3"),
+ Utf8String(),
+ Utf8String(),
+ 34,
+ CodeCompletion::FunctionCompletionKind);
+
+ EXPECT_CALL(mockIpcClient, codeCompleted(Property(&CodeCompletedCommand::codeCompletions, Contains(codeCompletion))))
+ .Times(1);
+
+ clangServer.completeCode(completeCodeCommand);
+}
+
+TEST_F(ClangIpcServer, GetTranslationUnitDoesNotExistForUnregisterTranslationUnitWithWrongFilePath)
+{
+ FileContainer fileContainer(Utf8StringLiteral("foo.cpp"), projectPartId);
+ UnregisterTranslationUnitsForCodeCompletionCommand command({fileContainer});
+ TranslationUnitDoesNotExistCommand translationUnitDoesNotExistCommand(fileContainer);
+
+ EXPECT_CALL(mockIpcClient, translationUnitDoesNotExist(translationUnitDoesNotExistCommand))
+ .Times(1);
+
+ clangServer.unregisterTranslationUnitsForCodeCompletion(command);
+}
+
+TEST_F(ClangIpcServer, UnregisterTranslationUnitAndTestFailingCompletion)
+{
+ FileContainer fileContainer(functionTestFilePath, projectPartId);
+ UnregisterTranslationUnitsForCodeCompletionCommand command({fileContainer});
+ clangServer.unregisterTranslationUnitsForCodeCompletion(command);
+ CompleteCodeCommand completeCodeCommand(functionTestFilePath,
+ 20,
+ 1,
+ projectPartId);
+ TranslationUnitDoesNotExistCommand translationUnitDoesNotExistCommand(fileContainer);
+
+ EXPECT_CALL(mockIpcClient, translationUnitDoesNotExist(translationUnitDoesNotExistCommand))
+ .Times(1);
+
+ clangServer.completeCode(completeCodeCommand);
+}
+
+TEST_F(ClangIpcServer, GetProjectPartDoesNotExistUnregisterProjectPartInexistingProjectPart)
+{
+ Utf8StringVector inexistingProjectPartFilePath = {Utf8StringLiteral("projectpartsdoesnotexist.pro"), Utf8StringLiteral("project2doesnotexists.pro")};
+ UnregisterProjectPartsForCodeCompletionCommand unregisterProjectPartsForCodeCompletionCommand(inexistingProjectPartFilePath);
+ ProjectPartsDoNotExistCommand projectPartsDoNotExistCommand(inexistingProjectPartFilePath);
+
+ EXPECT_CALL(mockIpcClient, projectPartsDoNotExist(projectPartsDoNotExistCommand))
+ .Times(1);
+
+ clangServer.unregisterProjectPartsForCodeCompletion(unregisterProjectPartsForCodeCompletionCommand);
+}
+
+TEST_F(ClangIpcServer, GetProjectPartDoesNotExistRegisterTranslationUnitWithInexistingProjectPart)
+{
+ Utf8String inexistingProjectPartFilePath = Utf8StringLiteral("projectpartsdoesnotexist.pro");
+ RegisterTranslationUnitForCodeCompletionCommand registerFileForCodeCompletionCommand({FileContainer(variableTestFilePath, inexistingProjectPartFilePath)});
+ ProjectPartsDoNotExistCommand projectPartsDoNotExistCommand({inexistingProjectPartFilePath});
+
+ EXPECT_CALL(mockIpcClient, projectPartsDoNotExist(projectPartsDoNotExistCommand))
+ .Times(1);
+
+ clangServer.registerTranslationUnitsForCodeCompletion(registerFileForCodeCompletionCommand);
+}
+
+TEST_F(ClangIpcServer, GetProjectPartDoesNotExistUnregisterTranslationUnitWithInexistingProjectPart)
+{
+ Utf8String inexistingProjectPartFilePath = Utf8StringLiteral("projectpartsdoesnotexist.pro");
+ UnregisterTranslationUnitsForCodeCompletionCommand unregisterFileForCodeCompletionCommand({FileContainer(variableTestFilePath, inexistingProjectPartFilePath)});
+ ProjectPartsDoNotExistCommand projectPartsDoNotExistCommand({inexistingProjectPartFilePath});
+
+ EXPECT_CALL(mockIpcClient, projectPartsDoNotExist(projectPartsDoNotExistCommand))
+ .Times(1);
+
+ clangServer.unregisterTranslationUnitsForCodeCompletion(unregisterFileForCodeCompletionCommand);
+}
+
+TEST_F(ClangIpcServer, GetProjectPartDoesNotExistForCompletingProjectPartFile)
+{
+ Utf8String inexistingProjectPartFilePath = Utf8StringLiteral("projectpartsdoesnotexist.pro");
+ CompleteCodeCommand completeCodeCommand(variableTestFilePath,
+ 20,
+ 1,
+ inexistingProjectPartFilePath);
+ ProjectPartsDoNotExistCommand projectPartsDoNotExistCommand({inexistingProjectPartFilePath});
+
+ EXPECT_CALL(mockIpcClient, projectPartsDoNotExist(projectPartsDoNotExistCommand))
+ .Times(1);
+
+ clangServer.completeCode(completeCodeCommand);
+}
+
+TEST_F(ClangIpcServer, GetProjectPartDoesNotExistForCompletingUnregisteredFile)
+{
+ CompleteCodeCommand completeCodeCommand(parseErrorTestFilePath,
+ 20,
+ 1,
+ projectPartId);
+ TranslationUnitDoesNotExistCommand translationUnitDoesNotExistCommand(parseErrorTestFilePath, projectPartId);
+
+ EXPECT_CALL(mockIpcClient, translationUnitDoesNotExist(translationUnitDoesNotExistCommand))
+ .Times(1);
+
+ clangServer.completeCode(completeCodeCommand);
+}
+
+TEST_F(ClangIpcServer, TicketNumberIsForwarded)
+{
+ CompleteCodeCommand completeCodeCommand(functionTestFilePath,
+ 20,
+ 1,
+ projectPartId);
+ CodeCompletion codeCompletion(Utf8StringLiteral("Function"),
+ Utf8String(),
+ Utf8String(),
+ 34,
+ CodeCompletion::FunctionCompletionKind);
+
+ EXPECT_CALL(mockIpcClient, codeCompleted(Property(&CodeCompletedCommand::ticketNumber, Eq(completeCodeCommand.ticketNumber()))))
+ .Times(1);
+
+ clangServer.completeCode(completeCodeCommand);
+}
+}
diff --git a/tests/unit/unittest/clangstringtest.cpp b/tests/unit/unittest/clangstringtest.cpp
new file mode 100644
index 0000000000..a7b5f86767
--- /dev/null
+++ b/tests/unit/unittest/clangstringtest.cpp
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "gtest/gtest.h"
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock.h"
+#include "gtest-qt-printing.h"
+
+#include <clang-c/CXString.h>
+#include <clang-c/Index.h>
+
+#include <clangstring.h>
+#include <utf8string.h>
+
+namespace {
+
+using ClangBackEnd::ClangString;
+
+TEST(ClangString, ConvertToUtf8String)
+{
+ const CXString cxString = { "text", 0};
+
+ ASSERT_THAT(Utf8String(ClangString(cxString)), Utf8StringLiteral("text"));
+}
+
+TEST(ClangString, ConvertNullStringToUtf8String)
+{
+ const CXString cxString = { 0, 0};
+
+ ASSERT_THAT(Utf8String(ClangString(cxString)), Utf8String());
+}
+
+TEST(ClangString, MoveClangString)
+{
+ ClangString text(CXString{ "text", 0});
+
+ const ClangString text2 = std::move(text);
+
+ ASSERT_TRUE(text.isNull());
+ ASSERT_FALSE(text2.isNull());
+}
+
+}
diff --git a/tests/unit/unittest/clientserverinprocesstest.cpp b/tests/unit/unittest/clientserverinprocesstest.cpp
new file mode 100644
index 0000000000..3d29e596f0
--- /dev/null
+++ b/tests/unit/unittest/clientserverinprocesstest.cpp
@@ -0,0 +1,234 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "gtest/gtest.h"
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock.h"
+
+#include "gtest-qt-printing.h"
+#include "translationunitdoesnotexistcommand.h"
+
+#include <QString>
+#include <QBuffer>
+#include <QVariant>
+#include <vector>
+
+#include <cmbendcommand.h>
+#include <cmbalivecommand.h>
+#include <cmbcommands.h>
+#include <cmbechocommand.h>
+#include <cmbregistertranslationunitsforcodecompletioncommand.h>
+#include <cmbunregistertranslationunitsforcodecompletioncommand.h>
+#include <cmbcodecompletedcommand.h>
+#include <cmbregisterprojectsforcodecompletioncommand.h>
+#include <cmbunregisterprojectsforcodecompletioncommand.h>
+#include <cmbcompletecodecommand.h>
+#include <writecommandblock.h>
+#include <readcommandblock.h>
+
+#include <ipcserverproxy.h>
+#include <ipcclientproxy.h>
+#include <projectpartsdonotexistcommand.h>
+
+#include "mockipclient.h"
+#include "mockipcserver.h"
+
+using namespace ClangBackEnd;
+
+namespace {
+
+using ::testing::Args;
+using ::testing::Property;
+using ::testing::Eq;
+
+class ClientServerInProcess : public ::testing::Test
+{
+protected:
+ ClientServerInProcess();
+
+ void SetUp();
+ void TearDown();
+
+
+ void scheduleServerCommands();
+ void scheduleClientCommands();
+
+ QBuffer buffer;
+ MockIpcClient mockIpcClient;
+ MockIpcServer mockIpcServer;
+
+ ClangBackEnd::IpcServerProxy serverProxy;
+ ClangBackEnd::IpcClientProxy clientProxy;
+};
+
+TEST_F(ClientServerInProcess, SendEndCommand)
+{
+ EXPECT_CALL(mockIpcServer, end())
+ .Times(1);
+
+ serverProxy.end();
+ scheduleServerCommands();
+}
+
+TEST_F(ClientServerInProcess, SendAliveCommand)
+{
+ EXPECT_CALL(mockIpcClient, alive())
+ .Times(1);
+
+ clientProxy.alive();
+ scheduleClientCommands();
+}
+
+TEST_F(ClientServerInProcess, SendRegisterTranslationUnitForCodeCompletionCommand)
+{
+ ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_function.cpp"),
+ Utf8StringLiteral("pathToProjectPart.pro"));
+ ClangBackEnd::RegisterTranslationUnitForCodeCompletionCommand command({fileContainer});
+
+ EXPECT_CALL(mockIpcServer, registerTranslationUnitsForCodeCompletion(command))
+ .Times(1);
+
+ serverProxy.registerTranslationUnitsForCodeCompletion(command);
+ scheduleServerCommands();
+}
+
+TEST_F(ClientServerInProcess, SendUnregisterTranslationUnitsForCodeCompletionCommand)
+{
+ ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral("foo.cpp"), Utf8StringLiteral("pathToProjectPart.pro"));
+ ClangBackEnd::UnregisterTranslationUnitsForCodeCompletionCommand command({fileContainer});
+
+ EXPECT_CALL(mockIpcServer, unregisterTranslationUnitsForCodeCompletion(command))
+ .Times(1);
+
+ serverProxy.unregisterTranslationUnitsForCodeCompletion(command);
+ scheduleServerCommands();
+}
+
+TEST_F(ClientServerInProcess, SendCompleteCodeCommand)
+{
+ ClangBackEnd::CompleteCodeCommand command(Utf8StringLiteral("foo.cpp"), 24, 33, Utf8StringLiteral("do what I want"));
+
+ EXPECT_CALL(mockIpcServer, completeCode(command))
+ .Times(1);
+
+ serverProxy.completeCode(command);
+ scheduleServerCommands();
+}
+
+TEST_F(ClientServerInProcess, SendCodeCompletedCommand)
+{
+ QVector<ClangBackEnd::CodeCompletion> codeCompletions({Utf8StringLiteral("newFunction()")});
+ ClangBackEnd::CodeCompletedCommand command(codeCompletions, 1);
+
+ EXPECT_CALL(mockIpcClient, codeCompleted(command))
+ .Times(1);
+
+ clientProxy.codeCompleted(command);
+ scheduleClientCommands();
+}
+
+TEST_F(ClientServerInProcess, SendRegisterProjectPartsForCodeCompletionCommand)
+{
+ ClangBackEnd::ProjectPartContainer projectContainer(Utf8StringLiteral(TESTDATA_DIR"/complete.pro"));
+ ClangBackEnd::RegisterProjectPartsForCodeCompletionCommand command({projectContainer});
+
+ EXPECT_CALL(mockIpcServer, registerProjectPartsForCodeCompletion(command))
+ .Times(1);
+
+ serverProxy.registerProjectPartsForCodeCompletion(command);
+ scheduleServerCommands();
+}
+
+TEST_F(ClientServerInProcess, SendUnregisterProjectPartsForCodeCompletionCommand)
+{
+ ClangBackEnd::UnregisterProjectPartsForCodeCompletionCommand command({Utf8StringLiteral(TESTDATA_DIR"/complete.pro")});
+
+ EXPECT_CALL(mockIpcServer, unregisterProjectPartsForCodeCompletion(command))
+ .Times(1);
+
+ serverProxy.unregisterProjectPartsForCodeCompletion(command);
+ scheduleServerCommands();
+}
+
+TEST_F(ClientServerInProcess, SendTranslationUnitDoesNotExistCommand)
+{
+ ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_function.cpp"),
+ Utf8StringLiteral("pathToProjectPart.pro"));
+ ClangBackEnd::TranslationUnitDoesNotExistCommand command(fileContainer);
+
+ EXPECT_CALL(mockIpcClient, translationUnitDoesNotExist(command))
+ .Times(1);
+
+ clientProxy.translationUnitDoesNotExist(command);
+ scheduleClientCommands();
+}
+
+
+TEST_F(ClientServerInProcess, SendProjectPartDoesNotExistCommand)
+{
+ ClangBackEnd::ProjectPartsDoNotExistCommand command({Utf8StringLiteral("pathToProjectPart.pro")});
+
+ EXPECT_CALL(mockIpcClient, projectPartsDoNotExist(command))
+ .Times(1);
+
+ clientProxy.projectPartsDoNotExist(command);
+ scheduleClientCommands();
+}
+ClientServerInProcess::ClientServerInProcess()
+ : serverProxy(&mockIpcClient, &buffer),
+ clientProxy(&mockIpcServer, &buffer)
+{
+}
+
+void ClientServerInProcess::SetUp()
+{
+ buffer.open(QIODevice::ReadWrite);
+}
+
+void ClientServerInProcess::TearDown()
+{
+ buffer.close();
+}
+
+void ClientServerInProcess::scheduleServerCommands()
+{
+ buffer.seek(0);
+ clientProxy.readCommands();
+ buffer.buffer().clear();
+}
+
+void ClientServerInProcess::scheduleClientCommands()
+{
+ buffer.seek(0);
+ serverProxy.readCommands();
+ buffer.buffer().clear();
+}
+
+}
diff --git a/tests/unit/unittest/clientserveroutsideprocess.cpp b/tests/unit/unittest/clientserveroutsideprocess.cpp
new file mode 100644
index 0000000000..22be5abce8
--- /dev/null
+++ b/tests/unit/unittest/clientserveroutsideprocess.cpp
@@ -0,0 +1,201 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+
+#include "gtest/gtest.h"
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock.h"
+
+#include <QBuffer>
+#include <QProcess>
+#include <QSignalSpy>
+#include <QString>
+#include <QVariant>
+
+#include <vector>
+
+#include "gtest-qt-printing.h"
+
+#include <cmbendcommand.h>
+#include <cmbalivecommand.h>
+#include <cmbcommands.h>
+#include <cmbechocommand.h>
+#include <cmbregistertranslationunitsforcodecompletioncommand.h>
+#include <cmbunregistertranslationunitsforcodecompletioncommand.h>
+#include <cmbregisterprojectsforcodecompletioncommand.h>
+#include <cmbunregisterprojectsforcodecompletioncommand.h>
+#include <cmbcodecompletedcommand.h>
+#include <cmbcompletecodecommand.h>
+#include <writecommandblock.h>
+#include <readcommandblock.h>
+#include <connectionclient.h>
+#include <translationunitdoesnotexistcommand.h>
+#include <projectpartsdonotexistcommand.h>
+
+#include <mockipclient.h>
+
+#ifdef Q_OS_WIN
+#define QTC_HOST_EXE_SUFFIX L".exe"
+#else
+#define QTC_HOST_EXE_SUFFIX ""
+#endif
+
+using namespace ClangBackEnd;
+
+using ::testing::Eq;
+
+class ClientServerOutsideProcess : public ::testing::Test
+{
+protected:
+ void SetUp();
+ void TearDown();
+
+ static void SetUpTestCase();
+ static void TearDownTestCase();
+
+ static MockIpcClient mockIpcClient;
+ static ClangBackEnd::ConnectionClient client;
+};
+
+MockIpcClient ClientServerOutsideProcess::mockIpcClient;
+ClangBackEnd::ConnectionClient ClientServerOutsideProcess::client(&ClientServerOutsideProcess::mockIpcClient);
+
+TEST_F(ClientServerOutsideProcess, RestartProcess)
+{
+ client.restartProcess();
+
+ ASSERT_TRUE(client.isProcessIsRunning());
+ ASSERT_TRUE(client.isConnected());
+}
+
+TEST_F(ClientServerOutsideProcess, RestartProcessAfterAliveTimeout)
+{
+ QSignalSpy clientSpy(&client, SIGNAL(processRestarted()));
+
+ client.setProcessAliveTimerInterval(1);
+
+ ASSERT_TRUE(clientSpy.wait(100000));
+}
+
+TEST_F(ClientServerOutsideProcess, RestartProcessAfterTermination)
+{
+ QSignalSpy clientSpy(&client, SIGNAL(processRestarted()));
+
+ client.processForTestOnly()->kill();
+
+ ASSERT_TRUE(clientSpy.wait(100000));
+}
+
+TEST_F(ClientServerOutsideProcess, SendRegisterTranslationUnitForCodeCompletionCommand)
+{
+ ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral("foo"), Utf8StringLiteral("pathToProjectPart.pro"));
+ ClangBackEnd::RegisterTranslationUnitForCodeCompletionCommand registerTranslationUnitForCodeCompletionCommand({fileContainer});
+ EchoCommand echoCommand(QVariant::fromValue(registerTranslationUnitForCodeCompletionCommand));
+
+ EXPECT_CALL(mockIpcClient, echo(echoCommand))
+ .Times(1);
+
+ client.serverProxy().registerTranslationUnitsForCodeCompletion(registerTranslationUnitForCodeCompletionCommand);
+ ASSERT_TRUE(client.waitForEcho());
+}
+
+TEST_F(ClientServerOutsideProcess, SendUnregisterTranslationUnitsForCodeCompletionCommand)
+{
+ FileContainer fileContainer(Utf8StringLiteral("foo.cpp"), Utf8StringLiteral("bar.pro"));
+ ClangBackEnd::UnregisterTranslationUnitsForCodeCompletionCommand unregisterTranslationUnitsForCodeCompletionCommand ({fileContainer});
+ EchoCommand echoCommand(QVariant::fromValue(unregisterTranslationUnitsForCodeCompletionCommand));
+
+ EXPECT_CALL(mockIpcClient, echo(echoCommand))
+ .Times(1);
+
+ client.serverProxy().unregisterTranslationUnitsForCodeCompletion(unregisterTranslationUnitsForCodeCompletionCommand);
+ ASSERT_TRUE(client.waitForEcho());
+}
+
+TEST_F(ClientServerOutsideProcess, SendCompleteCodeCommand)
+{
+ CompleteCodeCommand codeCompleteCommand(Utf8StringLiteral("foo.cpp"), 24, 33, Utf8StringLiteral("do what I want"));
+ EchoCommand echoCommand(QVariant::fromValue(codeCompleteCommand));
+
+ EXPECT_CALL(mockIpcClient, echo(echoCommand))
+ .Times(1);
+
+ client.serverProxy().completeCode(codeCompleteCommand);
+ ASSERT_TRUE(client.waitForEcho());
+}
+
+TEST_F(ClientServerOutsideProcess, SendRegisterProjectPartsForCodeCompletionCommand)
+{
+ ClangBackEnd::ProjectPartContainer projectContainer(Utf8StringLiteral(TESTDATA_DIR"/complete.pro"));
+ ClangBackEnd::RegisterProjectPartsForCodeCompletionCommand registerProjectPartsForCodeCompletionCommand({projectContainer});
+ EchoCommand echoCommand(QVariant::fromValue(registerProjectPartsForCodeCompletionCommand));
+
+ EXPECT_CALL(mockIpcClient, echo(echoCommand))
+ .Times(1);
+
+ client.serverProxy().registerProjectPartsForCodeCompletion(registerProjectPartsForCodeCompletionCommand);
+ ASSERT_TRUE(client.waitForEcho());
+}
+
+TEST_F(ClientServerOutsideProcess, SendUnregisterProjectPartsForCodeCompletionCommand)
+{
+ ClangBackEnd::UnregisterProjectPartsForCodeCompletionCommand unregisterProjectPartsForCodeCompletionCommand({Utf8StringLiteral(TESTDATA_DIR"/complete.pro")});
+ EchoCommand echoCommand(QVariant::fromValue(unregisterProjectPartsForCodeCompletionCommand));
+
+ EXPECT_CALL(mockIpcClient, echo(echoCommand))
+ .Times(1);
+
+ client.serverProxy().unregisterProjectPartsForCodeCompletion(unregisterProjectPartsForCodeCompletionCommand);
+ ASSERT_TRUE(client.waitForEcho());
+}
+
+void ClientServerOutsideProcess::SetUpTestCase()
+{
+ client.setProcessPath(QStringLiteral(ECHOSERVER QTC_HOST_EXE_SUFFIX));
+
+ ASSERT_TRUE(client.connectToServer());
+}
+
+void ClientServerOutsideProcess::TearDownTestCase()
+{
+ client.finishProcess();
+}
+void ClientServerOutsideProcess::SetUp()
+{
+ client.setProcessAliveTimerInterval(1000000);
+
+ ASSERT_TRUE(client.isConnected());
+}
+
+void ClientServerOutsideProcess::TearDown()
+{
+ ASSERT_TRUE(client.isProcessIsRunning());
+ ASSERT_TRUE(client.isConnected());
+}
diff --git a/tests/unit/unittest/codecompletionsextractortest.cpp b/tests/unit/unittest/codecompletionsextractortest.cpp
new file mode 100644
index 0000000000..e9a4f26856
--- /dev/null
+++ b/tests/unit/unittest/codecompletionsextractortest.cpp
@@ -0,0 +1,663 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "gtest/gtest.h"
+
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock-generated-matchers.h"
+#include "gtest-qt-printing.h"
+
+#include <clang-c/Index.h>
+
+#include <codecompletionsextractor.h>
+#include <clangcodecompleteresults.h>
+#include <filecontainer.h>
+#include <translationunit.h>
+#include <unsavedfiles.h>
+#include <projectpart.h>
+#include <utf8stringvector.h>
+
+#include <QFile>
+
+using ClangBackEnd::CodeCompletionsExtractor;
+using ClangBackEnd::ClangCodeCompleteResults;
+using ClangBackEnd::TranslationUnit;
+using ClangBackEnd::CodeCompletion;
+using ClangBackEnd::UnsavedFiles;
+using ClangBackEnd::CodeCompletionChunk;
+
+
+
+namespace {
+
+using ::testing::PrintToString;
+using ::testing::Not;
+
+MATCHER_P3(HasCompletion, name, kind, availability,
+ std::string(negation ? "hasn't" : "has") + " completion of name " + PrintToString(name) +
+ ", kind " + PrintToString(kind))
+{
+ ::CodeCompletionsExtractor &extractor = const_cast<::CodeCompletionsExtractor&>(arg);
+ while (extractor.next()) {
+ if (extractor.currentCodeCompletion().text() == name) {
+ if (extractor.currentCodeCompletion().completionKind() == kind) {
+ if (extractor.currentCodeCompletion().availability() == availability) {
+ return true;
+ } else if (!extractor.peek(name)) {
+ *result_listener << "availability is " << PrintToString(extractor.currentCodeCompletion().availability()) << " and not " << PrintToString(availability);
+ return false;
+ }
+ } else if (!extractor.peek(name)) {
+ *result_listener << "kind is " << PrintToString(extractor.currentCodeCompletion().completionKind()) << " and not " << PrintToString(kind);
+ return false;
+ }
+ }
+ }
+
+ return false;
+}
+
+MATCHER_P2(HasCompletionChunks, name, chunks,
+ std::string(negation ? "hasn't" : "has") + " completion of name " + PrintToString(name) +
+ " with the chunks " + PrintToString(chunks))
+{
+ ::CodeCompletionsExtractor &extractor = const_cast<::CodeCompletionsExtractor&>(arg);
+ while (extractor.next()) {
+ if (extractor.currentCodeCompletion().text() == name) {
+ if (extractor.currentCodeCompletion().chunks() == chunks) {
+ return true;
+ } else if (!extractor.peek(name)) {
+ *result_listener << "chunks are " << PrintToString(arg.currentCodeCompletion().chunks()) << " and not " << PrintToString(chunks);
+ return false;
+ }
+ }
+ }
+
+ return false;
+}
+
+const Utf8String unsavedFileContent(const char *unsavedFilePath)
+{
+ QFile unsavedFileContentFile(QString::fromUtf8(unsavedFilePath));
+ bool isOpen = unsavedFileContentFile.open(QIODevice::ReadOnly | QIODevice::Text);
+ if (!isOpen)
+ ADD_FAILURE() << "File with the unsaved content cannot be opened!";
+
+ return Utf8String::fromByteArray(unsavedFileContentFile.readAll());
+}
+
+const ClangBackEnd::FileContainer unsavedDataFileContainer(const char *filePath,
+ const char *unsavedFilePath)
+{
+ return ClangBackEnd::FileContainer(Utf8String::fromUtf8(filePath),
+ Utf8String(),
+ unsavedFileContent(unsavedFilePath),
+ true);
+}
+
+ClangCodeCompleteResults getResults(const TranslationUnit &translationUnit, uint line, uint column = 1)
+{
+ return ClangCodeCompleteResults(clang_codeCompleteAt(translationUnit.cxTranslationUnit(),
+ translationUnit.filePath().constData(),
+ line,
+ column,
+ translationUnit.cxUnsavedFiles(),
+ translationUnit.unsavedFilesCount(),
+ CXCodeComplete_IncludeMacros | CXCodeComplete_IncludeCodePatterns));
+}
+
+class CodeCompletionsExtractor : public ::testing::Test
+{
+public:
+ static void TearDownTestCase();
+
+protected:
+ static ClangBackEnd::ProjectPart project;
+ static ClangBackEnd::UnsavedFiles unsavedFiles;
+ static TranslationUnit functionTranslationUnit;
+ static TranslationUnit variableTranslationUnit;
+ static TranslationUnit classTranslationUnit ;
+ static TranslationUnit namespaceTranslationUnit;
+ static TranslationUnit enumerationTranslationUnit;
+ static TranslationUnit constructorTranslationUnit;
+};
+
+ClangBackEnd::ProjectPart CodeCompletionsExtractor::project(Utf8StringLiteral("/path/to/projectfile"));
+ClangBackEnd::UnsavedFiles CodeCompletionsExtractor::unsavedFiles;
+TranslationUnit CodeCompletionsExtractor::functionTranslationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_function.cpp"), unsavedFiles, project);
+TranslationUnit CodeCompletionsExtractor::variableTranslationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_variable.cpp"), unsavedFiles, project);
+TranslationUnit CodeCompletionsExtractor::classTranslationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_class.cpp"), unsavedFiles, project);
+TranslationUnit CodeCompletionsExtractor::namespaceTranslationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_namespace.cpp"), unsavedFiles, project);
+TranslationUnit CodeCompletionsExtractor::enumerationTranslationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_enumeration.cpp"), unsavedFiles, project);
+TranslationUnit CodeCompletionsExtractor::constructorTranslationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_constructor.cpp"), unsavedFiles, project);
+
+void CodeCompletionsExtractor::TearDownTestCase()
+{
+ functionTranslationUnit.reset();
+ variableTranslationUnit.reset();
+ classTranslationUnit.reset();
+ namespaceTranslationUnit.reset();
+ enumerationTranslationUnit.reset();
+ constructorTranslationUnit.reset();
+}
+
+TEST_F(CodeCompletionsExtractor, Function)
+{
+ ClangCodeCompleteResults completeResults(getResults(functionTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Function"),
+ CodeCompletion::FunctionCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, TemplateFunction)
+{
+ ClangCodeCompleteResults completeResults(getResults(functionTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("TemplateFunction"),
+ CodeCompletion::TemplateFunctionCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, Variable)
+{
+ ClangCodeCompleteResults completeResults(getResults(variableTranslationUnit, 4));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Var"),
+ CodeCompletion::VariableCompletionKind,
+ CodeCompletion::Available));
+}
+
+
+TEST_F(CodeCompletionsExtractor, NonTypeTemplateParameter)
+{
+ ClangCodeCompleteResults completeResults(getResults(variableTranslationUnit, 25, 19));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("NonTypeTemplateParameter"),
+ CodeCompletion::VariableCompletionKind,
+ CodeCompletion::Available));
+}
+
+
+TEST_F(CodeCompletionsExtractor, VariableReference)
+{
+ ClangCodeCompleteResults completeResults(getResults(variableTranslationUnit, 12));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Var"),
+ CodeCompletion::VariableCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, Parameter)
+{
+ ClangCodeCompleteResults completeResults(getResults(variableTranslationUnit, 4));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Parameter"),
+ CodeCompletion::VariableCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, Field)
+{
+ ClangCodeCompleteResults completeResults(getResults(variableTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Field"),
+ CodeCompletion::VariableCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, Class)
+{
+ ClangCodeCompleteResults completeResults(getResults(classTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Class"),
+ CodeCompletion::ClassCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, Struct)
+{
+ ClangCodeCompleteResults completeResults(getResults(classTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Struct"),
+ CodeCompletion::ClassCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, Union)
+{
+ ClangCodeCompleteResults completeResults(getResults(classTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Union"),
+ CodeCompletion::ClassCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, TemplateTypeParameter)
+{
+ ClangCodeCompleteResults completeResults(getResults(classTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("TemplateTypeParameter"),
+ CodeCompletion::ClassCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, TemplateClass)
+{
+ ClangCodeCompleteResults completeResults(getResults(classTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("TemplateClass"),
+ CodeCompletion::TemplateClassCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, TemplateTemplateParameter)
+{
+ ClangCodeCompleteResults completeResults(getResults(classTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("TemplateTemplateParameter"),
+ CodeCompletion::TemplateClassCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, ClassTemplatePartialSpecialization)
+{
+ ClangCodeCompleteResults completeResults(getResults(classTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("ClassTemplatePartialSpecialization"),
+ CodeCompletion::TemplateClassCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, Namespace)
+{
+ ClangCodeCompleteResults completeResults(getResults(namespaceTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Namespace"),
+ CodeCompletion::NamespaceCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, NamespaceAlias)
+{
+ ClangCodeCompleteResults completeResults(getResults(namespaceTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("NamespaceAlias"),
+ CodeCompletion::NamespaceCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, Enumeration)
+{
+ ClangCodeCompleteResults completeResults(getResults(enumerationTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Enumeration"),
+ CodeCompletion::EnumerationCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, Enumerator)
+{
+ ClangCodeCompleteResults completeResults(getResults(enumerationTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Enumerator"),
+ CodeCompletion::EnumeratorCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, Constructor)
+{
+ ClangCodeCompleteResults completeResults(getResults(constructorTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Constructor"),
+ CodeCompletion::ConstructorCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, Destructor)
+{
+ ClangCodeCompleteResults completeResults(getResults(constructorTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("~Constructor"),
+ CodeCompletion::DestructorCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, Method)
+{
+ ClangCodeCompleteResults completeResults(getResults(functionTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Method"),
+ CodeCompletion::FunctionCompletionKind,
+ CodeCompletion::Available));
+ ASSERT_FALSE(extractor.currentCodeCompletion().hasParameters());
+}
+
+TEST_F(CodeCompletionsExtractor, MethodWithParameters)
+{
+ ClangCodeCompleteResults completeResults(getResults(functionTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("MethodWithParameters"),
+ CodeCompletion::FunctionCompletionKind,
+ CodeCompletion::Available));
+ ASSERT_TRUE(extractor.currentCodeCompletion().hasParameters());
+}
+
+TEST_F(CodeCompletionsExtractor, Slot)
+{
+ ClangCodeCompleteResults completeResults(getResults(functionTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Slot"),
+ CodeCompletion::SlotCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, Signal)
+{
+ ClangCodeCompleteResults completeResults(getResults(functionTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Signal"),
+ CodeCompletion::SignalCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, MacroDefinition)
+{
+ ClangCodeCompleteResults completeResults(getResults(variableTranslationUnit, 35));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("MacroDefinition"),
+ CodeCompletion::PreProcessorCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, FunctionMacro)
+{
+ ClangCodeCompleteResults completeResults(getResults(functionTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("FunctionMacro"),
+ CodeCompletion::FunctionCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, IntKeyword)
+{
+ ClangCodeCompleteResults completeResults(getResults(functionTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("int"),
+ CodeCompletion::KeywordCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, SwitchKeyword)
+{
+ ClangCodeCompleteResults completeResults(getResults(functionTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("switch"),
+ CodeCompletion::KeywordCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, ClassKeyword)
+{
+ ClangCodeCompleteResults completeResults(getResults(functionTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("class"),
+ CodeCompletion::KeywordCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, DeprecatedFunction)
+{
+ ClangCodeCompleteResults completeResults(getResults(functionTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("DeprecatedFunction"),
+ CodeCompletion::FunctionCompletionKind,
+ CodeCompletion::Deprecated));
+}
+
+TEST_F(CodeCompletionsExtractor, NotAccessibleFunction)
+{
+ ClangCodeCompleteResults completeResults(getResults(functionTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("NotAccessibleFunction"),
+ CodeCompletion::FunctionCompletionKind,
+ CodeCompletion::NotAccessible));
+}
+
+TEST_F(CodeCompletionsExtractor, NotAvailableFunction)
+{
+ ClangCodeCompleteResults completeResults(getResults(functionTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("NotAvailableFunction"),
+ CodeCompletion::FunctionCompletionKind,
+ CodeCompletion::NotAvailable));
+}
+
+TEST_F(CodeCompletionsExtractor, UnsavedFile)
+{
+ ClangBackEnd::UnsavedFiles unsavedFiles;
+ ClangBackEnd::ProjectPart project(Utf8StringLiteral("/path/to/projectfile"));
+ TranslationUnit translationUnit(Utf8String::fromUtf8(TESTDATA_DIR"/complete_extractor_function.cpp"), unsavedFiles, project);
+ unsavedFiles.createOrUpdate({unsavedDataFileContainer(TESTDATA_DIR"/complete_extractor_function.cpp",
+ TESTDATA_DIR"/complete_extractor_function_unsaved.cpp")});
+ ClangCodeCompleteResults completeResults(getResults(translationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Method2"),
+ CodeCompletion::FunctionCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, ChangeUnsavedFile)
+{
+ ClangBackEnd::UnsavedFiles unsavedFiles;
+ ClangBackEnd::ProjectPart project(Utf8StringLiteral("/path/to/projectfile"));
+ TranslationUnit translationUnit(Utf8String::fromUtf8(TESTDATA_DIR"/complete_extractor_function.cpp"), unsavedFiles, project);
+ unsavedFiles.createOrUpdate({unsavedDataFileContainer(TESTDATA_DIR"/complete_extractor_function.cpp",
+ TESTDATA_DIR"/complete_extractor_function_unsaved.cpp")});
+ ClangCodeCompleteResults completeResults(getResults(translationUnit, 20));
+ unsavedFiles.createOrUpdate({unsavedDataFileContainer(TESTDATA_DIR"/complete_extractor_function.cpp",
+ TESTDATA_DIR"/complete_extractor_function_unsaved_2.cpp")});
+ completeResults = getResults(translationUnit, 20);
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("Method3"),
+ CodeCompletion::FunctionCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, ArgumentDefinition)
+{
+ variableTranslationUnit.cxTranslationUnit();
+ project.setArguments({Utf8StringLiteral("-DArgumentDefinition")});
+ ClangCodeCompleteResults completeResults(getResults(variableTranslationUnit, 35));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletion(Utf8StringLiteral("ArgumentDefinitionVariable"),
+ CodeCompletion::VariableCompletionKind,
+ CodeCompletion::Available));
+}
+
+TEST_F(CodeCompletionsExtractor, NoArgumentDefinition)
+{
+ variableTranslationUnit.cxTranslationUnit();
+ project.setArguments(Utf8StringVector());
+ ClangCodeCompleteResults completeResults(getResults(variableTranslationUnit, 35));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, Not(HasCompletion(Utf8StringLiteral("ArgumentDefinitionVariable"),
+ CodeCompletion::VariableCompletionKind,
+ CodeCompletion::Available)));
+}
+
+TEST_F(CodeCompletionsExtractor, CompletionChunksFunction)
+{
+ ClangCodeCompleteResults completeResults(getResults(functionTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletionChunks(Utf8StringLiteral("Function"),
+ QVector<CodeCompletionChunk>({{CodeCompletionChunk::ResultType, Utf8StringLiteral("void")},
+ {CodeCompletionChunk::TypedText, Utf8StringLiteral("Function")},
+ {CodeCompletionChunk::LeftParen, Utf8StringLiteral("(")},
+ {CodeCompletionChunk::RightParen, Utf8StringLiteral(")")}})));
+}
+
+TEST_F(CodeCompletionsExtractor, CompletionChunksFunctionWithOptionalChunks)
+{
+ ClangCodeCompleteResults completeResults(getResults(functionTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletionChunks(Utf8StringLiteral("FunctionWithOptional"),
+ QVector<CodeCompletionChunk>({{CodeCompletionChunk::ResultType, Utf8StringLiteral("void")},
+ {CodeCompletionChunk::TypedText, Utf8StringLiteral("FunctionWithOptional")},
+ {CodeCompletionChunk::LeftParen, Utf8StringLiteral("(")},
+ {CodeCompletionChunk::Placeholder, Utf8StringLiteral("int x")},
+ {CodeCompletionChunk::Optional, Utf8String(), QVector<CodeCompletionChunk>({
+ {CodeCompletionChunk::Comma, Utf8StringLiteral(", ")},
+ {CodeCompletionChunk::Placeholder, Utf8StringLiteral("char y")},
+ {CodeCompletionChunk::Comma, Utf8StringLiteral(", ")},
+ {CodeCompletionChunk::Placeholder, Utf8StringLiteral("int z")}})},
+ {CodeCompletionChunk::RightParen, Utf8StringLiteral(")")}})));
+}
+
+TEST_F(CodeCompletionsExtractor, CompletionChunksField)
+{
+ ClangCodeCompleteResults completeResults(getResults(variableTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletionChunks(Utf8StringLiteral("Field"),
+ QVector<CodeCompletionChunk>({{CodeCompletionChunk::ResultType, Utf8StringLiteral("int")},
+ {CodeCompletionChunk::TypedText, Utf8StringLiteral("Field")}})));
+}
+
+TEST_F(CodeCompletionsExtractor, CompletionChunksEnumerator)
+{
+ ClangCodeCompleteResults completeResults(getResults(enumerationTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletionChunks(Utf8StringLiteral("Enumerator"),
+ QVector<CodeCompletionChunk>({{CodeCompletionChunk::ResultType, Utf8StringLiteral("Enumeration")},
+ {CodeCompletionChunk::TypedText, Utf8StringLiteral("Enumerator")}})));
+}
+
+TEST_F(CodeCompletionsExtractor, CompletionChunksEnumeration)
+{
+ ClangCodeCompleteResults completeResults(getResults(enumerationTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletionChunks(Utf8StringLiteral("Enumeration"),
+ QVector<CodeCompletionChunk>({{CodeCompletionChunk::TypedText, Utf8StringLiteral("Enumeration")}})));
+}
+
+TEST_F(CodeCompletionsExtractor, CompletionChunksClass)
+{
+ ClangCodeCompleteResults completeResults(getResults(classTranslationUnit, 20));
+
+ ::CodeCompletionsExtractor extractor(completeResults.data());
+
+ ASSERT_THAT(extractor, HasCompletionChunks(Utf8StringLiteral("Class"),
+ QVector<CodeCompletionChunk>({{CodeCompletionChunk::TypedText, Utf8StringLiteral("Class")}})));
+}
+
+
+}
diff --git a/tests/unit/unittest/codecompletiontest.cpp b/tests/unit/unittest/codecompletiontest.cpp
new file mode 100644
index 0000000000..efb4551a0a
--- /dev/null
+++ b/tests/unit/unittest/codecompletiontest.cpp
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "gtest/gtest.h"
+#include "gmock/gmock-matchers.h"
+#include "gtest-qt-printing.h"
+
+#include <codecompleter.h>
+#include <filecontainer.h>
+#include <translationunit.h>
+#include <unsavedfiles.h>
+#include <utf8stringvector.h>
+#include <projectpart.h>
+
+#include <QFile>
+
+
+using ::testing::ElementsAreArray;
+using ::testing::Contains;
+using ::testing::AllOf;
+using ::testing::Not;
+
+using ClangBackEnd::CodeCompletion;
+using ClangBackEnd::CodeCompleter;
+
+namespace {
+
+class CodeCompleter : public ::testing::Test
+{
+public:
+ static void SetUpTestCase();
+ static void TearDownTestCase();
+
+protected:
+ static ClangBackEnd::ProjectPart projectPart;
+ static ClangBackEnd::UnsavedFiles unsavedFiles;
+ static ClangBackEnd::TranslationUnit translationUnit;
+ static ClangBackEnd::CodeCompleter completer;
+};
+
+ClangBackEnd::ProjectPart CodeCompleter::projectPart(Utf8StringLiteral("projectPartId"));
+ClangBackEnd::UnsavedFiles CodeCompleter::unsavedFiles;
+ClangBackEnd::TranslationUnit CodeCompleter::translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_completer.cpp"), unsavedFiles, projectPart);
+ClangBackEnd::CodeCompleter CodeCompleter::completer = translationUnit;
+
+void CodeCompleter::SetUpTestCase()
+{
+ QFile unsavedFileContentFile(QStringLiteral(TESTDATA_DIR) + QStringLiteral("/complete_completer_unsaved.cpp"));
+ unsavedFileContentFile.open(QIODevice::ReadOnly);
+
+ const Utf8String unsavedFileContent = Utf8String::fromByteArray(unsavedFileContentFile.readAll());
+ const ClangBackEnd::FileContainer unsavedDataFileContainer(translationUnit.filePath(),
+ projectPart.projectPartId(),
+ unsavedFileContent,
+ true);
+
+ unsavedFiles.createOrUpdate({unsavedDataFileContainer});
+}
+
+void CodeCompleter::TearDownTestCase()
+{
+ translationUnit.reset();
+ completer = ClangBackEnd::CodeCompleter();
+}
+
+
+TEST_F(CodeCompleter, FunctionInUnsavedFile)
+{
+ ASSERT_THAT(completer.complete(100, 1),
+ AllOf(Contains(CodeCompletion(Utf8StringLiteral("functionWithArguments"),
+ Utf8String(),
+ Utf8String(),
+ 0,
+ CodeCompletion::FunctionCompletionKind)),
+ Contains(CodeCompletion(Utf8StringLiteral("function"),
+ Utf8String(),
+ Utf8String(),
+ 0,
+ CodeCompletion::FunctionCompletionKind)),
+ Contains(CodeCompletion(Utf8StringLiteral("newFunction"),
+ Utf8String(),
+ Utf8String(),
+ 0,
+ CodeCompletion::FunctionCompletionKind)),
+ Contains(CodeCompletion(Utf8StringLiteral("f"),
+ Utf8String(),
+ Utf8String(),
+ 0,
+ CodeCompletion::FunctionCompletionKind)),
+ Not(Contains(CodeCompletion(Utf8StringLiteral("otherFunction"),
+ Utf8String(),
+ Utf8String(),
+ 0,
+ CodeCompletion::FunctionCompletionKind)))));
+}
+
+
+TEST_F(CodeCompleter, Macro)
+{
+ ASSERT_THAT(completer.complete(100, 1),
+ Contains(CodeCompletion(Utf8StringLiteral("Macro"),
+ Utf8String(),
+ Utf8String(),
+ 0,
+ CodeCompletion::PreProcessorCompletionKind)));
+}
+
+TEST_F(CodeCompleter, Keyword)
+{
+ ASSERT_THAT(completer.complete(100, 1),
+ Contains(CodeCompletion(Utf8StringLiteral("switch"),
+ Utf8String(),
+ Utf8String(),
+ 0,
+ CodeCompletion::KeywordCompletionKind)));
+}
+
+
+}
+
+
diff --git a/tests/unit/unittest/completionchunkstotextconvertertest.cpp b/tests/unit/unittest/completionchunkstotextconvertertest.cpp
new file mode 100644
index 0000000000..c5c7f596e9
--- /dev/null
+++ b/tests/unit/unittest/completionchunkstotextconvertertest.cpp
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+
+#include "gtest/gtest.h"
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock-generated-matchers.h"
+#include "gtest-qt-printing.h"
+
+#include <codecompletionchunk.h>
+#include <completionchunkstotextconverter.h>
+
+namespace {
+
+using ClangBackEnd::CodeCompletionChunk;
+
+class CompletionChunksToTextConverter : public ::testing::Test
+{
+protected:
+ ClangCodeModel::Internal::CompletionChunksToTextConverter converter;
+ CodeCompletionChunk integerResultType{CodeCompletionChunk::ResultType, Utf8StringLiteral("int")};
+ CodeCompletionChunk enumerationResultType{CodeCompletionChunk::ResultType, Utf8StringLiteral("Enumeration")};
+ CodeCompletionChunk functionName{CodeCompletionChunk::TypedText, Utf8StringLiteral("Function")};
+ CodeCompletionChunk variableName{CodeCompletionChunk::TypedText, Utf8StringLiteral("Variable")};
+ CodeCompletionChunk enumeratorName{CodeCompletionChunk::TypedText, Utf8StringLiteral("Enumerator")};
+ CodeCompletionChunk enumerationName{CodeCompletionChunk::TypedText, Utf8StringLiteral("Enumeration")};
+ CodeCompletionChunk className{CodeCompletionChunk::TypedText, Utf8StringLiteral("Class")};
+ CodeCompletionChunk leftParen{CodeCompletionChunk::LeftParen, Utf8StringLiteral("(")};
+ CodeCompletionChunk rightParen{CodeCompletionChunk::LeftParen, Utf8StringLiteral(")")};
+ CodeCompletionChunk comma{CodeCompletionChunk::Comma, Utf8StringLiteral(", ")};
+ CodeCompletionChunk functionArgumentX{CodeCompletionChunk::Placeholder, Utf8StringLiteral("char x")};
+ CodeCompletionChunk functionArgumentY{CodeCompletionChunk::Placeholder, Utf8StringLiteral("int y")};
+ CodeCompletionChunk functionArgumentZ{CodeCompletionChunk::Placeholder, Utf8StringLiteral("int z")};
+ CodeCompletionChunk optional{CodeCompletionChunk::Optional, Utf8String(), {comma, functionArgumentY, comma, functionArgumentZ}};
+};
+
+TEST_F(CompletionChunksToTextConverter, ParseIsClearingText)
+{
+ QVector<CodeCompletionChunk> completionChunks({integerResultType, functionName, leftParen, rightParen});
+ converter.parseChunks(completionChunks);
+
+ converter.parseChunks(completionChunks);
+
+ ASSERT_THAT(converter.text(), QStringLiteral("int Function()"));
+}
+
+TEST_F(CompletionChunksToTextConverter, ConvertFunction)
+{
+ QVector<CodeCompletionChunk> completionChunks({integerResultType, functionName, leftParen, rightParen});
+
+ converter.parseChunks(completionChunks);
+
+ ASSERT_THAT(converter.text(), QStringLiteral("int Function()"));
+}
+
+TEST_F(CompletionChunksToTextConverter, ConvertFunctionWithParameters)
+{
+ QVector<CodeCompletionChunk> completionChunks({integerResultType, functionName, leftParen, functionArgumentX,rightParen});
+
+ converter.parseChunks(completionChunks);
+
+ ASSERT_THAT(converter.text(), QStringLiteral("int Function(char x)"));
+}
+
+TEST_F(CompletionChunksToTextConverter, ConvertFunctionWithOptionalParameter)
+{
+ QVector<CodeCompletionChunk> completionChunks({integerResultType, functionName, leftParen, functionArgumentX, optional,rightParen});
+
+ converter.parseChunks(completionChunks);
+
+ ASSERT_THAT(converter.text(), QStringLiteral("int Function(char x<i>, int y, int z</i>)"));
+}
+
+TEST_F(CompletionChunksToTextConverter, ConvertVariable)
+{
+ QVector<CodeCompletionChunk> completionChunks({integerResultType, variableName});
+
+ converter.parseChunks(completionChunks);
+
+ ASSERT_THAT(converter.text(), QStringLiteral("int Variable"));
+}
+
+TEST_F(CompletionChunksToTextConverter, Enumerator)
+{
+ QVector<CodeCompletionChunk> completionChunks({enumerationResultType, enumeratorName});
+
+ converter.parseChunks(completionChunks);
+
+ ASSERT_THAT(converter.text(), QStringLiteral("Enumeration Enumerator"));
+}
+
+TEST_F(CompletionChunksToTextConverter, Enumeration)
+{
+ QVector<CodeCompletionChunk> completionChunks({className});
+
+ converter.parseChunks(completionChunks);
+
+ ASSERT_THAT(converter.text(), QStringLiteral("Class"));
+}
+
+}
diff --git a/tests/unit/unittest/createtablesqlstatementbuildertest.cpp b/tests/unit/unittest/createtablesqlstatementbuildertest.cpp
new file mode 100644
index 0000000000..87dbb84189
--- /dev/null
+++ b/tests/unit/unittest/createtablesqlstatementbuildertest.cpp
@@ -0,0 +1,189 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "gtest/gtest.h"
+#include "gmock/gmock-matchers.h"
+#include "gtest-qt-printing.h"
+
+#include <QString>
+
+#include <createtablesqlstatementbuilder.h>
+#include <sqlstatementbuilderexception.h>
+
+#include <utf8stringvector.h>
+
+class CreateTableSqlStatementBuilder : public ::testing::Test
+{
+protected:
+ void SetUp() override;
+
+ void bindValues();
+ static const QVector<Internal::ColumnDefinition> createColumnDefintions();
+ static const Internal::ColumnDefinition createColumnDefintion(const Utf8String &name,
+ ColumnType type,
+ bool isPrimaryKey = false);
+
+ Internal::CreateTableSqlStatementBuilder builder;
+};
+
+TEST_F(CreateTableSqlStatementBuilder, IsNotValidAfterCreation)
+{
+ ASSERT_FALSE(builder.isValid());
+}
+
+TEST_F(CreateTableSqlStatementBuilder, IsValidAfterBinding)
+{
+ bindValues();
+
+ ASSERT_TRUE(builder.isValid());
+}
+
+TEST_F(CreateTableSqlStatementBuilder, InvalidAfterClear)
+{
+ bindValues();
+
+ builder.clear();
+
+ ASSERT_TRUE(!builder.isValid());
+}
+
+TEST_F(CreateTableSqlStatementBuilder, NoSqlStatementAfterClear)
+{
+ bindValues();
+ builder.sqlStatement();
+
+ builder.clear();
+
+ ASSERT_THROW(builder.sqlStatement(), SqlStatementBuilderException);
+}
+
+TEST_F(CreateTableSqlStatementBuilder, SqlStatement)
+{
+ bindValues();
+
+ ASSERT_THAT(builder.sqlStatement(),
+ Utf8StringLiteral("CREATE TABLE IF NOT EXISTS test(id INTEGER PRIMARY KEY, name TEXT, number NUMERIC)"));}
+
+TEST_F(CreateTableSqlStatementBuilder, AddColumnToExistingColumns)
+{
+ bindValues();
+
+ builder.addColumnDefinition(Utf8StringLiteral("number2"), ColumnType::Real);
+
+ ASSERT_THAT(builder.sqlStatement(),
+ Utf8StringLiteral("CREATE TABLE IF NOT EXISTS test(id INTEGER PRIMARY KEY, name TEXT, number NUMERIC, number2 REAL)"));}
+
+TEST_F(CreateTableSqlStatementBuilder, ChangeTable)
+{
+ bindValues();
+
+ builder.setTable(Utf8StringLiteral("test2"));
+
+ ASSERT_THAT(builder.sqlStatement(),
+ Utf8StringLiteral("CREATE TABLE IF NOT EXISTS test2(id INTEGER PRIMARY KEY, name TEXT, number NUMERIC)"));
+}
+
+TEST_F(CreateTableSqlStatementBuilder, IsInvalidAfterClearColumsOnly)
+{
+ bindValues();
+ builder.sqlStatement();
+
+ builder.clearColumns();
+
+ ASSERT_THROW(builder.sqlStatement(), SqlStatementBuilderException);
+}
+
+TEST_F(CreateTableSqlStatementBuilder, ClearColumnsAndAddColumnNewColumns)
+{
+ bindValues();
+ builder.clearColumns();
+
+ builder.addColumnDefinition(Utf8StringLiteral("name3"), ColumnType::Text);
+ builder.addColumnDefinition(Utf8StringLiteral("number3"), ColumnType::Real);
+
+ ASSERT_THAT(builder.sqlStatement(),
+ Utf8StringLiteral("CREATE TABLE IF NOT EXISTS test(name3 TEXT, number3 REAL)"));
+}
+
+TEST_F(CreateTableSqlStatementBuilder, SetWitoutRowId)
+{
+ bindValues();
+
+ builder.setUseWithoutRowId(true);
+
+ ASSERT_THAT(builder.sqlStatement(),
+ Utf8StringLiteral("CREATE TABLE IF NOT EXISTS test(id INTEGER PRIMARY KEY, name TEXT, number NUMERIC) WITHOUT ROWID"));
+}
+
+TEST_F(CreateTableSqlStatementBuilder, SetColumnDefinitions)
+{
+ builder.clear();
+ builder.setTable(Utf8StringLiteral("test"));
+
+ builder.setColumnDefinitions(createColumnDefintions());
+
+ ASSERT_THAT(builder.sqlStatement(),
+ Utf8StringLiteral("CREATE TABLE IF NOT EXISTS test(id INTEGER PRIMARY KEY, name TEXT, number NUMERIC)"));
+}
+
+void CreateTableSqlStatementBuilder::SetUp()
+{
+ builder = Internal::CreateTableSqlStatementBuilder();
+}
+
+void CreateTableSqlStatementBuilder::bindValues()
+{
+ builder.clear();
+ builder.setTable(Utf8StringLiteral("test"));
+ builder.addColumnDefinition(Utf8StringLiteral("id"), ColumnType::Integer, true);
+ builder.addColumnDefinition(Utf8StringLiteral("name"), ColumnType::Text);
+ builder.addColumnDefinition(Utf8StringLiteral("number"),ColumnType:: Numeric);
+}
+
+const QVector<Internal::ColumnDefinition> CreateTableSqlStatementBuilder::createColumnDefintions()
+{
+ QVector<Internal::ColumnDefinition> columnDefinitions;
+ columnDefinitions.append(createColumnDefintion(Utf8StringLiteral("id"), ColumnType::Integer, true));
+ columnDefinitions.append(createColumnDefintion(Utf8StringLiteral("name"), ColumnType::Text));
+ columnDefinitions.append(createColumnDefintion(Utf8StringLiteral("number"), ColumnType::Numeric));
+
+ return columnDefinitions;
+}
+
+const Internal::ColumnDefinition CreateTableSqlStatementBuilder::createColumnDefintion(const Utf8String &name, ColumnType type, bool isPrimaryKey)
+{
+ Internal::ColumnDefinition columnDefinition;
+
+ columnDefinition.setName(name);
+ columnDefinition.setType(type);
+ columnDefinition.setIsPrimaryKey(isPrimaryKey);
+
+ return columnDefinition;
+}
diff --git a/tests/unit/unittest/data/complete_completer.cpp b/tests/unit/unittest/data/complete_completer.cpp
new file mode 100644
index 0000000000..a764b7adb4
--- /dev/null
+++ b/tests/unit/unittest/data/complete_completer.cpp
@@ -0,0 +1,101 @@
+void function()
+{
+
+}
+
+class Foo;
+void functionWithArguments(int i, char *c, const Foo &ref)
+{
+
+}
+
+void otherFunction()
+{
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void f()
+{
+
+}
diff --git a/tests/unit/unittest/data/complete_completer_unsaved.cpp b/tests/unit/unittest/data/complete_completer_unsaved.cpp
new file mode 100644
index 0000000000..9ec3fed8f4
--- /dev/null
+++ b/tests/unit/unittest/data/complete_completer_unsaved.cpp
@@ -0,0 +1,100 @@
+void function()
+{
+
+}
+
+class Foo;
+void functionWithArguments(int i, char *c, const Foo &ref)
+{
+
+}
+
+void newFunction()
+{
+
+}
+
+#define Macro
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void f()
+{
+
+}
diff --git a/tests/unit/unittest/data/complete_extractor_class.cpp b/tests/unit/unittest/data/complete_extractor_class.cpp
new file mode 100644
index 0000000000..becfdc3292
--- /dev/null
+++ b/tests/unit/unittest/data/complete_extractor_class.cpp
@@ -0,0 +1,21 @@
+class Class {};
+struct Struct{};
+union Union{};
+typedef Class TypeDef;
+template<class T> class TemplateClass{};
+template<class T> class ClassTemplatePartialSpecialization;
+template<class T> class ClassTemplatePartialSpecialization<T*>;
+
+
+
+
+
+
+
+
+
+template<class TemplateTypeParameter, template<class> class TemplateTemplateParameter>
+void function()
+{
+
+}
diff --git a/tests/unit/unittest/data/complete_extractor_constructor.cpp b/tests/unit/unittest/data/complete_extractor_constructor.cpp
new file mode 100644
index 0000000000..e28ccaea82
--- /dev/null
+++ b/tests/unit/unittest/data/complete_extractor_constructor.cpp
@@ -0,0 +1,22 @@
+class Constructor {
+ Constructor();
+ ~Constructor();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ void function()
+ {
+
+ }
+};
diff --git a/tests/unit/unittest/data/complete_extractor_enumeration.cpp b/tests/unit/unittest/data/complete_extractor_enumeration.cpp
new file mode 100644
index 0000000000..79973a616b
--- /dev/null
+++ b/tests/unit/unittest/data/complete_extractor_enumeration.cpp
@@ -0,0 +1,22 @@
+enum Enumeration {
+ Enumerator
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void function()
+{
+
+}
+
diff --git a/tests/unit/unittest/data/complete_extractor_function.cpp b/tests/unit/unittest/data/complete_extractor_function.cpp
new file mode 100644
index 0000000000..a4d34fb04a
--- /dev/null
+++ b/tests/unit/unittest/data/complete_extractor_function.cpp
@@ -0,0 +1,22 @@
+void Function();
+template<class T> void TemplateFunction();
+void FunctionWithOptional(int x, char y = 1, int z = 5);
+#define FunctionMacro(X, Y) X + Y
+
+class base {
+ void NotAccessibleFunction();
+};
+class Class : public base {
+ void Method();
+ void MethodWithParameters(int x = 30);
+ __attribute__((annotate("qt_slot"))) void Slot();
+ __attribute__((annotate("qt_signal"))) void Signal();
+ __attribute__ ((deprecated)) void DeprecatedFunction();
+ void NotAvailableFunction() = delete;
+
+public:
+ void function()
+ {
+
+ }
+};
diff --git a/tests/unit/unittest/data/complete_extractor_function_unsaved.cpp b/tests/unit/unittest/data/complete_extractor_function_unsaved.cpp
new file mode 100644
index 0000000000..adab53527b
--- /dev/null
+++ b/tests/unit/unittest/data/complete_extractor_function_unsaved.cpp
@@ -0,0 +1,22 @@
+void Function();
+template<class T> void TemplateFunction();
+
+#define FunctionMacro(X, Y) X + Y
+
+class base {
+ void NotAccessibleFunction();
+};
+class Class : public base {
+ void Method2();
+ void MethodWithParameters(int x = 30);
+ __attribute__((annotate("qt_slot"))) void Slot();
+ __attribute__((annotate("qt_signal"))) void Signal();
+ __attribute__ ((deprecated)) void DeprecatedFunction();
+ void NotAvailableFunction() = delete;
+
+public:
+ void function()
+ {
+
+ }
+};
diff --git a/tests/unit/unittest/data/complete_extractor_function_unsaved_2.cpp b/tests/unit/unittest/data/complete_extractor_function_unsaved_2.cpp
new file mode 100644
index 0000000000..08153184f4
--- /dev/null
+++ b/tests/unit/unittest/data/complete_extractor_function_unsaved_2.cpp
@@ -0,0 +1,22 @@
+void Function();
+template<class T> void TemplateFunction();
+
+#define FunctionMacro(X, Y) X + Y
+
+class base {
+ void NotAccessibleFunction();
+};
+class Class : public base {
+ void Method3();
+ void MethodWithParameters(int x = 30);
+ __attribute__((annotate("qt_slot"))) void Slot();
+ __attribute__((annotate("qt_signal"))) void Signal();
+ __attribute__ ((deprecated)) void DeprecatedFunction();
+ void NotAvailableFunction() = delete;
+
+public:
+ void function()
+ {
+
+ }
+};
diff --git a/tests/unit/unittest/data/complete_extractor_namespace.cpp b/tests/unit/unittest/data/complete_extractor_namespace.cpp
new file mode 100644
index 0000000000..46d273da9d
--- /dev/null
+++ b/tests/unit/unittest/data/complete_extractor_namespace.cpp
@@ -0,0 +1,22 @@
+namespace Namespace {}
+namespace NamespaceAlias = Namespace;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void function()
+{
+
+}
+
diff --git a/tests/unit/unittest/data/complete_extractor_variable.cpp b/tests/unit/unittest/data/complete_extractor_variable.cpp
new file mode 100644
index 0000000000..e8a67f9c6c
--- /dev/null
+++ b/tests/unit/unittest/data/complete_extractor_variable.cpp
@@ -0,0 +1,36 @@
+void function(int Parameter)
+{
+ int Var = 0;
+
+}
+
+void function2()
+{
+ int Var = 0;
+ auto Lambda = [&Var]()
+ {
+
+ };
+}
+
+class Class {
+ int Field;
+
+ void function() {
+
+ }
+};
+
+template <int NonTypeTemplateParameter>
+void function3() {}
+
+#define MacroDefinition
+
+
+void function4()
+{
+#ifdef ArgumentDefinition
+ int ArgumentDefinitionVariable;
+#endif
+
+}
diff --git a/tests/unit/unittest/data/complete_testfile_1.cpp b/tests/unit/unittest/data/complete_testfile_1.cpp
new file mode 100644
index 0000000000..7804bc5fd6
--- /dev/null
+++ b/tests/unit/unittest/data/complete_testfile_1.cpp
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+void function()
+{
+
+}
+
+class Foo;
+void functionWithArguments(int i, char *c, const Foo &ref)
+{
+
+}
+
+void otherFunction()
+{
+
+}
+
+void f()
+{
+
+}
diff --git a/tests/unit/unittest/data/complete_translationunit_parse_error.cpp b/tests/unit/unittest/data/complete_translationunit_parse_error.cpp
new file mode 100644
index 0000000000..288cef2a33
--- /dev/null
+++ b/tests/unit/unittest/data/complete_translationunit_parse_error.cpp
@@ -0,0 +1,2 @@
+NAMESPACE {
+
diff --git a/tests/unit/unittest/gtest-qt-printing.cpp b/tests/unit/unittest/gtest-qt-printing.cpp
new file mode 100644
index 0000000000..da82cd2595
--- /dev/null
+++ b/tests/unit/unittest/gtest-qt-printing.cpp
@@ -0,0 +1,31 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+//#include "gtest-qt-printing.h"
diff --git a/tests/unit/unittest/gtest-qt-printing.h b/tests/unit/unittest/gtest-qt-printing.h
new file mode 100644
index 0000000000..353efad9ea
--- /dev/null
+++ b/tests/unit/unittest/gtest-qt-printing.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include <QString>
+#include <QDebug>
+
+#include <iostream>
+
+#include <gtest/gtest-printers.h>
+
+#ifndef GTESTQTPRINTING_H
+#define GTESTQTPRINTING_H
+
+QT_BEGIN_NAMESPACE
+class QVariant;
+inline void PrintTo(const QVariant &variant, ::std::ostream *os)
+{
+ QString output;
+ QDebug debug(&output);
+
+ debug << variant;
+
+ *os << output.toUtf8().constData();
+}
+
+inline void PrintTo(const QString &text, ::std::ostream *os)
+{
+ *os << text.toUtf8().constData();
+}
+
+QT_END_NAMESPACE
+
+//namespace testing {
+//namespace internal {
+
+// void PrintTo(const QVariant &variant, ::std::ostream *os);
+
+//}
+//}
+#endif // GTESTQTPRINTING_H
+
diff --git a/tests/unit/unittest/main.cpp b/tests/unit/unittest/main.cpp
new file mode 100644
index 0000000000..a1b332e7d7
--- /dev/null
+++ b/tests/unit/unittest/main.cpp
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "gtest/gtest.h"
+
+#include <cmbcommands.h>
+#include <sqliteglobal.h>
+
+#include <QCoreApplication>
+
+int main(int argc, char *argv[])
+{
+ ClangBackEnd::Commands::registerCommands();
+ Sqlite::registerTypes();
+
+ QCoreApplication application(argc, argv);
+
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/tests/unit/unittest/mockipclient.h b/tests/unit/unittest/mockipclient.h
new file mode 100644
index 0000000000..9a09a06cc2
--- /dev/null
+++ b/tests/unit/unittest/mockipclient.h
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef MOCKIPCLIENT_H
+#define MOCKIPCLIENT_H
+
+#include <ipcclientinterface.h>
+
+
+class MockIpcClient : public ClangBackEnd::IpcClientInterface {
+ public:
+ MOCK_METHOD0(alive,
+ void());
+ MOCK_METHOD1(echo,
+ void(const ClangBackEnd::EchoCommand &command));
+ MOCK_METHOD1(codeCompleted,
+ void(const ClangBackEnd::CodeCompletedCommand &command));
+ MOCK_METHOD1(translationUnitDoesNotExist,
+ void(const ClangBackEnd::TranslationUnitDoesNotExistCommand &command));
+ MOCK_METHOD1(projectPartsDoNotExist,
+ void(const ClangBackEnd::ProjectPartsDoNotExistCommand &command));
+};
+
+#endif // MOCKIPCLIENT_H
+
diff --git a/tests/unit/unittest/mockipcserver.h b/tests/unit/unittest/mockipcserver.h
new file mode 100644
index 0000000000..276ee1aa8a
--- /dev/null
+++ b/tests/unit/unittest/mockipcserver.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef MOCKIPCSERVER_H
+#define MOCKIPCSERVER_H
+
+#include <ipcserverinterface.h>
+
+class MockIpcServer : public ClangBackEnd::IpcServerInterface {
+ public:
+ MOCK_METHOD0(end,
+ void());
+ MOCK_METHOD1(registerTranslationUnitsForCodeCompletion,
+ void(const ClangBackEnd::RegisterTranslationUnitForCodeCompletionCommand &command));
+ MOCK_METHOD1(unregisterTranslationUnitsForCodeCompletion,
+ void(const ClangBackEnd::UnregisterTranslationUnitsForCodeCompletionCommand &command));
+ MOCK_METHOD1(registerProjectPartsForCodeCompletion,
+ void(const ClangBackEnd::RegisterProjectPartsForCodeCompletionCommand &command));
+ MOCK_METHOD1(unregisterProjectPartsForCodeCompletion,
+ void(const ClangBackEnd::UnregisterProjectPartsForCodeCompletionCommand &command));
+ MOCK_METHOD1(completeCode,
+ void(const ClangBackEnd::CompleteCodeCommand &command));
+};
+
+#endif // MOCKIPCSERVER_H
+
diff --git a/tests/unit/unittest/projecttest.cpp b/tests/unit/unittest/projecttest.cpp
new file mode 100644
index 0000000000..daab4e8816
--- /dev/null
+++ b/tests/unit/unittest/projecttest.cpp
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "gtest/gtest.h"
+
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock-generated-matchers.h"
+#include "gtest-qt-printing.h"
+
+#include <projectpart.h>
+#include <utf8stringvector.h>
+#include <projects.h>
+#include <projectpartsdonotexistexception.h>
+
+#include <chrono>
+#include <thread>
+
+using testing::ElementsAre;
+using testing::StrEq;
+using testing::Pointwise;
+using testing::Contains;
+using testing::Gt;
+using testing::Not;
+
+namespace {
+
+TEST(ProjectPart, CreateProjectPart)
+{
+ Utf8String projectPath(Utf8StringLiteral("/tmp/blah.pro"));
+
+ ClangBackEnd::ProjectPart project(projectPath);
+
+ ASSERT_THAT(project.projectPartId(), projectPath);
+}
+
+TEST(ProjectPart, CreateProjectPartWithProjectPartContainer)
+{
+ ClangBackEnd::ProjectPartContainer projectContainer(Utf8StringLiteral("pathToProjectPart.pro"), {Utf8StringLiteral("-O")});
+
+ ClangBackEnd::ProjectPart project(projectContainer);
+
+ ASSERT_THAT(project.projectPartId(), Utf8StringLiteral("pathToProjectPart.pro"));
+ ASSERT_THAT(project.arguments(), Contains(StrEq("-O")));
+}
+
+TEST(ProjectPart, SetArguments)
+{
+ ClangBackEnd::ProjectPart project(Utf8StringLiteral("/tmp/blah.pro"));
+
+ project.setArguments(Utf8StringVector({Utf8StringLiteral("-O"), Utf8StringLiteral("-fast")}));
+
+ ASSERT_THAT(project.arguments(), ElementsAre(StrEq("-O"), StrEq("-fast")));
+}
+
+TEST(ProjectPart, ArgumentCount)
+{
+ ClangBackEnd::ProjectPart project(Utf8StringLiteral("/tmp/blah.pro"));
+
+ project.setArguments(Utf8StringVector({Utf8StringLiteral("-O"), Utf8StringLiteral("-fast")}));
+
+ ASSERT_THAT(project.argumentCount(), 2);
+}
+
+TEST(ProjectPart, TimeStampIsUpdatedAsArgumentChanged)
+{
+ ClangBackEnd::ProjectPart project(Utf8StringLiteral("/tmp/blah.pro"));
+ auto lastChangeTimePoint = project.lastChangeTimePoint();
+ std::this_thread::sleep_for(std::chrono::steady_clock::duration(1));
+
+ project.setArguments(Utf8StringVector({Utf8StringLiteral("-O"), Utf8StringLiteral("-fast")}));
+
+ ASSERT_THAT(project.lastChangeTimePoint(), Gt(lastChangeTimePoint));
+
+}
+
+TEST(ProjectPart, GetNonExistingPoject)
+{
+ ClangBackEnd::ProjectParts projects;
+
+ ASSERT_THROW(projects.project(Utf8StringLiteral("pathToProjectPart.pro")), ClangBackEnd::ProjectPartDoNotExistException);
+}
+
+TEST(ProjectPart, AddProjectParts)
+{
+ ClangBackEnd::ProjectPartContainer projectContainer(Utf8StringLiteral("pathToProjectPart.pro"), {Utf8StringLiteral("-O")});
+ ClangBackEnd::ProjectParts projects;
+
+ projects.createOrUpdate({projectContainer});
+
+ ASSERT_THAT(projects.project(projectContainer.projectPartId()), ClangBackEnd::ProjectPart(projectContainer));
+ ASSERT_THAT(projects.project(projectContainer.projectPartId()).arguments(), ElementsAre(StrEq("-O")));
+}
+
+TEST(ProjectPart, UpdateProjectParts)
+{
+ ClangBackEnd::ProjectPartContainer projectContainer(Utf8StringLiteral("pathToProjectPart.pro"), {Utf8StringLiteral("-O")});
+ ClangBackEnd::ProjectPartContainer projectContainerWithNewArguments(Utf8StringLiteral("pathToProjectPart.pro"), {Utf8StringLiteral("-fast")});
+ ClangBackEnd::ProjectParts projects;
+ projects.createOrUpdate({projectContainer});
+
+ projects.createOrUpdate({projectContainerWithNewArguments});
+
+ ASSERT_THAT(projects.project(projectContainer.projectPartId()), ClangBackEnd::ProjectPart(projectContainer));
+ ASSERT_THAT(projects.project(projectContainer.projectPartId()).arguments(), ElementsAre(StrEq("-fast")));
+}
+
+TEST(ProjectPart, ThrowExceptionForAccesingRemovedProjectParts)
+{
+ ClangBackEnd::ProjectPartContainer projectContainer(Utf8StringLiteral("pathToProjectPart.pro"), {Utf8StringLiteral("-O")});
+ ClangBackEnd::ProjectParts projects;
+ projects.createOrUpdate({projectContainer});
+
+ projects.remove({projectContainer.projectPartId()});
+
+ ASSERT_THROW(projects.project(projectContainer.projectPartId()), ClangBackEnd::ProjectPartDoNotExistException);
+}
+
+TEST(ProjectPart, ProjectPartProjectPartIdIsEmptyfterRemoving)
+{
+ ClangBackEnd::ProjectPartContainer projectContainer(Utf8StringLiteral("pathToProjectPart.pro"), {Utf8StringLiteral("-O")});
+ ClangBackEnd::ProjectParts projects;
+ projects.createOrUpdate({projectContainer});
+ ClangBackEnd::ProjectPart project(projects.project(projectContainer.projectPartId()));
+
+ projects.remove({projectContainer.projectPartId()});
+
+ ASSERT_TRUE(project.projectPartId().isEmpty());
+}
+
+TEST(Project, ThrowsForNotExistingProjectPartButRemovesAllExistingProject)
+{
+ ClangBackEnd::ProjectPartContainer projectContainer(Utf8StringLiteral("pathToProjectPart.pro"));
+ ClangBackEnd::ProjectParts projects;
+ projects.createOrUpdate({projectContainer});
+ ClangBackEnd::ProjectPart project = *projects.findProjectPart(Utf8StringLiteral("pathToProjectPart.pro"));
+
+ EXPECT_THROW(projects.remove({Utf8StringLiteral("doesnotexist.pro"), projectContainer.projectPartId()}), ClangBackEnd::ProjectPartDoNotExistException);
+
+ ASSERT_THAT(projects.projects(), Not(Contains(project)));
+}
+
+TEST(ProjectPart, HasProjectPart)
+{
+ ClangBackEnd::ProjectPartContainer projectContainer(Utf8StringLiteral("pathToProjectPart.pro"));
+ ClangBackEnd::ProjectParts projects;
+ projects.createOrUpdate({projectContainer});
+
+ ASSERT_TRUE(projects.hasProjectPart(projectContainer.projectPartId()));
+}
+
+TEST(ProjectPart, DoNotHasProjectPart)
+{
+ ClangBackEnd::ProjectPartContainer projectContainer(Utf8StringLiteral("pathToProjectPart.pro"));
+ ClangBackEnd::ProjectParts projects;
+ projects.createOrUpdate({projectContainer});
+
+ ASSERT_FALSE(projects.hasProjectPart(Utf8StringLiteral("doesnotexist.pro")));
+}
+
+
+}
diff --git a/tests/unit/unittest/readandwritecommandblocktest.cpp b/tests/unit/unittest/readandwritecommandblocktest.cpp
new file mode 100644
index 0000000000..d9de87b529
--- /dev/null
+++ b/tests/unit/unittest/readandwritecommandblocktest.cpp
@@ -0,0 +1,225 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "gtest/gtest.h"
+#include "gmock/gmock-matchers.h"
+#include "gtest-qt-printing.h"
+
+#include <QString>
+#include <QBuffer>
+#include <QVariant>
+#include <vector>
+
+#include <cmbendcommand.h>
+#include <cmbalivecommand.h>
+#include <cmbcommands.h>
+#include <cmbregistertranslationunitsforcodecompletioncommand.h>
+#include <cmbunregistertranslationunitsforcodecompletioncommand.h>
+#include <cmbcodecompletedcommand.h>
+#include <cmbcompletecodecommand.h>
+#include <writecommandblock.h>
+#include <readcommandblock.h>
+
+#include "gtest-qt-printing.h"
+
+using namespace testing;
+namespace CodeModelBackeEndTest {
+
+class ReadAndWriteCommandBlockTest : public ::testing::Test
+{
+protected:
+ ReadAndWriteCommandBlockTest();
+
+ virtual void SetUp() override;
+ virtual void TearDown() override;
+
+ template<class Type>
+ void CompareCommand(const Type &command);
+
+ QVariant writeCodeCompletedCommand();
+ void popLastCharacterFromBuffer();
+ void pushLastCharacterToBuffer();
+ void readPartialCommand();
+
+protected:
+ QBuffer buffer;
+ ClangBackEnd::WriteCommandBlock writeCommandBlock;
+ ClangBackEnd::ReadCommandBlock readCommandBlock;
+ char lastCharacter = 0;
+};
+
+ReadAndWriteCommandBlockTest::ReadAndWriteCommandBlockTest()
+ : writeCommandBlock(&buffer),
+ readCommandBlock(&buffer)
+{
+}
+
+void ReadAndWriteCommandBlockTest::SetUp()
+{
+ buffer.open(QIODevice::ReadWrite);
+ writeCommandBlock = ClangBackEnd::WriteCommandBlock(&buffer);
+ readCommandBlock = ClangBackEnd::ReadCommandBlock(&buffer);
+}
+
+void ReadAndWriteCommandBlockTest::TearDown()
+{
+ buffer.close();
+}
+
+TEST_F(ReadAndWriteCommandBlockTest, WriteCommandAndTestSize)
+{
+ writeCommandBlock.write(QVariant::fromValue(ClangBackEnd::EndCommand()));
+
+ ASSERT_EQ(46, buffer.size());
+}
+
+TEST_F(ReadAndWriteCommandBlockTest, WriteSecondCommandAndTestSize)
+{
+ writeCommandBlock.write(QVariant::fromValue(ClangBackEnd::EndCommand()));
+
+ ASSERT_EQ(46, buffer.size());
+}
+
+TEST_F(ReadAndWriteCommandBlockTest, WriteTwoCommandsAndTestCount)
+{
+ writeCommandBlock.write(QVariant::fromValue(ClangBackEnd::EndCommand()));
+ writeCommandBlock.write(QVariant::fromValue(ClangBackEnd::EndCommand()));
+
+ ASSERT_EQ(2, writeCommandBlock.counter());
+}
+
+TEST_F(ReadAndWriteCommandBlockTest, ReadThreeCommandsAndTestCount)
+{
+ writeCommandBlock.write(QVariant::fromValue(ClangBackEnd::EndCommand()));
+ writeCommandBlock.write(QVariant::fromValue(ClangBackEnd::EndCommand()));
+ writeCommandBlock.write(QVariant::fromValue(ClangBackEnd::EndCommand()));
+ buffer.seek(0);
+
+ ASSERT_EQ(3, readCommandBlock.readAll().count());
+}
+
+TEST_F(ReadAndWriteCommandBlockTest, CompareEndCommand)
+{
+ CompareCommand(ClangBackEnd::EndCommand());
+}
+
+TEST_F(ReadAndWriteCommandBlockTest, CompareAliveCommand)
+{
+ CompareCommand(ClangBackEnd::AliveCommand());
+}
+
+TEST_F(ReadAndWriteCommandBlockTest, CompareRegisterTranslationUnitForCodeCompletionCommand)
+{
+ ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral("foo.cpp"), Utf8StringLiteral("pathToProject.pro"));
+ QVector<ClangBackEnd::FileContainer> fileContainers({fileContainer});
+
+ CompareCommand(ClangBackEnd::RegisterTranslationUnitForCodeCompletionCommand(fileContainers));
+}
+
+TEST_F(ReadAndWriteCommandBlockTest, CompareUnregisterFileForCodeCompletionCommand)
+{
+ ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral("foo.cpp"), Utf8StringLiteral("pathToProject.pro"));
+
+ CompareCommand(ClangBackEnd::UnregisterTranslationUnitsForCodeCompletionCommand({fileContainer}));
+}
+
+TEST_F(ReadAndWriteCommandBlockTest, CompareCompleteCodeCommand)
+{
+ CompareCommand(ClangBackEnd::CompleteCodeCommand(Utf8StringLiteral("foo.cpp"), 24, 33, Utf8StringLiteral("do what I want")));
+}
+
+TEST_F(ReadAndWriteCommandBlockTest, CompareCodeCompletedCommand)
+{
+ QVector<ClangBackEnd::CodeCompletion> codeCompletions({Utf8StringLiteral("newFunction()")});
+
+ CompareCommand(ClangBackEnd::CodeCompletedCommand(codeCompletions, 1));
+}
+
+TEST_F(ReadAndWriteCommandBlockTest, GetInvalidCommandForAPartialBuffer)
+{
+ writeCodeCompletedCommand();
+ popLastCharacterFromBuffer();
+ buffer.seek(0);
+
+ readPartialCommand();
+}
+
+TEST_F(ReadAndWriteCommandBlockTest, ReadCommandAfterInterruption)
+{
+ const QVariant writeCommand = writeCodeCompletedCommand();
+ popLastCharacterFromBuffer();
+ buffer.seek(0);
+ readPartialCommand();
+ pushLastCharacterToBuffer();
+
+ ASSERT_EQ(readCommandBlock.read(), writeCommand);
+}
+
+QVariant ReadAndWriteCommandBlockTest::writeCodeCompletedCommand()
+{
+ ClangBackEnd::CodeCompletedCommand command(QVector<ClangBackEnd::CodeCompletion>({Utf8StringLiteral("newFunction()")}), 1);
+ const QVariant writeCommand = QVariant::fromValue(command);
+ writeCommandBlock.write(writeCommand);
+
+ return writeCommand;
+}
+
+void ReadAndWriteCommandBlockTest::popLastCharacterFromBuffer()
+{
+ auto &internalBuffer = buffer.buffer();
+ lastCharacter = internalBuffer.at(internalBuffer.size() - 1);
+ internalBuffer.chop(1);
+}
+
+void ReadAndWriteCommandBlockTest::pushLastCharacterToBuffer()
+{
+ buffer.buffer().push_back(lastCharacter);
+}
+
+void ReadAndWriteCommandBlockTest::readPartialCommand()
+{
+ QVariant readCommand = readCommandBlock.read();
+
+ ASSERT_FALSE(readCommand.isValid());
+}
+
+template<class Type>
+void ReadAndWriteCommandBlockTest::CompareCommand(const Type &command)
+{
+ const QVariant writeCommand = QVariant::fromValue(command);
+ writeCommandBlock.write(writeCommand);
+ buffer.seek(0);
+
+ const QVariant readCommand = readCommandBlock.read();
+
+ ASSERT_EQ(writeCommand, readCommand);
+}
+
+}
diff --git a/tests/unit/unittest/spydummy.cpp b/tests/unit/unittest/spydummy.cpp
new file mode 100644
index 0000000000..758c8b0762
--- /dev/null
+++ b/tests/unit/unittest/spydummy.cpp
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "spydummy.h"
+
+SpyDummy::SpyDummy(QObject *parent) : QObject(parent)
+{
+
+}
+
+SpyDummy::~SpyDummy()
+{
+
+}
+
diff --git a/tests/unit/unittest/spydummy.h b/tests/unit/unittest/spydummy.h
new file mode 100644
index 0000000000..6d17f49472
--- /dev/null
+++ b/tests/unit/unittest/spydummy.h
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef SPYDUMMY_H
+#define SPYDUMMY_H
+
+#include <QObject>
+
+class SpyDummy : public QObject
+{
+ Q_OBJECT
+public:
+ explicit SpyDummy(QObject *parent = 0);
+ ~SpyDummy();
+
+signals:
+ void tableIsReady();
+ void databaseIsOpened();
+ void databaseIsClosed();
+};
+
+#endif // SPYDUMMY_H
diff --git a/tests/unit/unittest/sqlitecolumntest.cpp b/tests/unit/unittest/sqlitecolumntest.cpp
new file mode 100644
index 0000000000..a716dc5f3d
--- /dev/null
+++ b/tests/unit/unittest/sqlitecolumntest.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+
+#include <gtest/gtest.h>
+#include <gmock/gmock-matchers.h>
+#include "gtest-qt-printing.h"
+
+#include <sqlitecolumn.h>
+
+namespace {
+
+class SqliteColumn : public ::testing::Test
+{
+protected:
+ void SetUp() override;
+
+ ::SqliteColumn column;
+};
+
+TEST_F(SqliteColumn, ChangeName)
+{
+ column.setName(Utf8StringLiteral("Claudia"));
+
+ ASSERT_THAT(column.name(), Utf8StringLiteral("Claudia"));
+}
+
+TEST_F(SqliteColumn, DefaultType)
+{
+ ASSERT_THAT(column.type(), ColumnType::Numeric);
+}
+
+TEST_F(SqliteColumn, ChangeType)
+{
+ column.setType(ColumnType::Text);
+
+ ASSERT_THAT(column.type(), ColumnType::Text);
+}
+
+TEST_F(SqliteColumn, DefaultPrimaryKey)
+{
+ ASSERT_FALSE(column.isPrimaryKey());
+}
+
+TEST_F(SqliteColumn, SetPrimaryKey)
+{
+ column.setIsPrimaryKey(true);
+
+ ASSERT_TRUE(column.isPrimaryKey());
+}
+
+TEST_F(SqliteColumn, GetColumnDefinition)
+{
+ column.setName(Utf8StringLiteral("Claudia"));
+
+ Internal::ColumnDefinition columnDefintion = column.columnDefintion();
+
+ ASSERT_THAT(columnDefintion.name(), Utf8StringLiteral("Claudia"));
+ ASSERT_THAT(columnDefintion.type(), ColumnType::Numeric);
+ ASSERT_FALSE(columnDefintion.isPrimaryKey());
+}
+
+void SqliteColumn::SetUp()
+{
+ column.clear();
+}
+
+}
diff --git a/tests/unit/unittest/sqlitedatabasebackendtest.cpp b/tests/unit/unittest/sqlitedatabasebackendtest.cpp
new file mode 100644
index 0000000000..c023d85268
--- /dev/null
+++ b/tests/unit/unittest/sqlitedatabasebackendtest.cpp
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "gtest/gtest.h"
+#include "gmock/gmock-matchers.h"
+#include "gtest-qt-printing.h"
+
+#include <QDir>
+
+#include "sqlitedatabasebackend.h"
+#include "sqliteexception.h"
+#include "sqlitewritestatement.h"
+
+namespace {
+
+class SqliteDatabaseBackend : public ::testing::Test
+{
+protected:
+ void SetUp() override;
+ void TearDown() override;
+
+ QString databaseFilePath = QDir::tempPath() + QStringLiteral("/SqliteDatabaseBackendTest.db");
+ ::SqliteDatabaseBackend databaseBackend;
+};
+
+TEST_F(SqliteDatabaseBackend, OpenAlreadyOpenDatabase)
+{
+ ASSERT_THROW(databaseBackend.open(databaseFilePath), SqliteException);
+}
+
+TEST_F(SqliteDatabaseBackend, CloseAlreadyClosedDatabase)
+{
+ databaseBackend.close();
+ ASSERT_THROW(databaseBackend.close(), SqliteException);
+}
+
+TEST_F(SqliteDatabaseBackend, OpenWithWrongPath)
+{
+ ASSERT_THROW(databaseBackend.open(QStringLiteral("/xxx/SqliteDatabaseBackendTest.db")), SqliteException);
+}
+
+TEST_F(SqliteDatabaseBackend, DefaultJournalMode)
+{
+ ASSERT_THAT(databaseBackend.journalMode(), JournalMode::Delete);
+}
+
+TEST_F(SqliteDatabaseBackend, WalJournalMode)
+{
+ databaseBackend.setJournalMode(JournalMode::Wal);
+
+ ASSERT_THAT(databaseBackend.journalMode(), JournalMode::Wal);
+}
+
+TEST_F(SqliteDatabaseBackend, TruncateJournalMode)
+{
+ databaseBackend.setJournalMode(JournalMode::Truncate);
+
+ ASSERT_THAT(databaseBackend.journalMode(), JournalMode::Truncate);
+}
+
+TEST_F(SqliteDatabaseBackend, MemoryJournalMode)
+{
+ databaseBackend.setJournalMode(JournalMode::Memory);
+
+ ASSERT_THAT(databaseBackend.journalMode(), JournalMode::Memory);
+}
+
+TEST_F(SqliteDatabaseBackend, PersistJournalMode)
+{
+ databaseBackend.setJournalMode(JournalMode::Persist);
+
+ ASSERT_THAT(databaseBackend.journalMode(), JournalMode::Persist);
+}
+
+TEST_F(SqliteDatabaseBackend, DefaultTextEncoding)
+{
+ ASSERT_THAT(databaseBackend.textEncoding(), Utf8);
+}
+
+TEST_F(SqliteDatabaseBackend, Utf16TextEncoding)
+{
+ databaseBackend.setTextEncoding(Utf16);
+
+ ASSERT_THAT(databaseBackend.textEncoding(), Utf16);
+}
+
+TEST_F(SqliteDatabaseBackend, Utf16beTextEncoding)
+{
+ databaseBackend.setTextEncoding(Utf16be);
+
+ ASSERT_THAT(databaseBackend.textEncoding(), Utf16be);
+}
+
+TEST_F(SqliteDatabaseBackend, Utf16leTextEncoding)
+{
+ databaseBackend.setTextEncoding(Utf16le);
+
+ ASSERT_THAT(databaseBackend.textEncoding(), Utf16le);
+}
+
+TEST_F(SqliteDatabaseBackend, Utf8TextEncoding)
+{
+ databaseBackend.setTextEncoding(Utf8);
+
+ ASSERT_THAT(databaseBackend.textEncoding(), Utf8);
+}
+
+TEST_F(SqliteDatabaseBackend, TextEncodingCannotBeChangedAfterTouchingDatabase)
+{
+ databaseBackend.setJournalMode(JournalMode::Memory);
+
+ SqliteWriteStatement::execute(Utf8StringLiteral("CREATE TABLE text(name, number)"));
+
+ ASSERT_THROW(databaseBackend.setTextEncoding(Utf16), SqliteException);
+}
+
+void SqliteDatabaseBackend::SetUp()
+{
+ QDir::temp().remove(QStringLiteral("SqliteDatabaseBackendTest.db"));
+ databaseBackend.open(databaseFilePath);
+}
+
+void SqliteDatabaseBackend::TearDown()
+{
+ databaseBackend.closeWithoutException();
+}
+}
diff --git a/tests/unit/unittest/sqlitedatabasetest.cpp b/tests/unit/unittest/sqlitedatabasetest.cpp
new file mode 100644
index 0000000000..b4c979fe17
--- /dev/null
+++ b/tests/unit/unittest/sqlitedatabasetest.cpp
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+
+#include "gtest/gtest.h"
+#include "gmock/gmock-matchers.h"
+#include "gtest-qt-printing.h"
+
+#include <QVariant>
+#include <QSignalSpy>
+
+#include <sqlitedatabase.h>
+#include <sqlitetable.h>
+#include <utf8string.h>
+
+#include "spydummy.h"
+
+namespace {
+
+class SqliteDatabase : public ::testing::Test
+{
+protected:
+ void SetUp() override;
+ void TearDown() override;
+
+ SpyDummy spyDummy;
+ QString databaseFilePath = QStringLiteral(":memory:");
+ ::SqliteDatabase database;
+};
+
+TEST_F(SqliteDatabase, SetDatabaseFilePath)
+{
+ ASSERT_THAT(database.databaseFilePath(), databaseFilePath);
+}
+
+TEST_F(SqliteDatabase, SetJournalMode)
+{
+ database.setJournalMode(JournalMode::Memory);
+
+ ASSERT_THAT(database.journalMode(), JournalMode::Memory);
+}
+
+TEST_F(SqliteDatabase, OpenDatabase)
+{
+ database.close();
+ QSignalSpy signalSpy(&spyDummy, &SpyDummy::databaseIsOpened);
+ database.open();
+
+ ASSERT_TRUE(signalSpy.wait(100000));
+ ASSERT_TRUE(database.isOpen());
+}
+
+TEST_F(SqliteDatabase, CloseDatabase)
+{
+ QSignalSpy signalSpy(&spyDummy, &SpyDummy::databaseIsClosed);
+
+ database.close();
+
+ ASSERT_TRUE(signalSpy.wait(100000));
+ ASSERT_FALSE(database.isOpen());
+}
+
+TEST_F(SqliteDatabase, AddTable)
+{
+ SqliteTable *sqliteTable = new SqliteTable;
+
+ database.addTable(sqliteTable);
+
+ ASSERT_THAT(database.tables().first(), sqliteTable);
+}
+
+void SqliteDatabase::SetUp()
+{
+ QObject::connect(&database, &::SqliteDatabase::databaseIsOpened, &spyDummy, &SpyDummy::databaseIsOpened);
+ QObject::connect(&database, &::SqliteDatabase::databaseIsClosed, &spyDummy, &SpyDummy::databaseIsClosed);
+
+ database.setJournalMode(JournalMode::Memory);
+ database.setDatabaseFilePath(databaseFilePath);
+}
+
+void SqliteDatabase::TearDown()
+{
+ database.close();
+}
+}
diff --git a/tests/unit/unittest/sqlitestatementtest.cpp b/tests/unit/unittest/sqlitestatementtest.cpp
new file mode 100644
index 0000000000..5e218168ee
--- /dev/null
+++ b/tests/unit/unittest/sqlitestatementtest.cpp
@@ -0,0 +1,570 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "gtest/gtest.h"
+#include "gmock/gmock-matchers.h"
+#include "gtest-qt-printing.h"
+
+#include <QDir>
+#include <QVariant>
+#include <QStringList>
+#include <QByteArray>
+#include <QMap>
+#include <QString>
+
+#include <sqlitereadwritestatement.h>
+#include <sqlitereadstatement.h>
+#include <sqlitewritestatement.h>
+#include <sqlitedatabasebackend.h>
+#include <utf8string.h>
+
+namespace {
+class SqliteStatement : public ::testing::Test
+{
+protected:
+ void SetUp() override;
+ void TearDown() override;
+
+ SqliteDatabaseBackend databaseBackend;
+};
+
+TEST_F(SqliteStatement, PrepareFailure)
+{
+ ASSERT_THROW(SqliteReadStatement(Utf8StringLiteral("blah blah blah")), SqliteException);
+ ASSERT_THROW(SqliteWriteStatement(Utf8StringLiteral("blah blah blah")), SqliteException);
+ ASSERT_THROW(SqliteReadStatement(Utf8StringLiteral("INSERT INTO test(name, number) VALUES (?, ?)")), SqliteException);
+ ASSERT_THROW(SqliteWriteStatement(Utf8StringLiteral("SELECT name, number FROM test '")), SqliteException);
+}
+
+TEST_F(SqliteStatement, CountRows)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT * FROM test"));
+ int nextCount = 0;
+ while (statement.next())
+ ++nextCount;
+
+ int sqlCount = SqliteReadStatement::toValue<int>(Utf8StringLiteral("SELECT count(*) FROM test"));
+
+ ASSERT_THAT(nextCount, sqlCount);
+}
+
+TEST_F(SqliteStatement, Value)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test ORDER BY name"));
+
+ statement.next();
+
+ ASSERT_THAT(statement.value<QVariant>(1).type(), QVariant::ByteArray);
+
+ statement.next();
+
+ ASSERT_THAT(statement.value<int>(0), 0);
+ ASSERT_THAT(statement.value<qint64>(0), 0);
+ ASSERT_THAT(statement.value<double>(0), 0.0);
+ ASSERT_THAT(statement.value<QString>(0), QStringLiteral("foo"));
+ ASSERT_THAT(statement.value<Utf8String>(0), Utf8StringLiteral("foo"));
+ ASSERT_THAT(statement.value<QVariant>(0), QVariant::fromValue(QStringLiteral("foo")));
+ ASSERT_THAT(statement.value<QVariant>(0).type(), QVariant::String);
+
+ ASSERT_THAT(statement.value<int>(1), 23);
+ ASSERT_THAT(statement.value<qint64>(1), 23);
+ ASSERT_THAT(statement.value<double>(1), 23.3);
+ ASSERT_THAT(statement.value<QString>(1), QStringLiteral("23.3"));
+ ASSERT_THAT(statement.value<Utf8String>(1), Utf8StringLiteral("23.3"));
+ ASSERT_THAT(statement.value<QVariant>(1), QVariant::fromValue(23.3));
+ ASSERT_THAT(statement.value<QVariant>(1).type(), QVariant::Double);
+
+ statement.next();
+
+ ASSERT_THAT(statement.value<QVariant>(1).type(), QVariant::LongLong);
+}
+
+TEST_F(SqliteStatement, ValueFailure)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test"));
+ ASSERT_THROW(statement.value<int>(0), SqliteException);
+
+ statement.reset();
+
+ while (statement.next()) {}
+ ASSERT_THROW(statement.value<int>(0), SqliteException);
+
+ statement.reset();
+
+ statement.next();
+ ASSERT_THROW(statement.value<int>(-1), SqliteException);
+ ASSERT_THROW(statement.value<int>(2), SqliteException);
+}
+
+TEST_F(SqliteStatement, ToIntergerValue)
+{
+ ASSERT_THAT(SqliteReadStatement::toValue<int>(Utf8StringLiteral("SELECT number FROM test WHERE name='foo'")), 23);
+}
+
+TEST_F(SqliteStatement, ToLongIntergerValue)
+{
+ ASSERT_THAT(SqliteReadStatement::toValue<qint64>(Utf8StringLiteral("SELECT number FROM test WHERE name='foo'")), 23LL);
+}
+
+TEST_F(SqliteStatement, ToDoubleValue)
+{
+ ASSERT_THAT(SqliteReadStatement::toValue<double>(Utf8StringLiteral("SELECT number FROM test WHERE name='foo'")), 23.3);
+}
+
+TEST_F(SqliteStatement, ToQStringValue)
+{
+ ASSERT_THAT(SqliteReadStatement::toValue<QString>(Utf8StringLiteral("SELECT name FROM test WHERE name='foo'")), QStringLiteral("foo"));
+}
+
+TEST_F(SqliteStatement, ToUtf8StringValue)
+{
+ ASSERT_THAT(SqliteReadStatement::toValue<Utf8String>(Utf8StringLiteral("SELECT name FROM test WHERE name='foo'")), Utf8StringLiteral("foo"));
+}
+
+TEST_F(SqliteStatement, ToQByteArrayValueIsNull)
+{
+ ASSERT_TRUE(SqliteReadStatement::toValue<QByteArray>(Utf8StringLiteral("SELECT name FROM test WHERE name='foo'")).isNull());
+}
+
+TEST_F(SqliteStatement, ToQVariantValue)
+{
+ ASSERT_THAT(SqliteReadStatement::toValue<QVariant>(Utf8StringLiteral("SELECT name FROM test WHERE name='foo'")), QVariant::fromValue(QStringLiteral("foo")));
+}
+
+TEST_F(SqliteStatement, Utf8Values)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test ORDER by name"));
+
+ Utf8StringVector values = statement.values<Utf8StringVector>();
+ ASSERT_THAT(values.count(), 3);
+ ASSERT_THAT(values.at(0), Utf8StringLiteral("bar"));
+ ASSERT_THAT(values.at(1), Utf8StringLiteral("foo"));
+ ASSERT_THAT(values.at(2), Utf8StringLiteral("poo"));
+}
+TEST_F(SqliteStatement, DoubleValues)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test ORDER by name"));
+
+ QVector<double> values = statement.values<QVector<double>>(1);
+
+ ASSERT_THAT(values.count(), 3);
+ ASSERT_THAT(values.at(0), 0.0);
+ ASSERT_THAT(values.at(1), 23.3);
+ ASSERT_THAT(values.at(2), 40.0);
+}
+
+TEST_F(SqliteStatement, QVariantValues)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test ORDER by name"));
+
+ QVector<QVariant> values = statement.values<QVector<QVariant>>(QVector<int>() << 0 << 1);
+
+ ASSERT_THAT(values.count(), 6);
+ ASSERT_THAT(values.at(0), QVariant::fromValue(QStringLiteral("bar")));
+ ASSERT_THAT(values.at(1), QVariant::fromValue(QByteArray::fromHex("0500")));
+ ASSERT_THAT(values.at(2), QVariant::fromValue(QStringLiteral("foo")));
+ ASSERT_THAT(values.at(3), QVariant::fromValue(23.3));
+ ASSERT_THAT(values.at(4), QVariant::fromValue(QStringLiteral("poo")));
+ ASSERT_THAT(values.at(5), QVariant::fromValue(40));
+}
+
+TEST_F(SqliteStatement, RowColumnValueMapCountForValidRow)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test WHERE rowid=1"));
+
+ QMap<QString, QVariant> values = statement.rowColumnValueMap();
+
+ ASSERT_THAT(values.count(), 2);
+}
+
+TEST_F(SqliteStatement, RowColumnValueMapCountForInvalidRow)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test WHERE rowid=100"));
+
+ QMap<QString, QVariant> values = statement.rowColumnValueMap();
+
+ ASSERT_THAT(values.count(), 0);
+}
+
+TEST_F(SqliteStatement, RowColumnValueMapValues)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test WHERE rowid=2"));
+
+ QMap<QString, QVariant> values = statement.rowColumnValueMap();
+
+ ASSERT_THAT(values.value(QStringLiteral("name")).toString(), QStringLiteral("foo"));
+ ASSERT_THAT(values.value(QStringLiteral("number")).toDouble(), 23.3);
+}
+
+TEST_F(SqliteStatement, TwoColumnValueMapCount)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test"));
+
+ QMap<QString, QVariant> values = statement.twoColumnValueMap();
+
+ ASSERT_THAT(values.count(), 3);
+}
+
+TEST_F(SqliteStatement, TwoColumnValueMapValues)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test"));
+
+ QMap<QString, QVariant> values = statement.twoColumnValueMap();
+
+ ASSERT_THAT(values.value(QStringLiteral("foo")).toDouble(), 23.3);
+}
+
+TEST_F(SqliteStatement, ValuesFailure)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test"));
+
+ ASSERT_THROW(statement.values<QVector<QVariant>>(QVector<int>() << 1 << 2);, SqliteException);
+ ASSERT_THROW(statement.values<QVector<QVariant>>(QVector<int>() << -1 << 1);, SqliteException);
+}
+
+TEST_F(SqliteStatement, ColumnNames)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test"));
+
+ Utf8StringVector columnNames = statement.columnNames();
+
+ ASSERT_THAT(columnNames.count(), statement.columnCount());
+
+ ASSERT_THAT(columnNames.at(0), Utf8StringLiteral("name"));
+ ASSERT_THAT(columnNames.at(1), Utf8StringLiteral("number"));
+}
+
+TEST_F(SqliteStatement, BindQString)
+{
+
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test WHERE name=?"));
+
+ statement.bind(1, QStringLiteral("foo"));
+
+ statement.next();
+
+ ASSERT_THAT(statement.value<QString>(0), QStringLiteral("foo"));
+ ASSERT_THAT(statement.value<double>(1), 23.3);
+}
+
+TEST_F(SqliteStatement, BindInteger)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test WHERE number=?"));
+
+ statement.bind(1, 40);
+ statement.next();
+
+ ASSERT_THAT(statement.value<QString>(0), QStringLiteral("poo"));
+}
+
+TEST_F(SqliteStatement, BindLongInteger)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test WHERE number=?"));
+
+ statement.bind(1, qint64(40));
+ statement.next();
+
+ ASSERT_THAT(statement.value<QString>(0), QStringLiteral("poo"));
+}
+
+TEST_F(SqliteStatement, BindByteArray)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test WHERE number=?"));
+
+ statement.bind(1, QByteArray::fromHex("0500"));
+ statement.next();
+
+ ASSERT_THAT(statement.value<QString>(0), QStringLiteral("bar"));
+}
+
+TEST_F(SqliteStatement, BindDouble)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test WHERE number=?"));
+
+ statement.bind(1, 23.3);
+ statement.next();
+
+ ASSERT_THAT(statement.value<QString>(0), QStringLiteral("foo"));
+}
+
+TEST_F(SqliteStatement, BindIntergerQVariant)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test WHERE number=?"));
+
+ statement.bind(1, QVariant::fromValue(40));
+ statement.next();
+
+ ASSERT_THAT(statement.value<QString>(0), QStringLiteral("poo"));
+}
+
+TEST_F(SqliteStatement, BindLongIntergerQVariant)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test WHERE number=?"));
+
+ statement.bind(1, QVariant::fromValue(qint64(40)));
+ statement.next();
+ ASSERT_THAT(statement.value<QString>(0), QStringLiteral("poo"));
+}
+
+TEST_F(SqliteStatement, BindDoubleQVariant)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test WHERE number=?"));
+
+ statement.bind(1, QVariant::fromValue(23.3));
+ statement.next();
+
+ ASSERT_THAT(statement.value<QString>(0), QStringLiteral("foo"));
+ }
+
+TEST_F(SqliteStatement, BindByteArrayQVariant)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test WHERE number=?"));
+
+ statement.bind(1, QVariant::fromValue(QByteArray::fromHex("0500")));
+ statement.next();
+
+ ASSERT_THAT(statement.value<QString>(0), QStringLiteral("bar"));
+}
+
+TEST_F(SqliteStatement, BindIntegerByParameter)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test WHERE number=@number"));
+
+ statement.bind(Utf8StringLiteral("@number"), 40);
+ statement.next();
+
+ ASSERT_THAT(statement.value<QString>(0), QStringLiteral("poo"));
+}
+
+TEST_F(SqliteStatement, BindLongIntegerByParameter)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test WHERE number=@number"));
+
+ statement.bind(Utf8StringLiteral("@number"), qint64(40));
+ statement.next();
+
+ ASSERT_THAT(statement.value<QString>(0), QStringLiteral("poo"));
+}
+
+TEST_F(SqliteStatement, BindByteArrayByParameter)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test WHERE number=@number"));
+
+ statement.bind(Utf8StringLiteral("@number"), QByteArray::fromHex("0500"));
+ statement.next();
+
+ ASSERT_THAT(statement.value<QString>(0), QStringLiteral("bar"));
+}
+
+TEST_F(SqliteStatement, BindDoubleByIndex)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test WHERE number=@number"));
+
+ statement.bind(statement.bindingIndexForName(Utf8StringLiteral("@number")), 23.3);
+ statement.next();
+
+ ASSERT_THAT(statement.value<QString>(0), QStringLiteral("foo"));
+}
+
+TEST_F(SqliteStatement, BindQVariantByIndex)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test WHERE number=@number"));
+
+ statement.bind(statement.bindingIndexForName(Utf8StringLiteral("@number")), QVariant::fromValue((40)));
+ statement.next();
+
+ ASSERT_THAT(statement.value<QString>(0), QStringLiteral("poo"));
+
+}
+
+TEST_F(SqliteStatement, BindFailure)
+{
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test WHERE number=@number"));
+
+ ASSERT_THROW(statement.bind(0, 40), SqliteException);
+ ASSERT_THROW(statement.bind(2, 40), SqliteException);
+ ASSERT_THROW(statement.bind(Utf8StringLiteral("@name"), 40), SqliteException);
+}
+
+TEST_F(SqliteStatement, RequestBindingNamesFromStatement)
+{
+ Utf8StringVector expectedValues({Utf8StringLiteral("name"), Utf8StringLiteral("number"), Utf8StringLiteral("id")});
+
+ SqliteWriteStatement statement(Utf8StringLiteral("UPDATE test SET name=@name, number=@number WHERE rowid=@id"));
+
+ ASSERT_THAT(statement.bindingColumnNames(), expectedValues);
+}
+
+TEST_F(SqliteStatement, WriteUpdateWidthUnamedParameter)
+{
+ {
+ int startTotalCount = databaseBackend.totalChangesCount();
+ RowDictionary firstValueMap;
+ firstValueMap.insert(Utf8StringLiteral("name"), QStringLiteral("foo"));
+ firstValueMap.insert(Utf8StringLiteral("number"), 66.6);
+
+ RowDictionary secondValueMap;
+ secondValueMap.insert(Utf8StringLiteral("name"), QStringLiteral("bar"));
+ secondValueMap.insert(Utf8StringLiteral("number"), 77.7);
+
+ SqliteWriteStatement statement(Utf8StringLiteral("UPDATE test SET number=? WHERE name=?"));
+ statement.setBindingColumnNames(Utf8StringVector() << Utf8StringLiteral("number") << Utf8StringLiteral("name"));
+
+ statement.write(firstValueMap);
+
+ ASSERT_THAT(databaseBackend.totalChangesCount(), startTotalCount + 1);
+
+ statement.write(firstValueMap);
+
+ ASSERT_THAT(databaseBackend.totalChangesCount(), startTotalCount + 2);
+
+ statement.write(secondValueMap);
+
+ ASSERT_THAT(databaseBackend.totalChangesCount(), startTotalCount + 3);
+ }
+
+ {
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test WHERE name='foo'"));
+
+ statement.next();
+
+ ASSERT_THAT(statement.value<double>(1), 66.6);
+ }
+}
+
+TEST_F(SqliteStatement, WriteUpdateWidthNamedParameter)
+{
+ {
+ int startTotalCount = databaseBackend.totalChangesCount();
+ RowDictionary firstValueMap;
+ firstValueMap.insert(Utf8StringLiteral("name"), QStringLiteral("foo"));
+ firstValueMap.insert(Utf8StringLiteral("number"), 99.9);
+
+ SqliteWriteStatement statement(Utf8StringLiteral("UPDATE test SET number=@number WHERE name=@name"));
+ statement.write(firstValueMap);
+ ASSERT_THAT(databaseBackend.totalChangesCount(), startTotalCount + 1);
+ }
+
+ {
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test WHERE name='foo'"));
+ statement.next();
+ ASSERT_THAT(statement.value<double>(1), 99.9);
+ }
+}
+
+TEST_F(SqliteStatement, WriteUpdateWidthNamedParameterAndBindNotAllParameter)
+{
+ {
+ int startTotalCount = databaseBackend.totalChangesCount();
+ RowDictionary firstValueMap;
+ firstValueMap.insert(Utf8StringLiteral("name"), QStringLiteral("foo"));
+
+ SqliteWriteStatement statement(Utf8StringLiteral("UPDATE test SET number=@number WHERE name=@name"));
+ statement.writeUnchecked(firstValueMap);
+ ASSERT_THAT(databaseBackend.totalChangesCount(), startTotalCount + 1);
+ }
+
+ {
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test WHERE name='foo'"));
+ statement.next();
+ ASSERT_THAT(statement.value<double>(1), 0.0);
+ }
+}
+
+TEST_F(SqliteStatement, WriteInsert)
+{
+ {
+ int startTotalCount = databaseBackend.totalChangesCount();
+
+ RowDictionary valueMap;
+ valueMap.insert(Utf8StringLiteral("name"), QStringLiteral("jane"));
+ valueMap.insert(Utf8StringLiteral("number"), 232.3);
+
+ SqliteWriteStatement statement(Utf8StringLiteral("INSERT OR IGNORE INTO test(name, number) VALUES (?, ?)"));
+ statement.setBindingColumnNames(Utf8StringVector() << Utf8StringLiteral("name") << Utf8StringLiteral("number"));
+ statement.write(valueMap);
+ ASSERT_THAT(databaseBackend.totalChangesCount(), startTotalCount + 1);
+ statement.write(valueMap);
+ ASSERT_THAT(databaseBackend.totalChangesCount(), startTotalCount + 1);
+ }
+
+ {
+ SqliteReadStatement statement(Utf8StringLiteral("SELECT name, number FROM test WHERE name='jane'"));
+ statement.next();
+ ASSERT_THAT(statement.value<double>(1), 232.3);
+ }
+}
+
+TEST_F(SqliteStatement, WriteFailure)
+{
+ {
+ RowDictionary valueMap;
+ valueMap.insert(Utf8StringLiteral("name"), QStringLiteral("foo"));
+ valueMap.insert(Utf8StringLiteral("number"), 323.3);
+
+ SqliteWriteStatement statement(Utf8StringLiteral("INSERT INTO test(name, number) VALUES (?, ?)"));
+ statement.setBindingColumnNames(Utf8StringVector() << Utf8StringLiteral("name") << Utf8StringLiteral("number"));
+ ASSERT_THROW(statement.write(valueMap), SqliteException);
+ }
+
+ {
+ RowDictionary valueMap;
+ valueMap.insert(Utf8StringLiteral("name"), QStringLiteral("bar"));
+
+ SqliteWriteStatement statement(Utf8StringLiteral("INSERT OR IGNORE INTO test(name, number) VALUES (?, ?)"));
+ statement.setBindingColumnNames(Utf8StringVector() << Utf8StringLiteral("name") << Utf8StringLiteral("number"));
+ ASSERT_THROW(statement.write(valueMap), SqliteException);
+ }
+}
+
+TEST_F(SqliteStatement, ClosedDatabase)
+{
+ databaseBackend.close();
+ ASSERT_THROW(SqliteWriteStatement(Utf8StringLiteral("INSERT INTO test(name, number) VALUES (?, ?)")), SqliteException);
+ ASSERT_THROW(SqliteReadStatement(Utf8StringLiteral("SELECT * FROM test")), SqliteException);
+ ASSERT_THROW(SqliteReadWriteStatement(Utf8StringLiteral("INSERT INTO test(name, number) VALUES (?, ?)")), SqliteException);
+ databaseBackend.open(QDir::tempPath() + QStringLiteral("/SqliteStatementTest.db"));
+}
+
+void SqliteStatement::SetUp()
+{
+ databaseBackend.open(QStringLiteral(":memory:"));
+ SqliteWriteStatement::execute(Utf8StringLiteral("CREATE TABLE test(name TEXT UNIQUE, number NUMERIC)"));
+ SqliteWriteStatement::execute(Utf8StringLiteral("INSERT INTO test VALUES ('bar', x'0500')"));
+ SqliteWriteStatement::execute(Utf8StringLiteral("INSERT INTO test VALUES ('foo', 23.3)"));
+ SqliteWriteStatement::execute(Utf8StringLiteral("INSERT INTO test VALUES ('poo', 40)"));
+}
+
+void SqliteStatement::TearDown()
+{
+ databaseBackend.close();
+}
+
+}
diff --git a/tests/unit/unittest/sqlitetabletest.cpp b/tests/unit/unittest/sqlitetabletest.cpp
new file mode 100644
index 0000000000..fa5e671163
--- /dev/null
+++ b/tests/unit/unittest/sqlitetabletest.cpp
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "gtest/gtest.h"
+#include "gmock/gmock-matchers.h"
+#include "gtest-qt-printing.h"
+
+#include <QVariant>
+#include <QSignalSpy>
+
+#include <sqlitedatabase.h>
+#include <sqlitetable.h>
+#include <sqlitecolumn.h>
+#include <utf8string.h>
+
+#include "spydummy.h"
+
+namespace {
+
+class SqliteTable : public ::testing::Test
+{
+protected:
+ void SetUp() override;
+ void TearDown() override;
+
+ SqliteColumn *addColumn(const Utf8String &columnName);
+
+ SpyDummy spyDummy;
+ SqliteDatabase *database = nullptr;
+ ::SqliteTable *table = nullptr;
+ Utf8String tableName = Utf8StringLiteral("testTable");
+};
+
+
+TEST_F(SqliteTable, ColumnIsAddedToTable)
+{
+ table->setUseWithoutRowId(true);
+
+ ASSERT_TRUE(table->useWithoutRowId());
+}
+
+TEST_F(SqliteTable, SetTableName)
+{
+ table->setName(tableName);
+
+ ASSERT_THAT(table->name(), tableName);
+}
+
+TEST_F(SqliteTable, SetUseWithoutRowid)
+{
+ table->setUseWithoutRowId(true);
+
+ ASSERT_TRUE(table->useWithoutRowId());
+}
+
+TEST_F(SqliteTable, TableIsReadyAfterOpenDatabase)
+{
+ QSignalSpy signalSpy(&spyDummy, &SpyDummy::tableIsReady);
+ table->setName(tableName);
+ addColumn(Utf8StringLiteral("name"));
+
+ database->open();
+
+ ASSERT_TRUE(signalSpy.wait(100000));
+}
+
+void SqliteTable::SetUp()
+{
+ table = new ::SqliteTable;
+ QObject::connect(table, &::SqliteTable::tableIsReady, &spyDummy, &SpyDummy::tableIsReady);
+
+ database = new SqliteDatabase;
+ database->setJournalMode(JournalMode::Memory);
+ database->setDatabaseFilePath( QStringLiteral(":memory:"));
+ database->addTable(table);
+}
+
+void SqliteTable::TearDown()
+{
+ database->close();
+ delete database;
+ database = nullptr;
+ table = nullptr;
+}
+
+SqliteColumn *SqliteTable::addColumn(const Utf8String &columnName)
+{
+ SqliteColumn *newSqliteColum = new SqliteColumn;
+
+ newSqliteColum->setName(columnName);
+
+ table->addColumn(newSqliteColum);
+
+ return newSqliteColum;
+}
+}
diff --git a/tests/unit/unittest/sqlstatementbuildertest.cpp b/tests/unit/unittest/sqlstatementbuildertest.cpp
new file mode 100644
index 0000000000..1f04c64f5f
--- /dev/null
+++ b/tests/unit/unittest/sqlstatementbuildertest.cpp
@@ -0,0 +1,176 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "gtest/gtest.h"
+#include "gmock/gmock-matchers.h"
+#include "gtest-qt-printing.h"
+
+#include <QString>
+
+#include <sqlstatementbuilder.h>
+#include <sqlstatementbuilderexception.h>
+#include <utf8stringvector.h>
+
+using namespace ::testing;
+
+TEST(SqlStatementBuilder, Bind)
+{
+ SqlStatementBuilder sqlStatementBuilder(Utf8StringLiteral("SELECT $columns FROM $table WHERE $column = 'foo' AND rowid=$row AND rowid IN ($rows)"));
+
+ sqlStatementBuilder.bind(Utf8StringLiteral("$columns"), Utf8StringVector() << Utf8StringLiteral("name") << Utf8StringLiteral("number"));
+ sqlStatementBuilder.bind(Utf8StringLiteral("$column"), Utf8StringLiteral("name"));
+ sqlStatementBuilder.bind(Utf8StringLiteral("$table"), Utf8StringLiteral("test"));
+ sqlStatementBuilder.bind(Utf8StringLiteral("$row"), 20);
+ sqlStatementBuilder.bind(Utf8StringLiteral("$rows"), QVector<int>() << 1 << 2 << 3);
+
+ ASSERT_THAT(sqlStatementBuilder.sqlStatement(), Utf8StringLiteral("SELECT name, number FROM test WHERE name = 'foo' AND rowid=20 AND rowid IN (1, 2, 3)"));
+}
+
+TEST(SqlStatementBuilder, BindEmpty)
+{
+ SqlStatementBuilder sqlStatementBuilder(Utf8StringLiteral("SELECT $columns FROM $table$emptyPart"));
+ sqlStatementBuilder.bind(Utf8StringLiteral("$columns"), Utf8StringVector() << Utf8StringLiteral("name") << Utf8StringLiteral("number"));
+ sqlStatementBuilder.bind(Utf8StringLiteral("$table"), Utf8StringLiteral("test"));
+
+ sqlStatementBuilder.bindEmptyText(Utf8StringLiteral("$emptyPart"));
+
+ ASSERT_THAT(sqlStatementBuilder.sqlStatement(), Utf8StringLiteral("SELECT name, number FROM test"));
+}
+
+TEST(SqlStatementBuilder, BindFailure)
+{
+ SqlStatementBuilder sqlStatementBuilder(Utf8StringLiteral("SELECT $columns FROM $table"));
+
+ Utf8StringVector columns;
+
+ ASSERT_THROW(sqlStatementBuilder.bind(Utf8StringLiteral("$columns"), Utf8StringLiteral("")), SqlStatementBuilderException);
+ ASSERT_THROW(sqlStatementBuilder.bind(Utf8StringLiteral("columns"), Utf8StringLiteral("test")), SqlStatementBuilderException);
+ ASSERT_THROW(sqlStatementBuilder.bind(Utf8StringLiteral("$columns"), columns), SqlStatementBuilderException);
+ ASSERT_THROW(sqlStatementBuilder.bindWithInsertTemplateParameters(Utf8StringLiteral("$columns"), columns), SqlStatementBuilderException);
+ ASSERT_THROW(sqlStatementBuilder.bindWithUpdateTemplateParameters(Utf8StringLiteral("$columns"), columns), SqlStatementBuilderException);
+}
+
+TEST(SqlStatementBuilder, BindWithInsertTemplateParameters)
+{
+ Utf8StringVector columns({Utf8StringLiteral("name"), Utf8StringLiteral("number")});
+
+ SqlStatementBuilder sqlStatementBuilder(Utf8StringLiteral("INSERT OR IGNORE INTO $table ($columns) VALUES ($values)"));
+ sqlStatementBuilder.bind(Utf8StringLiteral("$table"), Utf8StringLiteral("test"));
+ sqlStatementBuilder.bind(Utf8StringLiteral("$columns"), columns);
+ sqlStatementBuilder.bindWithInsertTemplateParameters(Utf8StringLiteral("$values"), columns);
+
+ ASSERT_THAT(sqlStatementBuilder.sqlStatement(), Utf8StringLiteral("INSERT OR IGNORE INTO test (name, number) VALUES (?, ?)"));
+}
+
+TEST(SqlStatementBuilder, BindWithUpdateTemplateParameters)
+{
+ Utf8StringVector columns({Utf8StringLiteral("name"), Utf8StringLiteral("number")});
+
+ SqlStatementBuilder sqlStatementBuilder(Utf8StringLiteral("UPDATE $table SET $columnValues WHERE id=?"));
+ sqlStatementBuilder.bind(Utf8StringLiteral("$table"), Utf8StringLiteral("test"));
+ sqlStatementBuilder.bindWithUpdateTemplateParameters(Utf8StringLiteral("$columnValues"), columns);
+
+ ASSERT_THAT(sqlStatementBuilder.sqlStatement(), Utf8StringLiteral("UPDATE test SET name=?, number=? WHERE id=?"));
+}
+
+TEST(SqlStatementBuilder, BindWithUpdateTemplateNames)
+{
+ Utf8StringVector columns({Utf8StringLiteral("name"), Utf8StringLiteral("number")});
+
+ SqlStatementBuilder sqlStatementBuilder(Utf8StringLiteral("UPDATE $table SET $columnValues WHERE id=@id"));
+ sqlStatementBuilder.bind(Utf8StringLiteral("$table"), Utf8StringLiteral("test"));
+ sqlStatementBuilder.bindWithUpdateTemplateNames(Utf8StringLiteral("$columnValues"), columns);
+
+ ASSERT_THAT(sqlStatementBuilder.sqlStatement(), Utf8StringLiteral("UPDATE test SET name=@name, number=@number WHERE id=@id"));
+}
+
+TEST(SqlStatementBuilder, ClearOnRebinding)
+{
+ SqlStatementBuilder sqlStatementBuilder(Utf8StringLiteral("SELECT $columns FROM $table"));
+
+ sqlStatementBuilder.bind(Utf8StringLiteral("$columns"), Utf8StringLiteral("name, number"));
+ sqlStatementBuilder.bind(Utf8StringLiteral("$table"), Utf8StringLiteral("test"));
+
+ ASSERT_THAT(sqlStatementBuilder.sqlStatement(), Utf8StringLiteral("SELECT name, number FROM test"));
+
+ sqlStatementBuilder.bind(Utf8StringLiteral("$table"), Utf8StringLiteral("test2"));
+
+ ASSERT_THAT(sqlStatementBuilder.sqlStatement(), Utf8StringLiteral("SELECT name, number FROM test2"));
+}
+
+TEST(SqlStatementBuilder, ClearBinding)
+{
+ SqlStatementBuilder sqlStatementBuilder(Utf8StringLiteral("SELECT $columns FROM $table"));
+
+ sqlStatementBuilder.bind(Utf8StringLiteral("$columns"), Utf8StringLiteral("name, number"));
+ sqlStatementBuilder.bind(Utf8StringLiteral("$table"), Utf8StringLiteral("test"));
+
+ ASSERT_THAT(sqlStatementBuilder.sqlStatement(), Utf8StringLiteral("SELECT name, number FROM test"));
+
+ sqlStatementBuilder.clear();
+
+ ASSERT_THROW(sqlStatementBuilder.sqlStatement(), SqlStatementBuilderException);
+}
+
+TEST(SqlStatementBuilder, ColumnType)
+{
+ ASSERT_THAT(SqlStatementBuilder::columnTypeToString(ColumnType::Numeric), Utf8StringLiteral("NUMERIC"));
+ ASSERT_THAT(SqlStatementBuilder::columnTypeToString(ColumnType::Integer), Utf8StringLiteral("INTEGER"));
+ ASSERT_THAT(SqlStatementBuilder::columnTypeToString(ColumnType::Real), Utf8StringLiteral("REAL"));
+ ASSERT_THAT(SqlStatementBuilder::columnTypeToString(ColumnType::Text), Utf8StringLiteral("TEXT"));
+ ASSERT_TRUE(SqlStatementBuilder::columnTypeToString(ColumnType::None).isEmpty());
+}
+
+TEST(SqlStatementBuilder, SqlStatementFailure)
+{
+ SqlStatementBuilder sqlStatementBuilder(Utf8StringLiteral("SELECT $columns FROM $table"));
+
+ sqlStatementBuilder.bind(Utf8StringLiteral("$columns"), Utf8StringLiteral("name, number"));
+
+ ASSERT_THROW(sqlStatementBuilder.sqlStatement(), SqlStatementBuilderException);
+}
+
+TEST(SqlStatementBuilder, IsBuild)
+{
+ SqlStatementBuilder sqlStatementBuilder(Utf8StringLiteral("SELECT $columns FROM $table"));
+
+ sqlStatementBuilder.bind(Utf8StringLiteral("$columns"), Utf8StringLiteral("name, number"));
+ sqlStatementBuilder.bind(Utf8StringLiteral("$table"), Utf8StringLiteral("test"));
+
+ ASSERT_FALSE(sqlStatementBuilder.isBuild());
+
+ ASSERT_THAT(sqlStatementBuilder.sqlStatement(), Utf8StringLiteral("SELECT name, number FROM test"));
+
+ ASSERT_TRUE(sqlStatementBuilder.isBuild());
+
+ sqlStatementBuilder.clear();
+
+ ASSERT_FALSE(sqlStatementBuilder.isBuild());
+}
diff --git a/tests/unit/unittest/translationunitstest.cpp b/tests/unit/unittest/translationunitstest.cpp
new file mode 100644
index 0000000000..3b74c5a166
--- /dev/null
+++ b/tests/unit/unittest/translationunitstest.cpp
@@ -0,0 +1,182 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "gtest/gtest.h"
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock-generated-matchers.h"
+#include "gtest-qt-printing.h"
+
+#include <clang-c/Index.h>
+
+#include <translationunit.h>
+#include <unsavedfiles.h>
+#include <utf8string.h>
+#include <projectpart.h>
+#include <translationunits.h>
+#include <filecontainer.h>
+#include <projectpartcontainer.h>
+#include <projects.h>
+#include <translationunitdoesnotexistexception.h>
+#include <translationunitisnullexception.h>
+#include <translationunitfilenotexitexception.h>
+#include <projectpartsdonotexistexception.h>
+
+using ClangBackEnd::TranslationUnit;
+using ClangBackEnd::UnsavedFiles;
+using ClangBackEnd::ProjectPart;
+
+using testing::IsNull;
+using testing::NotNull;
+using testing::Gt;
+using testing::Not;
+using testing::Contains;
+
+namespace {
+
+using ::testing::PrintToString;
+
+MATCHER_P2(IsTranslationUnit, filePath, projectPartId,
+ std::string(negation ? "isn't" : "is") + " translation unit with file path "
+ + PrintToString(filePath) + " and project " + PrintToString(projectPartId)
+ )
+{
+ if (arg.filePath() != filePath) {
+ *result_listener << "file path is " + PrintToString(arg.filePath()) + " and not " + PrintToString(filePath);
+ return false;
+ }
+
+ if (arg.projectPartId() != projectPartId) {
+ *result_listener << "file path is " + PrintToString(arg.projectPartId()) + " and not " + PrintToString(projectPartId);
+ return false;
+ }
+
+ return true;
+}
+
+class TranslationUnits : public ::testing::Test
+{
+protected:
+ void SetUp() override;
+
+ ClangBackEnd::ProjectParts projects;
+ ClangBackEnd::UnsavedFiles unsavedFiles;
+ ClangBackEnd::TranslationUnits translationUnits = ClangBackEnd::TranslationUnits(projects, unsavedFiles);
+ const Utf8String filePath = Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp");
+ const Utf8String projectPartId = Utf8StringLiteral("/path/to/projectfile");
+
+};
+
+void TranslationUnits::SetUp()
+{
+ projects.createOrUpdate({ClangBackEnd::ProjectPartContainer(projectPartId)});
+}
+
+
+TEST_F(TranslationUnits, ThrowForGettingWithWrongFilePath)
+{
+ ASSERT_THROW(translationUnits.translationUnit(Utf8StringLiteral("foo.cpp"), projectPartId),
+ ClangBackEnd::TranslationUnitDoesNotExistException);
+
+}
+
+TEST_F(TranslationUnits, ThrowForGettingWithWrongProjectPartFilePath)
+{
+ ASSERT_THROW(translationUnits.translationUnit(filePath, Utf8StringLiteral("foo.pro")),
+ ClangBackEnd::ProjectPartDoNotExistException);
+
+}
+
+TEST_F(TranslationUnits, ThrowForAddingNonExistingFile)
+{
+ ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral("foo.cpp"), projectPartId);
+
+ ASSERT_THROW(translationUnits.createOrUpdate({fileContainer}),
+ ClangBackEnd::TranslationUnitFileNotExitsException);
+}
+
+TEST_F(TranslationUnits, DoNotThrowForAddingNonExistingFileWithUnsavedContent)
+{
+ ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral("foo.cpp"), projectPartId, Utf8String(), true);
+
+ ASSERT_NO_THROW(translationUnits.createOrUpdate({fileContainer}));
+}
+
+TEST_F(TranslationUnits, Add)
+{
+ ClangBackEnd::FileContainer fileContainer(filePath, projectPartId);
+
+ translationUnits.createOrUpdate({fileContainer});
+
+ ASSERT_THAT(translationUnits.translationUnit(filePath, projectPartId),
+ IsTranslationUnit(filePath, projectPartId));
+}
+
+TEST_F(TranslationUnits, ThrowForRemovingWithWrongFilePath)
+{
+ ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral("foo.cpp"), projectPartId);
+
+ ASSERT_THROW(translationUnits.remove({fileContainer}),
+ ClangBackEnd::TranslationUnitDoesNotExistException);
+}
+
+TEST_F(TranslationUnits, ThrowForRemovingWithWrongProjectPartFilePath)
+{
+ ClangBackEnd::FileContainer fileContainer(filePath, Utf8StringLiteral("foo.pro"));
+
+ ASSERT_THROW(translationUnits.remove({fileContainer}),
+ ClangBackEnd::ProjectPartDoNotExistException);
+}
+
+TEST_F(TranslationUnits, Remove)
+{
+ ClangBackEnd::FileContainer fileContainer(filePath, projectPartId);
+ translationUnits.createOrUpdate({fileContainer});
+
+ translationUnits.remove({fileContainer});
+
+ ASSERT_THROW(translationUnits.translationUnit(filePath, projectPartId),
+ ClangBackEnd::TranslationUnitDoesNotExistException);
+}
+
+TEST_F(TranslationUnits, RemoveAllValidIfExceptionIsThrown)
+{
+ ClangBackEnd::FileContainer fileContainer(filePath, projectPartId);
+ translationUnits.createOrUpdate({fileContainer});
+
+ ASSERT_THROW(translationUnits.remove({ClangBackEnd::FileContainer(Utf8StringLiteral("dontextist.pro"), projectPartId), fileContainer}),
+ ClangBackEnd::TranslationUnitDoesNotExistException);
+
+ ASSERT_THAT(translationUnits.translationUnits(),
+ Not(Contains(TranslationUnit(filePath, unsavedFiles, projects.project(projectPartId)))));
+}
+
+}
+
+
diff --git a/tests/unit/unittest/translationunittest.cpp b/tests/unit/unittest/translationunittest.cpp
new file mode 100644
index 0000000000..72cd39cf29
--- /dev/null
+++ b/tests/unit/unittest/translationunittest.cpp
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "gtest/gtest.h"
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock-generated-matchers.h"
+#include "gtest-qt-printing.h"
+
+#include <clang-c/Index.h>
+
+#include <translationunit.h>
+#include <unsavedfiles.h>
+#include <utf8string.h>
+#include <projectpart.h>
+#include <translationunits.h>
+#include <filecontainer.h>
+#include <projects.h>
+#include <translationunitdoesnotexistexception.h>
+#include <translationunitisnullexception.h>
+#include <translationunitfilenotexitexception.h>
+#include <translationunitparseerrorexception.h>
+
+#include <chrono>
+#include <thread>
+
+using ClangBackEnd::TranslationUnit;
+using ClangBackEnd::UnsavedFiles;
+using ClangBackEnd::ProjectPart;
+
+using testing::IsNull;
+using testing::NotNull;
+using testing::Gt;
+
+namespace {
+
+TEST(TranslationUnit, DefaultTranslationUnitIsInvalid)
+{
+ TranslationUnit translationUnit;
+
+ ASSERT_TRUE(translationUnit.isNull());
+}
+
+TEST(TranslationUnit, ThrowExceptionForNonExistingFilePath)
+{
+ ASSERT_THROW(TranslationUnit(Utf8StringLiteral("file.cpp"), UnsavedFiles(), ProjectPart(Utf8StringLiteral("/path/to/projectfile"))),
+ ClangBackEnd::TranslationUnitFileNotExitsException);
+}
+
+TEST(TranslationUnit, ThrowNoExceptionForNonExistingFilePathIfDoNotCheckIfFileExistsIsSet)
+{
+ ASSERT_NO_THROW(TranslationUnit(Utf8StringLiteral("file.cpp"), UnsavedFiles(), ProjectPart(Utf8StringLiteral("/path/to/projectfile")), TranslationUnit::DoNotCheckIfFileExists));
+}
+
+TEST(TranslationUnit, TranslationUnitIsValid)
+{
+ TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), UnsavedFiles(), ProjectPart(Utf8StringLiteral("/path/to/projectfile")));
+
+ ASSERT_FALSE(translationUnit.isNull());
+}
+
+
+TEST(TranslationUnit, ThrowExceptionForGettingIndexForInvalidUnit)
+{
+ TranslationUnit translationUnit;
+
+ ASSERT_THROW(translationUnit.index(), ClangBackEnd::TranslationUnitIsNullException);
+}
+
+TEST(TranslationUnit, IndexGetterIsNonNullForValidUnit)
+{
+ TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), UnsavedFiles(), ProjectPart(Utf8StringLiteral("/path/to/projectfile")));
+
+ ASSERT_THAT(translationUnit.index(), NotNull());
+}
+
+TEST(TranslationUnit, ThrowExceptionForGettingCxTranslationUnitForInvalidUnit)
+{
+ TranslationUnit translationUnit;
+
+ ASSERT_THROW(translationUnit.cxTranslationUnit(), ClangBackEnd::TranslationUnitIsNullException);
+}
+
+TEST(TranslationUnit, CxTranslationUnitGetterIsNonNullForValidUnit)
+{
+ UnsavedFiles unsavedFiles;
+ TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), unsavedFiles, ProjectPart(Utf8StringLiteral("/path/to/projectfile")));
+
+ ASSERT_THAT(translationUnit.cxTranslationUnit(), NotNull());
+}
+
+TEST(TranslationUnit, ThrowExceptionIfGettingFilePathForNullUnit)
+{
+ TranslationUnit translationUnit;
+
+ ASSERT_THROW(translationUnit.filePath(), ClangBackEnd::TranslationUnitIsNullException);
+}
+
+TEST(TranslationUnit, ResetedTranslationUnitIsNull)
+{
+ TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), UnsavedFiles(), ProjectPart(Utf8StringLiteral("/path/to/projectfile")));
+
+ translationUnit.reset();
+
+ ASSERT_TRUE(translationUnit.isNull());
+}
+
+TEST(TranslationUnit, TimeStampIsUpdatedAsNewCxTranslationUnitIsGenerated)
+{
+ TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), UnsavedFiles(), ProjectPart(Utf8StringLiteral("/path/to/projectfile")));
+ auto lastChangeTimePoint = translationUnit.lastChangeTimePoint();
+ std::this_thread::sleep_for(std::chrono::steady_clock::duration(1));
+
+ translationUnit.cxTranslationUnit();
+
+ ASSERT_THAT(translationUnit.lastChangeTimePoint(), Gt(lastChangeTimePoint));
+}
+
+
+//TEST(TranslationUnit, ThrowParseErrorForWrongArguments)
+//{
+// ProjectPart project(Utf8StringLiteral("/path/to/projectfile"));
+// project.setArguments({Utf8StringLiteral("-fblah")});
+// TranslationUnit translationUnit(Utf8StringLiteral(TESTDATA_DIR"/complete_testfile_1.cpp"), UnsavedFiles(), project);
+
+// ASSERT_THROW(translationUnit.cxTranslationUnit(), ClangBackEnd::TranslationUnitParseErrorException);
+//}
+
+}
diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro
new file mode 100644
index 0000000000..330a4f3d5b
--- /dev/null
+++ b/tests/unit/unittest/unittest.pro
@@ -0,0 +1,89 @@
+QT += core network testlib
+QT -= gui
+
+TARGET = unittest
+CONFIG += console c++14 testcase
+CONFIG -= app_bundle
+
+TEMPLATE = app
+
+GMOCK_DIR = $$(GMOCK_DIR)
+GTEST_DIR = $$GMOCK_DIR/gtest
+
+requires(exists($$GMOCK_DIR))
+!exists($$GMOCK_DIR):message("No gmock is found! To enabe unit tests set GMOCK_DIR")
+
+INCLUDEPATH += $$GTEST_DIR $$GTEST_DIR/include $$GMOCK_DIR $$GMOCK_DIR/include
+
+include(../../../src/libs/sqlite/sqlite-lib.pri)
+include(../../../src/libs/clangbackendipc/clangbackendipc-lib.pri)
+include(../../../src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri)
+include(../../../src/shared/clang/clang_installation.pri)
+include(../../../src/plugins/clangcodemodel/clangcodemodelunittestfiles.pri)
+
+INCLUDEPATH += $$PWD/../../../src/libs $$PWD/../../../src/plugins
+
+requires(!isEmpty(LLVM_LIBS))
+
+LIBS += $$LLVM_LIBS
+INCLUDEPATH += $$LLVM_INCLUDEPATH
+INCLUDEPATH += ../../../../src/libs/utils
+
+osx:QMAKE_CXXFLAGS = -stdlib=libc++
+
+SOURCES += main.cpp \
+ $$GTEST_DIR/src/gtest-all.cc \
+ $$GMOCK_DIR/src/gmock-all.cc \
+ utf8test.cpp \
+ sqlstatementbuildertest.cpp \
+ createtablesqlstatementbuildertest.cpp \
+ sqlitecolumntest.cpp \
+ sqlitestatementtest.cpp \
+ sqlitetabletest.cpp \
+ spydummy.cpp \
+ sqlitedatabasetest.cpp \
+ sqlitedatabasebackendtest.cpp \
+ readandwritecommandblocktest.cpp \
+ clientserverinprocesstest.cpp \
+ clientserveroutsideprocess.cpp \
+ gtest-qt-printing.cpp \
+ codecompletiontest.cpp \
+ ../../../src/libs/utils/qtcassert.cpp \
+ clangstringtest.cpp \
+ translationunittest.cpp \
+ clangcodecompleteresultstest.cpp \
+ codecompletionsextractortest.cpp \
+ unsavedfilestest.cpp \
+ projecttest.cpp \
+ clangipcservertest.cpp \
+ translationunitstest.cpp \
+ completionchunkstotextconvertertest.cpp
+
+HEADERS += \
+ gtest-qt-printing.h \
+ spydummy.h \
+ ../../../src/libs/utils/qtcassert.h \
+ mockipclient.h \
+ mockipcserver.h
+
+OTHER_FILES += data/complete_testfile_1.cpp \
+ data/complete_completer.cpp \
+ data/complete_completer_unsaved.cpp \
+ data/complete_extractor_function.cpp \
+ data/complete_extractor_function_unsaved.cpp \
+ data/complete_extractor_function_unsaved_2.cpp \
+ data/complete_extractor_variable.cpp \
+ data/complete_extractor_class.cpp \
+ data/complete_extractor_namespace.cpp \
+ data/complete_extractor_enumeration.cpp \
+ data/complete_extractor_constructor.cpp \
+ data/complete_translationunit_parse_error.cpp
+
+DEFINES += QT_NO_CAST_FROM_ASCII
+DEFINES += CLANGBACKEND_TESTS
+DEFINES += DONT_CHECK_COMMAND_COUNTER
+DEFINES += GTEST_HAS_STD_INITIALIZER_LIST_ GTEST_LANG_CXX11
+
+DEFINES += TESTDATA_DIR=\"R\\\"xxx($$PWD/data)xxx\\\"\"
+win32:DEFINES += ECHOSERVER=\"R\\\"xxx($$OUT_PWD/../echo)xxx\\\"\"
+unix:DEFINES += ECHOSERVER=\"R\\\"xxx($$OUT_PWD/../echoserver/echo)xxx\\\"\"
diff --git a/tests/unit/unittest/unsavedfilestest.cpp b/tests/unit/unittest/unsavedfilestest.cpp
new file mode 100644
index 0000000000..0b843c6011
--- /dev/null
+++ b/tests/unit/unittest/unsavedfilestest.cpp
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "gtest/gtest.h"
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock.h"
+#include "gtest-qt-printing.h"
+
+#include <unsavedfiles.h>
+#include <filecontainer.h>
+
+#include <QVector>
+
+using ClangBackEnd::UnsavedFiles;
+using ClangBackEnd::FileContainer;
+
+using ::testing::IsNull;
+using ::testing::NotNull;
+using ::testing::Gt;
+
+namespace {
+
+bool operator==(const ClangBackEnd::FileContainer &fileContainer, const CXUnsavedFile &cxUnsavedFile)
+{
+ return fileContainer.filePath() == Utf8String::fromUtf8(cxUnsavedFile.Filename)
+ && fileContainer.unsavedFileContent() == Utf8String(cxUnsavedFile.Contents, cxUnsavedFile.Length);
+}
+
+bool fileContainersContainsItemMatchingToCxUnsavedFile(const QVector<FileContainer> &fileContainers, const CXUnsavedFile &cxUnsavedFile)
+{
+ for (const FileContainer &fileContainer : fileContainers)
+ if (fileContainer == cxUnsavedFile)
+ return true;
+
+ return false;
+}
+
+MATCHER_P(HasUnsavedFiles, fileContainers, "")
+{
+ ClangBackEnd::UnsavedFiles unsavedFiles = arg;
+ if (unsavedFiles.count() != fileContainers.size()) {
+ *result_listener << "unsaved count is " << unsavedFiles.count() << " and not " << fileContainers.size();
+ return false;
+ }
+
+ for (const CXUnsavedFile &cxUnsavedFile : unsavedFiles.cxUnsavedFileVector()) {
+ if (!fileContainersContainsItemMatchingToCxUnsavedFile(fileContainers, cxUnsavedFile))
+ return false;
+ }
+
+ return true;
+}
+
+class UnsavedFiles : public ::testing::Test
+{
+protected:
+ void TearDown() override;
+
+protected:
+ ::UnsavedFiles unsavedFiles;
+};
+
+void UnsavedFiles::TearDown()
+{
+ unsavedFiles.clear();
+}
+
+TEST_F(UnsavedFiles, DoNothingForUpdateIfFileHasNoUnsavedContent)
+{
+ QVector<FileContainer> fileContainers({FileContainer(Utf8StringLiteral("file.cpp"), Utf8StringLiteral("pathToProject.pro"))});
+
+ unsavedFiles.createOrUpdate(fileContainers);
+
+ ASSERT_THAT(unsavedFiles, HasUnsavedFiles(QVector<FileContainer>()));
+}
+
+TEST_F(UnsavedFiles, AddUnsavedFileForUpdateWithUnsavedContent)
+{
+ QVector<FileContainer> fileContainers({FileContainer(Utf8StringLiteral("file.cpp"), Utf8StringLiteral("pathToProject.pro")),
+ FileContainer(Utf8StringLiteral("file.cpp"), Utf8StringLiteral("pathToProject.pro"), Utf8StringLiteral("foo"), true)});
+ unsavedFiles.createOrUpdate(fileContainers);
+
+ ASSERT_THAT(unsavedFiles, HasUnsavedFiles(QVector<FileContainer>({FileContainer(Utf8StringLiteral("file.cpp"), Utf8StringLiteral("pathToProject.pro"), Utf8StringLiteral("foo"), true)})));
+}
+
+TEST_F(UnsavedFiles, RemoveUnsavedFileForUpdateWithUnsavedContent)
+{
+ QVector<FileContainer> fileContainers({FileContainer(Utf8StringLiteral("file.cpp"), Utf8StringLiteral("pathToProject.pro"), Utf8StringLiteral("foo"), true),
+ FileContainer(Utf8StringLiteral("file.cpp"), Utf8StringLiteral("pathToProject.pro"))});
+
+ unsavedFiles.createOrUpdate(fileContainers);
+
+ ASSERT_THAT(unsavedFiles, HasUnsavedFiles(QVector<FileContainer>()));
+}
+
+TEST_F(UnsavedFiles, ExchangeUnsavedFileForUpdateWithUnsavedContent)
+{
+ QVector<FileContainer> fileContainers({FileContainer(Utf8StringLiteral("file.cpp"), Utf8StringLiteral("pathToProject.pro"), Utf8StringLiteral("foo"), true),
+ FileContainer(Utf8StringLiteral("file.cpp"), Utf8StringLiteral("pathToProject.pro"), Utf8StringLiteral("foo2"), true)});
+ unsavedFiles.createOrUpdate(fileContainers);
+
+ ASSERT_THAT(unsavedFiles, HasUnsavedFiles(QVector<FileContainer>({FileContainer(Utf8StringLiteral("file.cpp"), Utf8StringLiteral("pathToProject.pro"), Utf8StringLiteral("foo2"), true)})));
+}
+
+TEST_F(UnsavedFiles, TimeStampIsUpdatedAsUnsavedFilesChanged)
+{
+ QVector<FileContainer> fileContainers({FileContainer(Utf8StringLiteral("file.cpp"), Utf8StringLiteral("pathToProject.pro"), Utf8StringLiteral("foo"), true),
+ FileContainer(Utf8StringLiteral("file.cpp"), Utf8StringLiteral("pathToProject.pro"), Utf8StringLiteral("foo2"), true)});
+ auto lastChangeTimePoint = unsavedFiles.lastChangeTimePoint();
+
+ unsavedFiles.createOrUpdate(fileContainers);
+
+ ASSERT_THAT(unsavedFiles.lastChangeTimePoint(), Gt(lastChangeTimePoint));
+}
+
+TEST_F(UnsavedFiles, RemoveUnsavedFiles)
+{
+ QVector<FileContainer> fileContainers({FileContainer(Utf8StringLiteral("file.cpp"), Utf8StringLiteral("pathToProject.pro"), Utf8StringLiteral("foo"), true)});
+ unsavedFiles.createOrUpdate(fileContainers);
+
+ unsavedFiles.remove(fileContainers);
+
+ ASSERT_THAT(unsavedFiles, HasUnsavedFiles(QVector<FileContainer>()));
+}
+}
+
+
diff --git a/tests/unit/unittest/utf8test.cpp b/tests/unit/unittest/utf8test.cpp
new file mode 100644
index 0000000000..db4dcb0e81
--- /dev/null
+++ b/tests/unit/unittest/utf8test.cpp
@@ -0,0 +1,273 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 Digia. For licensing terms and
+** conditions see http://www.qt.io/licensing. For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "gtest/gtest.h"
+#include "gmock/gmock-matchers.h"
+#include "gtest-qt-printing.h"
+
+#include <QString>
+
+#include <utf8stringvector.h>
+
+using namespace ::testing;
+
+TEST(Utf8, QStringConversionConstructor)
+{
+ ASSERT_THAT(Utf8String(QStringLiteral("text")), Utf8StringLiteral("text"));
+}
+
+TEST(Utf8, QByteArrayConversionFunction)
+{
+ ASSERT_THAT(Utf8String::fromByteArray("text"), Utf8StringLiteral("text"));
+}
+
+TEST(Utf8, QStringConversionFunction)
+{
+ ASSERT_THAT(Utf8String::fromString(QStringLiteral("text")), Utf8StringLiteral("text"));
+}
+
+TEST(Utf8, Utf8ConversationFunction)
+{
+ ASSERT_THAT(Utf8String::fromUtf8("text"), Utf8StringLiteral("text"));
+}
+
+TEST(Utf8, Mid)
+{
+ Utf8String text(Utf8StringLiteral("some text"));
+
+ ASSERT_THAT(text.mid(5, 4), Utf8StringLiteral("text"));
+ ASSERT_THAT(text.mid(5), Utf8StringLiteral("text"));
+}
+
+TEST(Utf8, ByteSize)
+{
+ ASSERT_THAT(Utf8StringLiteral("text").byteSize(), 4);
+}
+
+TEST(Utf8, Append)
+{
+ Utf8String text(Utf8StringLiteral("some "));
+ text.append(Utf8StringLiteral("text"));
+
+ ASSERT_THAT(text, Utf8StringLiteral("some text"));
+}
+
+TEST(Utf8, ToByteArray)
+{
+ Utf8String text(Utf8StringLiteral("some text"));
+
+ ASSERT_THAT(text.toByteArray(), QByteArrayLiteral("some text"));
+}
+
+TEST(Utf8, ToString)
+{
+ Utf8String text(Utf8StringLiteral("some text"));
+
+ ASSERT_THAT(text.toString(), QStringLiteral("some text"));
+}
+
+
+TEST(Utf8, Contains)
+{
+ Utf8String text(Utf8StringLiteral("some text"));
+
+ ASSERT_TRUE(text.contains(Utf8StringLiteral("text")));
+ ASSERT_TRUE(text.contains("text"));
+ ASSERT_TRUE(text.contains('x'));
+}
+
+TEST(Utf8, EqualOperator)
+{
+ ASSERT_TRUE(Utf8StringLiteral("text") == Utf8StringLiteral("text"));
+ ASSERT_FALSE(Utf8StringLiteral("text") == Utf8StringLiteral("text2"));
+}
+
+TEST(Utf8, SmallerOperator)
+{
+ ASSERT_TRUE(Utf8StringLiteral("some") < Utf8StringLiteral("text"));
+ ASSERT_TRUE(Utf8StringLiteral("text") < Utf8StringLiteral("texta"));
+ ASSERT_FALSE(Utf8StringLiteral("text") < Utf8StringLiteral("some"));
+ ASSERT_FALSE(Utf8StringLiteral("text") < Utf8StringLiteral("text"));
+}
+
+TEST(Utf8, UnequalOperator)
+{
+ ASSERT_FALSE(Utf8StringLiteral("text") != Utf8StringLiteral("text"));
+ ASSERT_TRUE(Utf8StringLiteral("text") != Utf8StringLiteral("text2"));
+}
+
+TEST(Utf8, Join)
+{
+ Utf8StringVector vector;
+
+ vector.append(Utf8StringLiteral("some"));
+ vector.append(Utf8StringLiteral("text"));
+
+ ASSERT_THAT(Utf8StringLiteral("some, text"), vector.join(Utf8StringLiteral(", ")));
+}
+
+TEST(Utf8, Split)
+{
+ Utf8String test(Utf8StringLiteral("some text"));
+
+ Utf8StringVector splittedText = test.split(' ');
+
+ ASSERT_THAT(splittedText.at(0), Utf8StringLiteral("some"));
+ ASSERT_THAT(splittedText.at(1), Utf8StringLiteral("text"));
+}
+
+TEST(Utf8, IsEmpty)
+{
+ ASSERT_FALSE(Utf8StringLiteral("text").isEmpty());
+ ASSERT_TRUE(Utf8String().isEmpty());
+}
+
+TEST(Utf8, HasContent)
+{
+ ASSERT_TRUE(Utf8StringLiteral("text").hasContent());
+ ASSERT_FALSE(Utf8String().hasContent());
+}
+
+TEST(Utf8, Replace)
+{
+ Utf8String text(Utf8StringLiteral("some text"));
+
+ text.replace(Utf8StringLiteral("some"), Utf8StringLiteral("any"));
+
+ ASSERT_THAT(text, Utf8StringLiteral("any text"));
+}
+
+TEST(Utf8, StartsWith)
+{
+ Utf8String text(Utf8StringLiteral("$column"));
+
+ ASSERT_TRUE(text.startsWith(Utf8StringLiteral("$col")));
+ ASSERT_FALSE(text.startsWith(Utf8StringLiteral("col")));
+ ASSERT_TRUE(text.startsWith("$col"));
+ ASSERT_FALSE(text.startsWith("col"));
+ ASSERT_TRUE(text.startsWith('$'));
+ ASSERT_FALSE(text.startsWith('@'));
+}
+
+TEST(Utf8, Clear)
+{
+ Utf8String text(Utf8StringLiteral("$column"));
+
+ text.clear();
+
+ ASSERT_TRUE(text.isEmpty());
+}
+
+TEST(Utf8, Number)
+{
+ ASSERT_THAT(Utf8String::number(20), Utf8StringLiteral("20"));
+}
+
+TEST(Utf8, FromIntegerVector)
+{
+ QVector<int> integers({1, 2, 3});
+
+ ASSERT_THAT(Utf8StringVector::fromIntegerVector(integers).join(Utf8StringLiteral(", ")), Utf8StringLiteral("1, 2, 3"));
+}
+
+TEST(Utf8, PlusOperator)
+{
+ auto text = Utf8StringLiteral("foo") + Utf8StringLiteral("bar");
+
+ ASSERT_THAT(text, Utf8StringLiteral("foobar"));
+}
+
+TEST(Utf8, PlusAssignmentOperator)
+{
+ Utf8String text("foo", 3);
+
+ text += Utf8StringLiteral("bar");
+
+ ASSERT_THAT(text, Utf8StringLiteral("foobar"));
+}
+
+TEST(Utf8, CompareCharPointer)
+{
+ Utf8String text("foo", 3);
+
+ ASSERT_TRUE(text == "foo");
+ ASSERT_FALSE(text == "foo2");
+}
+
+TEST(Utf8, RemoveFastFromVectorFailed)
+{
+ Utf8StringVector values({Utf8StringLiteral("a"),
+ Utf8StringLiteral("b"),
+ Utf8StringLiteral("c"),
+ Utf8StringLiteral("d")});
+
+ ASSERT_FALSE(values.removeFast(Utf8StringLiteral("e")));
+}
+
+TEST(Utf8, RemoveFastFromVector)
+{
+ Utf8StringVector values({Utf8StringLiteral("a"),
+ Utf8StringLiteral("b"),
+ Utf8StringLiteral("c"),
+ Utf8StringLiteral("d")});
+
+ bool removed = values.removeFast(Utf8StringLiteral("b"));
+
+ ASSERT_TRUE(removed);
+ ASSERT_THAT(values, Not(Contains(Utf8StringLiteral("b"))));
+}
+
+TEST(Utf8, ConverteAutomaticallyFromQString)
+{
+ QString text(QStringLiteral("foo"));
+
+ Utf8String utf8Text(text);
+
+ ASSERT_THAT(utf8Text, Utf8StringLiteral("foo"));
+}
+
+TEST(Utf8, ConverteAutomaticallyToQString)
+{
+ Utf8String utf8Text(Utf8StringLiteral("foo"));
+
+ QString text = utf8Text;
+
+ ASSERT_THAT(text, QStringLiteral("foo"));
+}
+
+TEST(Utf8, ConverteAutomaticallyToQByteArray)
+{
+ Utf8String utf8Text(Utf8StringLiteral("foo"));
+
+ QByteArray bytes = utf8Text;
+
+ ASSERT_THAT(bytes, QByteArrayLiteral("foo"));
+}
+