2017-07-28 15:15:46 +02:00
|
|
|
/****************************************************************************
|
|
|
|
**
|
|
|
|
** Copyright (C) 2017 The Qt Company Ltd.
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
|
|
|
**
|
|
|
|
** This file is part of Qt Creator.
|
|
|
|
**
|
|
|
|
** Commercial License Usage
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
|
|
|
**
|
|
|
|
** GNU General Public License Usage
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
|
|
|
**
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include "googletest.h"
|
|
|
|
|
|
|
|
#include "dummyclangipcclient.h"
|
|
|
|
|
|
|
|
#include <clangclock.h>
|
|
|
|
#include <clangdocument.h>
|
|
|
|
#include <clangdocumentprocessors.h>
|
|
|
|
#include <clangdocuments.h>
|
|
|
|
#include <clangdocumentsuspenderresumer.h>
|
|
|
|
#include <clangtranslationunits.h>
|
|
|
|
#include <unsavedfiles.h>
|
|
|
|
#include <utf8string.h>
|
|
|
|
|
|
|
|
#include <utils/algorithm.h>
|
|
|
|
|
|
|
|
#include <clang-c/Index.h>
|
|
|
|
|
|
|
|
using ClangBackEnd::Clock;
|
|
|
|
using ClangBackEnd::Document;
|
|
|
|
using ClangBackEnd::JobRequest;
|
|
|
|
using ClangBackEnd::PreferredTranslationUnit;
|
|
|
|
using ClangBackEnd::SuspendResumeJobs;
|
|
|
|
using ClangBackEnd::SuspendResumeJobsEntry;
|
|
|
|
using ClangBackEnd::TimePoint;
|
|
|
|
|
|
|
|
using testing::ContainerEq;
|
|
|
|
using testing::ElementsAre;
|
|
|
|
using testing::IsEmpty;
|
|
|
|
|
|
|
|
namespace ClangBackEnd {
|
|
|
|
|
|
|
|
bool operator==(const SuspendResumeJobsEntry &a, const SuspendResumeJobsEntry &b)
|
|
|
|
{
|
|
|
|
return a.document == b.document
|
|
|
|
&& a.jobRequestType == b.jobRequestType
|
|
|
|
&& a.preferredTranslationUnit == b.preferredTranslationUnit;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // ClangBackEnd
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
class DocumentSuspenderResumer : public ::testing::Test
|
|
|
|
{
|
|
|
|
protected:
|
|
|
|
Document getDocument(const Utf8String &filePath);
|
|
|
|
void categorizeDocuments(int hotDocumentsSize);
|
|
|
|
SuspendResumeJobs createSuspendResumeJobs(int hotDocumentsSize = -1);
|
2017-08-22 14:51:34 +02:00
|
|
|
static void setParsed(Document &document);
|
2017-07-28 15:15:46 +02:00
|
|
|
|
|
|
|
protected:
|
|
|
|
ClangBackEnd::UnsavedFiles unsavedFiles;
|
2018-09-25 09:41:32 +02:00
|
|
|
ClangBackEnd::Documents documents{unsavedFiles};
|
2017-07-28 15:15:46 +02:00
|
|
|
DummyIpcClient dummyIpcClient;
|
2018-09-25 09:41:32 +02:00
|
|
|
ClangBackEnd::DocumentProcessors documentProcessors{documents, unsavedFiles, dummyIpcClient};
|
2017-07-28 15:15:46 +02:00
|
|
|
|
|
|
|
const Utf8String filePath1 = Utf8StringLiteral(TESTDATA_DIR"/empty1.cpp");
|
2018-09-25 09:41:32 +02:00
|
|
|
const ClangBackEnd::FileContainer fileContainer1{filePath1, Utf8String(), true};
|
2017-07-28 15:15:46 +02:00
|
|
|
|
|
|
|
const Utf8String filePath2 = Utf8StringLiteral(TESTDATA_DIR"/empty2.cpp");
|
2018-09-25 09:41:32 +02:00
|
|
|
const ClangBackEnd::FileContainer fileContainer2{filePath2, Utf8String(), true};
|
2017-07-28 15:15:46 +02:00
|
|
|
|
|
|
|
const Utf8String filePath3 = Utf8StringLiteral(TESTDATA_DIR"/empty3.cpp");
|
2018-09-25 09:41:32 +02:00
|
|
|
const ClangBackEnd::FileContainer fileContainer3{filePath3, Utf8String(), true};
|
2017-07-28 15:15:46 +02:00
|
|
|
|
|
|
|
std::vector<Document> hotDocuments;
|
|
|
|
std::vector<Document> coldDocuments;
|
|
|
|
};
|
|
|
|
|
|
|
|
TEST_F(DocumentSuspenderResumer, CategorizeNoDocuments)
|
|
|
|
{
|
|
|
|
categorizeDocuments(99);
|
|
|
|
|
|
|
|
ASSERT_THAT(hotDocuments, IsEmpty());
|
|
|
|
ASSERT_THAT(coldDocuments, IsEmpty());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(DocumentSuspenderResumer, CategorizeSingleDocument)
|
|
|
|
{
|
|
|
|
documents.create({fileContainer1});
|
|
|
|
|
|
|
|
categorizeDocuments(99);
|
|
|
|
|
|
|
|
ASSERT_THAT(hotDocuments, ElementsAre(getDocument(filePath1)));
|
|
|
|
ASSERT_THAT(coldDocuments, IsEmpty());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(DocumentSuspenderResumer, CategorizeKeepsStableOrder)
|
|
|
|
{
|
|
|
|
documents.create({fileContainer1, fileContainer2});
|
|
|
|
|
|
|
|
categorizeDocuments(99);
|
|
|
|
|
|
|
|
ASSERT_THAT(hotDocuments, ElementsAre(getDocument(filePath1),
|
|
|
|
getDocument(filePath2)));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(DocumentSuspenderResumer, CategorizePutsLastVisibleToTopOfHotDocuments)
|
|
|
|
{
|
|
|
|
documents.create({fileContainer1, fileContainer2});
|
|
|
|
documents.setVisibleInEditors({filePath1});
|
|
|
|
documents.setVisibleInEditors({filePath2});
|
|
|
|
|
|
|
|
categorizeDocuments(99);
|
|
|
|
|
|
|
|
ASSERT_THAT(hotDocuments, ElementsAre(getDocument(filePath2),
|
|
|
|
getDocument(filePath1)));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(DocumentSuspenderResumer, CategorizeWithLessDocumentsThanWeCareFor)
|
|
|
|
{
|
|
|
|
documents.create({fileContainer1});
|
|
|
|
|
|
|
|
categorizeDocuments(2);
|
|
|
|
|
|
|
|
ASSERT_THAT(hotDocuments, ElementsAre(getDocument(filePath1)));
|
|
|
|
ASSERT_THAT(coldDocuments, IsEmpty());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(DocumentSuspenderResumer, CategorizeWithZeroHotDocuments)
|
|
|
|
{
|
|
|
|
documents.create({fileContainer1});
|
|
|
|
|
|
|
|
categorizeDocuments(0);
|
|
|
|
|
|
|
|
ASSERT_THAT(hotDocuments, IsEmpty());
|
|
|
|
ASSERT_THAT(coldDocuments, ElementsAre(getDocument(filePath1)));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(DocumentSuspenderResumer, CategorizeWithMoreVisibleDocumentsThanHotDocuments)
|
|
|
|
{
|
|
|
|
const TimePoint timePoint = Clock::now();
|
|
|
|
Document document1 = documents.create({fileContainer1})[0];
|
|
|
|
document1.setIsVisibleInEditor(true, timePoint);
|
|
|
|
Document document2 = documents.create({fileContainer2})[0];
|
|
|
|
document2.setIsVisibleInEditor(true, timePoint);
|
|
|
|
|
|
|
|
categorizeDocuments(1);
|
|
|
|
|
|
|
|
ASSERT_THAT(hotDocuments, ElementsAre(getDocument(filePath1), getDocument(filePath2)));
|
|
|
|
ASSERT_THAT(coldDocuments, IsEmpty());
|
|
|
|
}
|
|
|
|
|
2017-09-29 13:46:53 +02:00
|
|
|
TEST_F(DocumentSuspenderResumer, CreateSuspendJobForInvisible)
|
2017-07-28 15:15:46 +02:00
|
|
|
{
|
|
|
|
Document document = documents.create({fileContainer1})[0];
|
|
|
|
document.setIsSuspended(false);
|
|
|
|
document.setIsVisibleInEditor(false, Clock::now());
|
2017-08-22 14:51:34 +02:00
|
|
|
setParsed(document);
|
|
|
|
|
2017-07-28 15:15:46 +02:00
|
|
|
const SuspendResumeJobs expectedJobs = {
|
|
|
|
{document, JobRequest::Type::SuspendDocument, PreferredTranslationUnit::RecentlyParsed}
|
|
|
|
};
|
|
|
|
|
|
|
|
const SuspendResumeJobs jobs = createSuspendResumeJobs(/*hotDocumentsSize=*/ 0);
|
|
|
|
|
|
|
|
ASSERT_THAT(jobs, ContainerEq(expectedJobs));
|
|
|
|
}
|
|
|
|
|
2017-09-29 13:46:53 +02:00
|
|
|
TEST_F(DocumentSuspenderResumer, DoNotCreateSuspendJobForVisible)
|
2017-07-28 15:15:46 +02:00
|
|
|
{
|
|
|
|
Document document = documents.create({fileContainer1})[0];
|
|
|
|
document.setIsSuspended(false);
|
|
|
|
document.setIsVisibleInEditor(true, Clock::now());
|
|
|
|
|
|
|
|
const SuspendResumeJobs jobs = createSuspendResumeJobs(/*hotDocumentsSize=*/ 0);
|
|
|
|
|
2017-08-23 09:14:54 +02:00
|
|
|
ASSERT_THAT(jobs, IsEmpty());
|
2017-07-28 15:15:46 +02:00
|
|
|
}
|
|
|
|
|
2017-09-29 13:46:53 +02:00
|
|
|
TEST_F(DocumentSuspenderResumer, DoNotCreateSuspendJobForUnparsed)
|
2017-08-22 14:51:34 +02:00
|
|
|
{
|
|
|
|
Document document = documents.create({fileContainer1})[0];
|
|
|
|
document.setIsSuspended(false);
|
|
|
|
document.setIsVisibleInEditor(true, Clock::now());
|
|
|
|
|
|
|
|
const SuspendResumeJobs jobs = createSuspendResumeJobs(/*hotDocumentsSize=*/ 0);
|
|
|
|
|
2017-08-23 09:14:54 +02:00
|
|
|
ASSERT_THAT(jobs, IsEmpty());
|
2017-08-22 14:51:34 +02:00
|
|
|
}
|
|
|
|
|
2017-09-29 13:46:53 +02:00
|
|
|
TEST_F(DocumentSuspenderResumer, CreateSuspendJobsForDocumentWithSupportiveTranslationUnit)
|
2017-07-28 15:15:46 +02:00
|
|
|
{
|
|
|
|
Document document = documents.create({fileContainer1})[0];
|
|
|
|
document.setIsSuspended(false);
|
|
|
|
document.setIsVisibleInEditor(false, Clock::now());
|
|
|
|
document.translationUnits().createAndAppend(); // Add supportive translation unit
|
2017-08-22 14:51:34 +02:00
|
|
|
setParsed(document);
|
2017-07-28 15:15:46 +02:00
|
|
|
const SuspendResumeJobs expectedJobs = {
|
|
|
|
{document, JobRequest::Type::SuspendDocument, PreferredTranslationUnit::RecentlyParsed},
|
|
|
|
{document, JobRequest::Type::SuspendDocument, PreferredTranslationUnit::PreviouslyParsed},
|
|
|
|
};
|
|
|
|
|
|
|
|
const SuspendResumeJobs jobs = createSuspendResumeJobs(/*hotDocumentsSize=*/ 0);
|
|
|
|
|
|
|
|
ASSERT_THAT(jobs, ContainerEq(expectedJobs));
|
|
|
|
}
|
|
|
|
|
2017-09-29 13:46:53 +02:00
|
|
|
TEST_F(DocumentSuspenderResumer, CreateResumeJob)
|
2017-07-28 15:15:46 +02:00
|
|
|
{
|
|
|
|
Document document = documents.create({fileContainer1})[0];
|
|
|
|
document.setIsSuspended(true);
|
|
|
|
document.setIsVisibleInEditor(true, Clock::now());
|
|
|
|
const SuspendResumeJobs expectedJobs = {
|
|
|
|
{document, JobRequest::Type::ResumeDocument, PreferredTranslationUnit::RecentlyParsed}
|
|
|
|
};
|
|
|
|
|
|
|
|
const SuspendResumeJobs jobs = createSuspendResumeJobs();
|
|
|
|
|
|
|
|
ASSERT_THAT(jobs, ContainerEq(expectedJobs));
|
|
|
|
}
|
|
|
|
|
2017-09-29 13:46:53 +02:00
|
|
|
TEST_F(DocumentSuspenderResumer, DoNotCreateResumeJobForInvisible)
|
2017-07-28 15:15:46 +02:00
|
|
|
{
|
|
|
|
Document document = documents.create({fileContainer1})[0];
|
|
|
|
document.setIsSuspended(true);
|
|
|
|
document.setIsVisibleInEditor(false, Clock::now());
|
|
|
|
|
|
|
|
const SuspendResumeJobs jobs = createSuspendResumeJobs(/*hotDocumentsSize=*/ 0);
|
|
|
|
|
2017-08-23 09:14:54 +02:00
|
|
|
ASSERT_THAT(jobs, IsEmpty());
|
2017-07-28 15:15:46 +02:00
|
|
|
}
|
|
|
|
|
2017-09-29 13:46:53 +02:00
|
|
|
TEST_F(DocumentSuspenderResumer, CreateResumeJobsForDocumentWithSupportiveTranslationUnit)
|
2017-07-28 15:15:46 +02:00
|
|
|
{
|
|
|
|
Document document = documents.create({fileContainer1})[0];
|
|
|
|
document.setIsSuspended(true);
|
|
|
|
document.setIsVisibleInEditor(true, Clock::now());
|
|
|
|
document.translationUnits().createAndAppend(); // Add supportive translation unit
|
|
|
|
const SuspendResumeJobs expectedJobs = {
|
|
|
|
{document, JobRequest::Type::ResumeDocument, PreferredTranslationUnit::RecentlyParsed},
|
|
|
|
{document, JobRequest::Type::ResumeDocument, PreferredTranslationUnit::PreviouslyParsed},
|
|
|
|
};
|
|
|
|
|
|
|
|
const SuspendResumeJobs jobs = createSuspendResumeJobs();
|
|
|
|
|
|
|
|
ASSERT_THAT(jobs, ContainerEq(expectedJobs));
|
|
|
|
}
|
|
|
|
|
2017-09-29 13:46:53 +02:00
|
|
|
TEST_F(DocumentSuspenderResumer, CreateSuspendAndResumeJobs)
|
2017-07-28 15:15:46 +02:00
|
|
|
{
|
|
|
|
Document hotDocument = documents.create({fileContainer1})[0];
|
|
|
|
hotDocument.setIsSuspended(true);
|
|
|
|
Document coldDocument = documents.create({fileContainer2})[0];
|
2017-08-22 14:51:34 +02:00
|
|
|
setParsed(coldDocument);
|
2017-07-28 15:15:46 +02:00
|
|
|
coldDocument.setIsSuspended(false);
|
|
|
|
documents.setVisibleInEditors({filePath1});
|
|
|
|
const SuspendResumeJobs expectedJobs = {
|
|
|
|
{coldDocument, JobRequest::Type::SuspendDocument, PreferredTranslationUnit::RecentlyParsed},
|
|
|
|
{hotDocument, JobRequest::Type::ResumeDocument, PreferredTranslationUnit::RecentlyParsed},
|
|
|
|
};
|
|
|
|
|
|
|
|
const SuspendResumeJobs jobs = createSuspendResumeJobs(/*hotDocumentsSize=*/ 1);
|
|
|
|
|
|
|
|
ASSERT_THAT(jobs, ContainerEq(expectedJobs));
|
|
|
|
}
|
|
|
|
|
|
|
|
ClangBackEnd::Document DocumentSuspenderResumer::getDocument(const Utf8String &filePath)
|
|
|
|
{
|
2018-09-25 09:41:32 +02:00
|
|
|
return documents.document(filePath);
|
2017-07-28 15:15:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void DocumentSuspenderResumer::categorizeDocuments(int hotDocumentsSize)
|
|
|
|
{
|
|
|
|
categorizeHotColdDocuments(hotDocumentsSize, documents.documents(), hotDocuments,
|
|
|
|
coldDocuments);
|
|
|
|
}
|
|
|
|
|
|
|
|
ClangBackEnd::SuspendResumeJobs
|
|
|
|
DocumentSuspenderResumer::createSuspendResumeJobs(int hotDocumentsSize)
|
|
|
|
{
|
|
|
|
return ClangBackEnd::createSuspendResumeJobs(documents.documents(), hotDocumentsSize);
|
|
|
|
}
|
|
|
|
|
2017-08-22 14:51:34 +02:00
|
|
|
void DocumentSuspenderResumer::setParsed(ClangBackEnd::Document &document)
|
|
|
|
{
|
|
|
|
const Utf8String first = document.translationUnit().id();
|
|
|
|
document.translationUnits().updateParseTimePoint(first, Clock::now());
|
|
|
|
|
|
|
|
const Utf8String second
|
|
|
|
= document.translationUnit(PreferredTranslationUnit::LastUninitialized).id();
|
|
|
|
if (second != first)
|
|
|
|
document.translationUnits().updateParseTimePoint(second, Clock::now());
|
|
|
|
}
|
|
|
|
|
2017-07-28 15:15:46 +02:00
|
|
|
} // anonymous
|