File indexing completed on 2024-05-26 04:38:56
0001 /* 0002 This file is part of KDevelop 0003 0004 Copyright 2008 Evgeniy Ivanov <powerfox@kde.ru> 0005 Copyright 2009 Fabian Wiesel <fabian.wiesel@fu-berlin.de> 0006 Copyright 2017 Sergey Kalinichev <kalinichev.so.0@gmail.com> 0007 0008 This library is free software; you can redistribute it and/or 0009 modify it under the terms of the GNU Library General Public 0010 License as published by the Free Software Foundation; either 0011 version 2 of the License, or (at your option) any later version. 0012 0013 This library is distributed in the hope that it will be useful, 0014 but WITHOUT ANY WARRANTY; without even the implied warranty of 0015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0016 Library General Public License for more details. 0017 0018 You should have received a copy of the GNU Library General Public License 0019 along with this library; see the file COPYING.LIB. If not, write to 0020 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0021 Boston, MA 02110-1301, USA. 0022 */ 0023 0024 #include "test_mercurial.h" 0025 0026 #include <QTest> 0027 #include <QSignalSpy> 0028 #include <tests/testcore.h> 0029 #include <tests/autotestshell.h> 0030 0031 #include <QScopedPointer> 0032 #include <QUrl> 0033 0034 #include <KIO/DeleteJob> 0035 0036 #include <vcs/dvcs/dvcsjob.h> 0037 #include <vcs/vcsannotation.h> 0038 #include <vcs/vcslocation.h> 0039 0040 #include "../mercurialplugin.h" 0041 #include "../mercurialannotatejob.h" 0042 #include "../models/mercurialheadsmodel.h" 0043 #include "debug.h" 0044 0045 using namespace KDevelop; 0046 0047 namespace 0048 { 0049 const QString tempDir = QDir::tempPath(); 0050 const QString MercurialTestDir1("kdevMercurial_testdir"); 0051 const QString mercurialTest_BaseDir(tempDir + "/kdevMercurial_testdir/"); 0052 const QString mercurialTest_BaseDir2(tempDir + "/kdevMercurial_testdir2/"); 0053 const QString mercurialRepo(mercurialTest_BaseDir + ".hg"); 0054 const QString mercurialSrcDir(mercurialTest_BaseDir + "src/"); 0055 const QString mercurialTest_FileName("testfile"); 0056 const QString mercurialTest_FileName2("foo"); 0057 const QString mercurialTest_FileName3("bar"); 0058 0059 void verifyJobSucceed(VcsJob* job) 0060 { 0061 QVERIFY(job); 0062 QVERIFY(job->exec()); 0063 QVERIFY(job->status() == KDevelop::VcsJob::JobSucceeded); 0064 } 0065 0066 void writeToFile(const QString& path, const QString& content, QIODevice::OpenModeFlag mode = QIODevice::WriteOnly) 0067 { 0068 QFile f(path); 0069 QVERIFY(f.open(mode)); 0070 QTextStream input(&f); 0071 input << content << endl; 0072 } 0073 0074 } 0075 0076 void MercurialTest::initTestCase() 0077 { 0078 AutoTestShell::init({"kdevmercurial"}); 0079 m_testCore = new KDevelop::TestCore(); 0080 m_testCore->initialize(KDevelop::Core::NoUi); 0081 0082 m_proxy = new MercurialPlugin(m_testCore); 0083 } 0084 0085 void MercurialTest::cleanupTestCase() 0086 { 0087 delete m_proxy; 0088 0089 removeTempDirs(); 0090 } 0091 0092 void MercurialTest::init() 0093 { 0094 QDir tmpdir(tempDir); 0095 tmpdir.mkdir(mercurialTest_BaseDir); 0096 tmpdir.mkdir(mercurialSrcDir); 0097 tmpdir.mkdir(mercurialTest_BaseDir2); 0098 } 0099 0100 void MercurialTest::cleanup() 0101 { 0102 removeTempDirs(); 0103 } 0104 0105 void MercurialTest::repoInit() 0106 { 0107 qCDebug(PLUGIN_MERCURIAL) << "Trying to init repo"; 0108 // create the local repository 0109 VcsJob *j = m_proxy->init(QUrl::fromLocalFile(mercurialTest_BaseDir)); 0110 verifyJobSucceed(j); 0111 QVERIFY(QFileInfo(mercurialRepo).exists()); 0112 0113 QVERIFY(m_proxy->isValidDirectory(QUrl::fromLocalFile(mercurialTest_BaseDir))); 0114 QVERIFY(!m_proxy->isValidDirectory(QUrl::fromLocalFile("/tmp"))); 0115 } 0116 0117 void MercurialTest::addFiles() 0118 { 0119 qCDebug(PLUGIN_MERCURIAL) << "Adding files to the repo"; 0120 0121 writeToFile(mercurialTest_BaseDir + mercurialTest_FileName, "commit 0 content"); 0122 writeToFile(mercurialTest_BaseDir + mercurialTest_FileName2, "commit 0 content, foo"); 0123 0124 VcsJob *j = m_proxy->status({QUrl::fromLocalFile(mercurialTest_BaseDir)}, KDevelop::IBasicVersionControl::Recursive); 0125 verifyJobSucceed(j); 0126 auto statusResults = j->fetchResults().toList(); 0127 QCOMPARE(statusResults.size(), 2); 0128 auto status = statusResults[0].value<VcsStatusInfo>(); 0129 QCOMPARE(status.url(), QUrl::fromLocalFile(mercurialTest_BaseDir + mercurialTest_FileName2)); 0130 QCOMPARE(status.state(), VcsStatusInfo::ItemUnknown); 0131 status = statusResults[1].value<VcsStatusInfo>(); 0132 QCOMPARE(status.url(), QUrl::fromLocalFile(mercurialTest_BaseDir + mercurialTest_FileName)); 0133 QCOMPARE(status.state(), VcsStatusInfo::ItemUnknown); 0134 0135 j = m_proxy->add({QUrl::fromLocalFile(mercurialTest_BaseDir)}, KDevelop::IBasicVersionControl::NonRecursive); 0136 QVERIFY(!j); 0137 0138 // /tmp/kdevMercurial_testdir/ and kdevMercurial_testdir 0139 //add always should use aboslute path to the any directory of the repository, let's check: 0140 j = m_proxy->add({QUrl::fromLocalFile(mercurialTest_BaseDir), QUrl::fromLocalFile(MercurialTestDir1)}, KDevelop::IBasicVersionControl::Recursive); 0141 verifyJobSucceed(j); 0142 0143 // /tmp/kdevMercurial_testdir/ and testfile 0144 j = m_proxy->add({QUrl::fromLocalFile(mercurialTest_BaseDir + mercurialTest_FileName)}, KDevelop::IBasicVersionControl::Recursive); 0145 verifyJobSucceed(j); 0146 0147 writeToFile(mercurialSrcDir + mercurialTest_FileName3, "commit 0 content, bar"); 0148 0149 j = m_proxy->status({QUrl::fromLocalFile(mercurialTest_BaseDir)}, KDevelop::IBasicVersionControl::Recursive); 0150 verifyJobSucceed(j); 0151 statusResults = j->fetchResults().toList(); 0152 QCOMPARE(statusResults.size(), 3); 0153 status = statusResults[0].value<VcsStatusInfo>(); 0154 QCOMPARE(status.url(), QUrl::fromLocalFile(mercurialTest_BaseDir + mercurialTest_FileName2)); 0155 QCOMPARE(status.state(), VcsStatusInfo::ItemAdded); 0156 status = statusResults[1].value<VcsStatusInfo>(); 0157 QCOMPARE(status.url(), QUrl::fromLocalFile(mercurialTest_BaseDir + mercurialTest_FileName)); 0158 QCOMPARE(status.state(), VcsStatusInfo::ItemAdded); 0159 status = statusResults[2].value<VcsStatusInfo>(); 0160 QCOMPARE(status.url(), QUrl::fromLocalFile(mercurialSrcDir + mercurialTest_FileName3)); 0161 QCOMPARE(status.state(), VcsStatusInfo::ItemUnknown); 0162 0163 // repository path without trailing slash and a file in a parent directory 0164 // /tmp/repo and /tmp/repo/src/bar 0165 j = m_proxy->add({QUrl::fromLocalFile(mercurialSrcDir + mercurialTest_FileName3)}); 0166 verifyJobSucceed(j); 0167 0168 // let's use absolute path, because it's used in ContextMenus 0169 j = m_proxy->add({QUrl::fromLocalFile(mercurialTest_BaseDir + mercurialTest_FileName2)}, KDevelop::IBasicVersionControl::Recursive); 0170 verifyJobSucceed(j); 0171 0172 //Now let's create several files and try "hg add file1 file2 file3" 0173 writeToFile(mercurialTest_BaseDir + "file1", "file1"); 0174 writeToFile(mercurialTest_BaseDir + "file2", "file2"); 0175 0176 j = m_proxy->add({QUrl::fromLocalFile(mercurialTest_BaseDir + "file1"), QUrl::fromLocalFile(mercurialTest_BaseDir + "file2")}, KDevelop::IBasicVersionControl::Recursive); 0177 verifyJobSucceed(j); 0178 } 0179 0180 void MercurialTest::commitFiles() 0181 { 0182 qCDebug(PLUGIN_MERCURIAL) << "Committing..."; 0183 0184 VcsJob *j = m_proxy->commit(QString("commit 0"), {QUrl::fromLocalFile(mercurialTest_BaseDir)}, KDevelop::IBasicVersionControl::Recursive); 0185 verifyJobSucceed(j); 0186 0187 j = m_proxy->status({QUrl::fromLocalFile(mercurialTest_BaseDir)}, KDevelop::IBasicVersionControl::Recursive); 0188 verifyJobSucceed(j); 0189 0190 // Test the results of the "mercurial add" 0191 DVcsJob *jobLs = new DVcsJob(mercurialTest_BaseDir, nullptr); 0192 *jobLs << "hg" << "stat" << "-q" << "-c" << "-n"; 0193 verifyJobSucceed(jobLs); 0194 0195 QStringList files = jobLs->output().split("\n"); 0196 QVERIFY(files.contains(mercurialTest_FileName)); 0197 QVERIFY(files.contains(mercurialTest_FileName2)); 0198 QVERIFY(files.contains("src/" + mercurialTest_FileName3)); 0199 0200 qCDebug(PLUGIN_MERCURIAL) << "Committing one more time"; 0201 0202 // let's try to change the file and test "hg commit -a" 0203 writeToFile(mercurialTest_BaseDir + mercurialTest_FileName, "commit 1 content", QIODevice::Append); 0204 0205 j = m_proxy->add({QUrl::fromLocalFile(mercurialTest_BaseDir + mercurialTest_FileName)}, KDevelop::IBasicVersionControl::Recursive); 0206 verifyJobSucceed(j); 0207 0208 j = m_proxy->commit(QString("commit 1"), {QUrl::fromLocalFile(mercurialTest_BaseDir)}, KDevelop::IBasicVersionControl::Recursive); 0209 verifyJobSucceed(j); 0210 } 0211 0212 void MercurialTest::cloneRepository() 0213 { 0214 // make job that clones the local repository, created in the previous test 0215 VcsJob *j = m_proxy->createWorkingCopy(VcsLocation(mercurialTest_BaseDir), QUrl::fromLocalFile(mercurialTest_BaseDir2)); 0216 verifyJobSucceed(j); 0217 QVERIFY(QFileInfo(QString(mercurialTest_BaseDir2 + "/.hg/")).exists()); 0218 } 0219 0220 void MercurialTest::testInit() 0221 { 0222 repoInit(); 0223 } 0224 0225 void MercurialTest::testAdd() 0226 { 0227 repoInit(); 0228 addFiles(); 0229 } 0230 0231 void MercurialTest::testCommit() 0232 { 0233 repoInit(); 0234 addFiles(); 0235 commitFiles(); 0236 } 0237 0238 void MercurialTest::testBranching() 0239 { 0240 repoInit(); 0241 addFiles(); 0242 commitFiles(); 0243 0244 auto j = m_proxy->branches(QUrl::fromLocalFile(mercurialTest_BaseDir)); 0245 verifyJobSucceed(j); 0246 auto branches = j->fetchResults().toList(); 0247 QCOMPARE(branches.size(), 1); 0248 QVERIFY(branches.first().toString().startsWith(QStringLiteral("default"))); 0249 0250 // add branch 0251 j = m_proxy->branch(QUrl::fromLocalFile(mercurialTest_BaseDir), VcsRevision::createSpecialRevision(VcsRevision::Head), "test"); 0252 verifyJobSucceed(j); 0253 j = m_proxy->commit(QString("commit 0"), {QUrl::fromLocalFile(mercurialTest_BaseDir)}, KDevelop::IBasicVersionControl::Recursive); 0254 verifyJobSucceed(j); 0255 j = m_proxy->branches(QUrl::fromLocalFile(mercurialTest_BaseDir)); 0256 verifyJobSucceed(j); 0257 branches = j->fetchResults().toList(); 0258 std::sort(branches.begin(), branches.end()); 0259 QCOMPARE(branches.size(), 2); 0260 QVERIFY(branches.first().toString().startsWith(QStringLiteral("default"))); 0261 QVERIFY(branches.last().toString().startsWith(QStringLiteral("test"))); 0262 0263 // switch branch 0264 j = m_proxy->currentBranch(QUrl::fromLocalFile(mercurialTest_BaseDir)); 0265 verifyJobSucceed(j); 0266 branches = j->fetchResults().toList(); 0267 QCOMPARE(branches.size(), 1); 0268 QVERIFY(branches.first().toString().startsWith(QStringLiteral("test"))); 0269 j = m_proxy->switchBranch(QUrl::fromLocalFile(mercurialTest_BaseDir), QStringLiteral("default")); 0270 verifyJobSucceed(j); 0271 j = m_proxy->currentBranch(QUrl::fromLocalFile(mercurialTest_BaseDir)); 0272 verifyJobSucceed(j); 0273 branches = j->fetchResults().toList(); 0274 QCOMPARE(branches.size(), 1); 0275 QVERIFY(branches.first().toString().startsWith(QStringLiteral("default"))); 0276 0277 // commit + merge 0278 writeToFile(mercurialTest_BaseDir + mercurialTest_FileName, "commit 2 content"); 0279 j = m_proxy->commit(QString("commit 2"), {QUrl::fromLocalFile(mercurialTest_BaseDir)}, KDevelop::IBasicVersionControl::Recursive); 0280 verifyJobSucceed(j); 0281 j = m_proxy->switchBranch(QUrl::fromLocalFile(mercurialTest_BaseDir), QStringLiteral("test")); 0282 verifyJobSucceed(j); 0283 j = m_proxy->mergeBranch(QUrl::fromLocalFile(mercurialTest_BaseDir), QStringLiteral("default")); 0284 verifyJobSucceed(j); 0285 j = m_proxy->commit(QString("Merge default"), {QUrl::fromLocalFile(mercurialTest_BaseDir)}, KDevelop::IBasicVersionControl::Recursive); 0286 verifyJobSucceed(j); 0287 auto commits = m_proxy->allCommits(mercurialTest_BaseDir); 0288 QCOMPARE(commits.count(), 5); 0289 QCOMPARE(commits[0].log(), QString("Merge default")); 0290 QCOMPARE(commits[0].parents().size(), 2); 0291 } 0292 0293 void MercurialTest::testRevisionHistory() 0294 { 0295 repoInit(); 0296 addFiles(); 0297 commitFiles(); 0298 0299 const auto commits = m_proxy->allCommits(mercurialTest_BaseDir); 0300 QCOMPARE(commits.count(), 2); 0301 QCOMPARE(commits[0].parents().size(), 1); //initial commit is on the top 0302 QVERIFY(commits[1].parents().isEmpty()); //0 is later than 1! 0303 QCOMPARE(commits[0].log(), QString("commit 1")); //0 is later than 1! 0304 QCOMPARE(commits[1].log(), QString("commit 0")); 0305 QVERIFY(commits[1].commit().contains(QRegExp("^\\w{,40}$"))); 0306 QVERIFY(commits[0].commit().contains(QRegExp("^\\w{,40}$"))); 0307 QVERIFY(commits[0].parents()[0].contains(QRegExp("^\\w{,40}$"))); 0308 } 0309 0310 void MercurialTest::removeTempDirs() 0311 { 0312 if (QFileInfo(mercurialTest_BaseDir).exists()) 0313 if (!(KIO::del(QUrl::fromLocalFile(mercurialTest_BaseDir))->exec())) 0314 qCDebug(PLUGIN_MERCURIAL) << "KIO::del(" << mercurialTest_BaseDir << ") returned false"; 0315 0316 if (QFileInfo(mercurialTest_BaseDir2).exists()) 0317 if (!(KIO::del(QUrl::fromLocalFile(mercurialTest_BaseDir2))->exec())) 0318 qCDebug(PLUGIN_MERCURIAL) << "KIO::del(" << mercurialTest_BaseDir2 << ") returned false"; 0319 } 0320 0321 void MercurialTest::testAnnotate() 0322 { 0323 repoInit(); 0324 addFiles(); 0325 commitFiles(); 0326 0327 // TODO: Check annotation with a lot of commits (> 200) 0328 VcsRevision revision; 0329 revision.setRevisionValue(0, KDevelop::VcsRevision::GlobalNumber); 0330 auto job = m_proxy->annotate(QUrl::fromLocalFile(mercurialTest_BaseDir + mercurialTest_FileName), revision); 0331 verifyJobSucceed(job); 0332 0333 auto results = job->fetchResults().toList(); 0334 QCOMPARE(results.size(), 2); 0335 0336 auto commit0 = results[0].value<VcsAnnotationLine>(); 0337 QCOMPARE(commit0.text(), QStringLiteral("commit 0 content")); 0338 QCOMPARE(commit0.lineNumber(), 0); 0339 QVERIFY(commit0.date().isValid()); 0340 QCOMPARE(commit0.revision().revisionValue().toLongLong(), 0); 0341 0342 auto commit1 = results[1].value<VcsAnnotationLine>(); 0343 QCOMPARE(commit1.text(), QStringLiteral("commit 1 content")); 0344 QCOMPARE(commit1.lineNumber(), 1); 0345 QVERIFY(commit1.date().isValid()); 0346 QCOMPARE(commit1.revision().revisionValue().toLongLong(), 1); 0347 0348 // Let's change a file without commiting it 0349 writeToFile(mercurialTest_BaseDir + mercurialTest_FileName, "commit 2 content (temporary)", QIODevice::Append); 0350 0351 job = m_proxy->annotate(QUrl::fromLocalFile(mercurialTest_BaseDir + mercurialTest_FileName), revision); 0352 verifyJobSucceed(job); 0353 0354 results = job->fetchResults().toList(); 0355 QCOMPARE(results.size(), 3); 0356 auto commit2 = results[2].value<VcsAnnotationLine>(); 0357 QCOMPARE(commit2.text(), QStringLiteral("commit 2 content (temporary)")); 0358 QCOMPARE(commit2.lineNumber(), 2); 0359 QVERIFY(commit2.date().isValid()); 0360 QCOMPARE(commit2.revision().revisionValue().toLongLong(), 2); 0361 QCOMPARE(commit2.author(), QStringLiteral("not.committed.yet")); 0362 QCOMPARE(commit2.commitMessage(), QStringLiteral("Not Committed Yet")); 0363 0364 // Check that commit 2 is stripped and mercurialTest_FileName is still modified 0365 job = m_proxy->status({QUrl::fromLocalFile(mercurialTest_BaseDir + mercurialTest_FileName)}, KDevelop::IBasicVersionControl::Recursive); 0366 verifyJobSucceed(job); 0367 0368 auto statusResults = job->fetchResults().toList(); 0369 QCOMPARE(statusResults.size(), 1); 0370 auto status = statusResults[0].value<VcsStatusInfo>(); 0371 QCOMPARE(status.url(), QUrl::fromLocalFile(mercurialTest_BaseDir + mercurialTest_FileName)); 0372 QCOMPARE(status.state(), VcsStatusInfo::ItemModified); 0373 } 0374 0375 void MercurialTest::testDiff() 0376 { 0377 repoInit(); 0378 addFiles(); 0379 commitFiles(); 0380 0381 writeToFile(mercurialTest_BaseDir + mercurialTest_FileName, "commit 2 content (temporary)", QIODevice::Append); 0382 0383 VcsRevision srcrev = VcsRevision::createSpecialRevision(VcsRevision::Base); 0384 VcsRevision dstrev = VcsRevision::createSpecialRevision(VcsRevision::Working); 0385 VcsJob* j = m_proxy->diff(QUrl::fromLocalFile(mercurialTest_BaseDir), srcrev, dstrev, IBasicVersionControl::Recursive); 0386 verifyJobSucceed(j); 0387 0388 KDevelop::VcsDiff d = j->fetchResults().value<KDevelop::VcsDiff>(); 0389 QCOMPARE(d.baseDiff().toLocalFile(), mercurialTest_BaseDir.left(mercurialTest_BaseDir.size() - 1)); 0390 QVERIFY(d.diff().contains(QUrl::fromLocalFile(mercurialTest_BaseDir + mercurialTest_FileName).toLocalFile())); 0391 } 0392 0393 void MercurialTest::testAnnotateFailed() 0394 { 0395 repoInit(); 0396 addFiles(); 0397 commitFiles(); 0398 0399 auto verifyAnnotateJobFailed = [this](MercurialAnnotateJob::TestCase test) 0400 { 0401 VcsRevision revision; 0402 revision.setRevisionValue(0, KDevelop::VcsRevision::GlobalNumber); 0403 auto job = m_proxy->annotate(QUrl::fromLocalFile(mercurialTest_BaseDir + mercurialTest_FileName), revision); 0404 auto annotateJob = dynamic_cast<MercurialAnnotateJob*>(job); 0405 QVERIFY(annotateJob); 0406 annotateJob->m_testCase = test; 0407 0408 QVERIFY(job->exec()); 0409 QVERIFY(job->status() == KDevelop::VcsJob::JobFailed); 0410 }; 0411 verifyAnnotateJobFailed(MercurialAnnotateJob::TestCase::Status); 0412 //verifyAnnotateJobFailed(MercurialAnnotateJob::TestCase::Commit); 0413 verifyAnnotateJobFailed(MercurialAnnotateJob::TestCase::Annotate); 0414 verifyAnnotateJobFailed(MercurialAnnotateJob::TestCase::Log); 0415 //verifyAnnotateJobFailed(MercurialAnnotateJob::TestCase::Strip); 0416 } 0417 0418 void MercurialTest::testHeads() 0419 { 0420 repoInit(); 0421 addFiles(); 0422 commitFiles(); 0423 0424 VcsRevision revision; 0425 revision.setRevisionValue(0, KDevelop::VcsRevision::GlobalNumber); 0426 auto job = m_proxy->checkoutHead(QUrl::fromLocalFile(mercurialTest_BaseDir), revision); 0427 verifyJobSucceed(job); 0428 0429 writeToFile(mercurialTest_BaseDir + mercurialTest_FileName, "new head content", QIODevice::Append); 0430 0431 auto j = m_proxy->commit(QString("new head"), {QUrl::fromLocalFile(mercurialTest_BaseDir)}, KDevelop::IBasicVersionControl::Recursive); 0432 verifyJobSucceed(j); 0433 0434 QScopedPointer<MercurialHeadsModel> headsModel(new MercurialHeadsModel(m_proxy, QUrl::fromLocalFile(mercurialTest_BaseDir), nullptr)); 0435 headsModel->update(); 0436 0437 QSignalSpy waiter(headsModel.data(), &MercurialHeadsModel::updateComplete); 0438 QVERIFY(waiter.wait()); 0439 QVERIFY(waiter.count() == 1); 0440 0441 QCOMPARE(headsModel->rowCount(), 2); 0442 auto rev2 = headsModel->data(headsModel->index(0, VcsBasicEventModel::RevisionColumn)).toLongLong(); 0443 auto rev1 = headsModel->data(headsModel->index(1, VcsBasicEventModel::RevisionColumn)).toLongLong(); 0444 QCOMPARE(rev2, 2); 0445 QCOMPARE(rev1, 1); 0446 } 0447 0448 QTEST_MAIN(MercurialTest)