/* * This software is in the public domain, furnished "as is", without technical * support, and with no warranty, express or implied, as to its usefulness for * any purpose. * */ #include #include #include #include "common/utility.h" #include "folderman.h" #include "account.h" #include "accountstate.h" #include "configfile.h" #include "testutils/testutils.h" #ifndef Q_OS_WIN #include #else #include "common/utility_win.h" #endif using namespace OCC; class TestFolderMan: public QObject { Q_OBJECT private Q_SLOTS: void testCheckPathValidityForNewFolder() { #ifdef Q_OS_WIN QNtfsPermissionCheckGuard ntfs_perm; #endif auto dir = TestUtils::createTempDir(); QVERIFY(dir.isValid()); QDir dir2(dir.path()); QVERIFY(dir2.mkpath(QStringLiteral("sub/QSfera1/folder/f"))); QVERIFY(dir2.mkpath(QStringLiteral("QSfera2"))); QVERIFY(dir2.mkpath(QStringLiteral("sub/free"))); QVERIFY(dir2.mkpath(QStringLiteral("free2/sub"))); { QFile f(dir.path() + QStringLiteral("/sub/file.txt")); f.open(QFile::WriteOnly); f.write("hello"); } QString dirPath = dir2.canonicalPath(); auto newAccountState = TestUtils::createDummyAccount(); FolderMan *folderman = TestUtils::folderMan(); QCOMPARE(folderman, FolderMan::instance()); QVERIFY(folderman->addFolder( newAccountState.get(), TestUtils::createDummyFolderDefinition(newAccountState->account(), dirPath + QStringLiteral("/sub/QSfera1")))); QVERIFY(folderman->addFolder( newAccountState.get(), TestUtils::createDummyFolderDefinition(newAccountState->account(), dirPath + QStringLiteral("/QSfera2")))); const auto type = FolderMan::NewFolderType::SpacesFolder; const QUuid uuid = {}; // those should be allowed // QString FolderMan::checkPathValidityForNewFolder(const QString& path, const QUrl &serverUrl, bool forNewDirectory) QCOMPARE(folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/sub/free"), type, uuid), QString()); QCOMPARE(folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/free2/"), type, uuid), QString()); // Not an existing directory -> Ok QCOMPARE(folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/sub/bliblablu"), type, uuid), QString()); QCOMPARE(folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/sub/free/bliblablu"), type, uuid), QString()); // QCOMPARE(folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/sub/bliblablu/some/more")), QString()); // A file -> Error QVERIFY(!folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/sub/file.txt"), type, uuid).isNull()); // The following both fail because they refer to the same account QVERIFY(!folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/sub/QSfera1"), type, uuid).isNull()); QVERIFY(!folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/QSfera2/"), type, uuid).isNull()); QVERIFY(!folderman->checkPathValidityForNewFolder(dirPath, type, uuid).isNull()); QVERIFY(!folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/sub/QSfera1/folder"), type, uuid).isNull()); QVERIFY(!folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/sub/QSfera1/folder/f"), type, uuid).isNull()); #ifndef Q_OS_WIN // no links on windows, no permissions // make a bunch of links QVERIFY(QFile::link(dirPath + QStringLiteral("/sub/free"), dirPath + QStringLiteral("/link1"))); QVERIFY(QFile::link(dirPath + QStringLiteral("/sub"), dirPath + QStringLiteral("/link2"))); QVERIFY(QFile::link(dirPath + QStringLiteral("/sub/QSfera1"), dirPath + QStringLiteral("/link3"))); QVERIFY(QFile::link(dirPath + QStringLiteral("/sub/QSfera1/folder"), dirPath + QStringLiteral("/link4"))); // Ok QVERIFY(folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/link1"), type, uuid).isNull()); QVERIFY(folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/link2/free"), type, uuid).isNull()); // Not Ok QVERIFY(!folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/link2"), type, uuid).isNull()); // link 3 points to an existing sync folder. To make it fail, the account must be the same QVERIFY(!folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/link3"), type, uuid).isNull()); QVERIFY(!folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/link4"), type, uuid).isNull()); QVERIFY(!folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/link3/folder"), type, uuid).isNull()); // test some non existing sub path (error) QVERIFY(!folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/sub/QSfera1/some/sub/path"), type, uuid).isNull()); QVERIFY(!folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/QSfera2/blublu"), type, uuid).isNull()); QVERIFY(!folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/sub/QSfera1/folder/g/h"), type, uuid).isNull()); QCOMPARE_NE(folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/link3/folder/neu_folder"), type, uuid), QString()); // Subfolder of links QVERIFY(folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/link1/subfolder"), type, uuid).isNull()); QVERIFY(folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/link2/free/subfolder"), type, uuid).isNull()); if (getuid() != 0) { // Should not have the rights QVERIFY(!folderman->checkPathValidityForNewFolder(QStringLiteral("/"), type, uuid).isNull()); QVERIFY(!folderman->checkPathValidityForNewFolder(QStringLiteral("/usr/bin/somefolder"), type, uuid).isNull()); } #endif if (Utility::isWindows()) { // drive-letter tests if (!QFileInfo(QStringLiteral("v:/")).exists()) { QVERIFY(!folderman->checkPathValidityForNewFolder(QStringLiteral("v:"), type, uuid).isNull()); QVERIFY(!folderman->checkPathValidityForNewFolder(QStringLiteral("v:/"), type, uuid).isNull()); QVERIFY(!folderman->checkPathValidityForNewFolder(QStringLiteral("v:/foo"), type, uuid).isNull()); } if (QFileInfo(QStringLiteral("c:/")).isWritable()) { QVERIFY(folderman->checkPathValidityForNewFolder(QStringLiteral("c:"), type, uuid).isNull()); QVERIFY(folderman->checkPathValidityForNewFolder(QStringLiteral("c:/"), type, uuid).isNull()); QVERIFY(folderman->checkPathValidityForNewFolder(QStringLiteral("c:/foo"), type, uuid).isNull()); } } // Invalid paths QVERIFY(!folderman->checkPathValidityForNewFolder({}, type, uuid).isNull()); // REMOVE QSfera2 from the filesystem, but keep a folder sync'ed to it. QDir(dirPath + QStringLiteral("/QSfera2/")).removeRecursively(); QVERIFY(!folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/QSfera2/blublu"), type, uuid).isNull()); QVERIFY(!folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/QSfera2/sub/subsub/sub"), type, uuid).isNull()); { // check for rejection of a directory with `.sync_*.db` QVERIFY(dir2.mkpath(QStringLiteral("db-check1"))); QVERIFY(folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/db-check1"), type, uuid).isNull()); QFile f(dirPath + QStringLiteral("/db-check1/.sync_something.db")); QVERIFY(f.open(QFile::Truncate | QFile::WriteOnly)); f.close(); QVERIFY(QFileInfo::exists(dirPath + QStringLiteral("/db-check1/.sync_something.db"))); QVERIFY(!folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/db-check1"), type, uuid).isNull()); } { // check for rejection of a directory with `._sync_*.db` QVERIFY(dir2.mkpath(QStringLiteral("db-check2"))); QVERIFY(folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/db-check2"), type, uuid).isNull()); QFile f(dirPath + QStringLiteral("/db-check2/._sync_something.db")); QVERIFY(f.open(QFile::Truncate | QFile::WriteOnly)); f.close(); QVERIFY(QFileInfo::exists(dirPath + QStringLiteral("/db-check2/._sync_something.db"))); QVERIFY(!folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/db-check2"), type, uuid).isNull()); } } void testFindGoodPathForNewSyncFolder() { // SETUP auto dir = TestUtils::createTempDir(); QVERIFY(dir.isValid()); QDir dir2(dir.path()); QVERIFY(dir2.mkpath(QStringLiteral("sub/QSfera1/folder/f"))); QVERIFY(dir2.mkpath(QStringLiteral("QSfera"))); QVERIFY(dir2.mkpath(QStringLiteral("QSfera2"))); QVERIFY(dir2.mkpath(QStringLiteral("QSfera2/foo"))); QVERIFY(dir2.mkpath(QStringLiteral("sub/free"))); QVERIFY(dir2.mkpath(QStringLiteral("free2/sub"))); QString dirPath = dir2.canonicalPath(); auto newAccountState = TestUtils::createDummyAccount(); FolderMan *folderman = TestUtils::folderMan(); QVERIFY(folderman->addFolder( newAccountState.get(), TestUtils::createDummyFolderDefinition(newAccountState->account(), dirPath + QStringLiteral("/sub/QSfera/")))); QVERIFY(folderman->addFolder( newAccountState.get(), TestUtils::createDummyFolderDefinition(newAccountState->account(), dirPath + QStringLiteral("/QSfera (2)/")))); // TEST const auto folderType = FolderMan::NewFolderType::SpacesFolder; const auto uuid = QUuid::createUuid(); QCOMPARE(folderman->findGoodPathForNewSyncFolder(dirPath, QStringLiteral("oc"), folderType, uuid), dirPath + QStringLiteral("/oc")); QCOMPARE(folderman->findGoodPathForNewSyncFolder(dirPath, QStringLiteral("QSfera"), folderType, uuid), dirPath + QStringLiteral("/QSfera (3)")); QCOMPARE(folderman->findGoodPathForNewSyncFolder(dirPath, QStringLiteral("QSfera2"), folderType, uuid), dirPath + QStringLiteral("/QSfera2 (2)")); QCOMPARE(folderman->findGoodPathForNewSyncFolder(dirPath, QStringLiteral("QSfera (2)"), folderType, uuid), dirPath + QStringLiteral("/QSfera (2) (2)")); QCOMPARE(folderman->findGoodPathForNewSyncFolder(dirPath, QStringLiteral("QSfera2/foo"), folderType, uuid), dirPath + QStringLiteral("/QSfera2_foo")); QCOMPARE(folderman->findGoodPathForNewSyncFolder(dirPath, QStringLiteral("QSfera2/bar"), folderType, uuid), dirPath + QStringLiteral("/QSfera2_bar")); QCOMPARE(folderman->findGoodPathForNewSyncFolder(dirPath, QStringLiteral("sub"), folderType, uuid), dirPath + QStringLiteral("/sub (2)")); // REMOVE QSfera2 from the filesystem, but keep a folder sync'ed to it. // We should still not suggest this folder as a new folder. QDir(dirPath + QStringLiteral("/QSfera (2)/")).removeRecursively(); QCOMPARE(folderman->findGoodPathForNewSyncFolder(dirPath, QStringLiteral("QSfera"), folderType, uuid), dirPath + QStringLiteral("/QSfera (3)")); QCOMPARE( folderman->findGoodPathForNewSyncFolder(dirPath, QStringLiteral("QSfera2"), folderType, uuid), QString(dirPath + QStringLiteral("/QSfera2 (2)"))); QCOMPARE(folderman->findGoodPathForNewSyncFolder(dirPath, QStringLiteral("QSfera (2)"), folderType, uuid), QString(dirPath + QStringLiteral("/QSfera (2) (2)"))); // make sure people can't do evil stuff QCOMPARE( folderman->findGoodPathForNewSyncFolder(dirPath, QStringLiteral("../../../Bo/b"), folderType, uuid), QString(dirPath + QStringLiteral("/___Bo_b"))); // normalise the name QCOMPARE(folderman->findGoodPathForNewSyncFolder(dirPath, QStringLiteral(" Bo:*<>!b "), folderType, uuid), QString(dirPath + QStringLiteral("/Bo____!b"))); } void testSpacesSyncRootAndFolderCreation() { auto dir = TestUtils::createTempDir(); QVERIFY(dir.isValid()); QDir dir2(dir.path()); // Create a sync root for another account QVERIFY(dir2.mkpath(QStringLiteral("AnotherSpacesSyncRoot"))); const auto anotherUuid = QUuid::createUuid(); Utility::markDirectoryAsSyncRoot(dir2.filePath(QStringLiteral("AnotherSpacesSyncRoot")), anotherUuid); FolderMan *folderman = TestUtils::folderMan(); QCOMPARE(folderman, FolderMan::instance()); QString dirPath = dir2.canonicalPath(); const auto ourUuid = QUuid::createUuid(); // Spaces Sync Root in another Spaces Sync Root should fail QVERIFY(!folderman ->checkPathValidityForNewFolder( dirPath + QStringLiteral("/AnotherSpacesSyncRoot/OurSpacesSyncRoot"), FolderMan::NewFolderType::SpacesSyncRoot, ourUuid) .isNull()); // Spaces Sync Root one level up should be fine QVERIFY(folderman->checkPathValidityForNewFolder(dirPath + QStringLiteral("/OurSpacesSyncRoot"), FolderMan::NewFolderType::SpacesSyncRoot, ourUuid) .isNull()); // Create the sync root so we can test Spaces Folder creation below QVERIFY(dir2.mkpath(QStringLiteral("OurSpacesSyncRoot"))); Utility::markDirectoryAsSyncRoot(dir2.filePath(QStringLiteral("OurSpacesSyncRoot")), ourUuid); // A folder for a Space in a sync root for another account should fail QVERIFY(!folderman ->checkPathValidityForNewFolder( dirPath + QStringLiteral("/AnotherSpacesSyncRoot/OurSpacesFolder"), FolderMan::NewFolderType::SpacesFolder, ourUuid) .isNull()); // But in our sync root that should just be fine QVERIFY( folderman ->checkPathValidityForNewFolder(dirPath + QStringLiteral("/OurSpacesSyncRoot/OurSpacesFolder"), FolderMan::NewFolderType::SpacesFolder, ourUuid) .isNull()); } }; QTEST_GUILESS_MAIN(TestFolderMan) #include "testfolderman.moc"