File indexing completed on 2024-04-28 05:50:34

0001 /*
0002     SPDX-FileCopyrightText: 2008 Robert Knight <robertknight@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 // Own
0008 #include "ProfileTest.h"
0009 
0010 // Qt
0011 #include <QFile>
0012 #include <QFileInfo>
0013 #include <QStandardPaths>
0014 #include <QTemporaryFile>
0015 #include <QTest>
0016 #include <QTextStream>
0017 
0018 // KDE
0019 
0020 // Konsole
0021 #include "../profile/Profile.h"
0022 #include "../profile/ProfileGroup.h"
0023 #include "../profile/ProfileManager.cpp"
0024 #include "../profile/ProfileReader.h"
0025 #include "../profile/ProfileWriter.h"
0026 
0027 #include <QStandardPaths>
0028 
0029 #include <array>
0030 
0031 using namespace Konsole;
0032 
0033 void ProfileTest::initTestCase()
0034 {
0035     QStandardPaths::setTestModeEnabled(true);
0036 }
0037 
0038 void ProfileTest::testProfile()
0039 {
0040     // create a new profile
0041     Profile *parent = new Profile;
0042     parent->setProperty(Profile::Name, QStringLiteral("Parent"));
0043     parent->setProperty(Profile::Path, QStringLiteral("FakePath"));
0044 
0045     parent->setProperty(Profile::AntiAliasFonts, false);
0046     parent->setProperty(Profile::StartInCurrentSessionDir, false);
0047 
0048     parent->setProperty(Profile::UseCustomCursorColor, true);
0049     QVERIFY(parent->useCustomCursorColor());
0050     QCOMPARE(parent->customCursorColor(), QColor());
0051     QCOMPARE(parent->customCursorTextColor(), QColor());
0052     parent->setProperty(Profile::UseCustomCursorColor, false);
0053     QVERIFY(!parent->useCustomCursorColor());
0054     QCOMPARE(parent->customCursorColor(), QColor());
0055     QCOMPARE(parent->customCursorTextColor(), QColor());
0056 
0057     // create a child profile
0058     Profile *child = new Profile(Profile::Ptr(parent));
0059     child->setProperty(Profile::StartInCurrentSessionDir, true);
0060 
0061     // check which properties are set
0062     QVERIFY(parent->isPropertySet(Profile::Name));
0063     QVERIFY(parent->isPropertySet(Profile::Path));
0064     QVERIFY(parent->isPropertySet(Profile::AntiAliasFonts));
0065     QVERIFY(!parent->isPropertySet(Profile::Icon));
0066     QVERIFY(!parent->isPropertySet(Profile::Command));
0067     QVERIFY(!parent->isPropertySet(Profile::Arguments));
0068 
0069     QVERIFY(child->isPropertySet(Profile::StartInCurrentSessionDir));
0070     QVERIFY(!child->isPropertySet(Profile::Name));
0071     QVERIFY(!child->isPropertySet(Profile::AntiAliasFonts));
0072     QVERIFY(!child->isPropertySet(Profile::ColorScheme));
0073 
0074     // read non-inheritable properties
0075     QCOMPARE(parent->property<QString>(Profile::Name), QStringLiteral("Parent"));
0076     QCOMPARE(child->property<QVariant>(Profile::Name), QVariant());
0077     QCOMPARE(parent->property<QString>(Profile::Path), QStringLiteral("FakePath"));
0078     QCOMPARE(child->property<QVariant>(Profile::Path), QVariant());
0079 
0080     // read inheritable properties
0081     QVERIFY(!parent->property<bool>(Profile::AntiAliasFonts));
0082     QVERIFY(!child->property<bool>(Profile::AntiAliasFonts));
0083 
0084     QVERIFY(!parent->startInCurrentSessionDir());
0085     QVERIFY(child->startInCurrentSessionDir());
0086 
0087     delete child;
0088 }
0089 
0090 void ProfileTest::testClone()
0091 {
0092     // create source profile and parent
0093     Profile::Ptr parent(new Profile);
0094     parent->setProperty(Profile::Command, QStringLiteral("ps"));
0095     parent->setProperty(Profile::ColorScheme, QStringLiteral("BlackOnWhite"));
0096 
0097     Profile::Ptr source(new Profile(parent));
0098     source->setProperty(Profile::AntiAliasFonts, false);
0099     source->setProperty(Profile::HistorySize, 4567);
0100 
0101     source->setProperty(Profile::Name, QStringLiteral("SourceProfile"));
0102     source->setProperty(Profile::Path, QStringLiteral("SourcePath"));
0103 
0104     // create target to clone source and parent
0105     Profile::Ptr targetParent(new Profile);
0106     // same value as source parent
0107     targetParent->setProperty(Profile::Command, QStringLiteral("ps"));
0108     // different value from source parent
0109     targetParent->setProperty(Profile::ColorScheme, QStringLiteral("BlackOnGrey"));
0110     Profile::Ptr target(new Profile(parent));
0111 
0112     // clone source profile, setting only properties that differ
0113     // between the source and target
0114     target->clone(source, true);
0115 
0116     // check that properties from source have been cloned into target
0117     QCOMPARE(source->property<bool>(Profile::AntiAliasFonts), target->property<bool>(Profile::AntiAliasFonts));
0118     QCOMPARE(source->property<int>(Profile::HistorySize), target->property<int>(Profile::HistorySize));
0119 
0120     // check that Name and Path properties are handled specially and not cloned
0121     QVERIFY(source->property<QString>(Profile::Name) != target->property<QString>(Profile::Name));
0122     QVERIFY(source->property<QString>(Profile::Path) != target->property<QString>(Profile::Path));
0123 
0124     // check that Command property is not set in target because the values
0125     // are the same
0126     QVERIFY(!target->isPropertySet(Profile::Command));
0127     // check that ColorScheme property is cloned because the inherited values
0128     // from the source parent and target parent differ
0129     QCOMPARE(source->property<QString>(Profile::ColorScheme), target->property<QString>(Profile::ColorScheme));
0130 }
0131 
0132 void ProfileTest::testProfileGroup()
0133 {
0134     // create three new profiles
0135     std::array<Profile::Ptr, 3> profile;
0136     for (auto &i : profile) {
0137         i = new Profile;
0138         QVERIFY(!i->asGroup());
0139     }
0140 
0141     // set properties with different values
0142     profile[0]->setProperty(Profile::UseCustomCursorColor, true);
0143     profile[1]->setProperty(Profile::UseCustomCursorColor, false);
0144 
0145     // set properties with same values
0146     for (auto &i : profile) {
0147         i->setProperty(Profile::HistorySize, 1234);
0148     }
0149 
0150     // create a group profile
0151     ProfileGroup::Ptr group = ProfileGroup::Ptr(new ProfileGroup);
0152     const ProfileGroup::Ptr group_const = ProfileGroup::Ptr(new ProfileGroup);
0153     QVERIFY(group->asGroup());
0154     QVERIFY(group_const->asGroup());
0155     for (auto &i : profile) {
0156         group->addProfile(i);
0157         QVERIFY(group->profiles().contains(i));
0158         QVERIFY(!group_const->profiles().contains(i));
0159     }
0160     group->updateValues();
0161 
0162     // read and check properties from the group
0163     QCOMPARE(group->property<int>(Profile::HistorySize), 1234);
0164     QCOMPARE(group_const->property<int>(Profile::HistorySize), 0);
0165     QCOMPARE(group->property<QVariant>(Profile::UseCustomCursorColor), QVariant());
0166     QCOMPARE(group_const->property<QVariant>(Profile::UseCustomCursorColor), QVariant());
0167 
0168     // set and test shareable properties in the group
0169     group->setProperty(Profile::Command, QStringLiteral("ssh"));
0170     group->setProperty(Profile::AntiAliasFonts, false);
0171 
0172     QCOMPARE(profile[0]->property<QString>(Profile::Command), QStringLiteral("ssh"));
0173     QVERIFY(!profile[1]->property<bool>(Profile::AntiAliasFonts));
0174 
0175     // set and test non-shareable properties in the group
0176     // (should have no effect)
0177     group->setProperty(Profile::Name, QStringLiteral("NewName"));
0178     group->setProperty(Profile::Path, QStringLiteral("NewPath"));
0179     QVERIFY(profile[1]->property<QString>(Profile::Name) != QLatin1String("NewName"));
0180     QVERIFY(profile[2]->property<QString>(Profile::Path) != QLatin1String("NewPath"));
0181 
0182     // remove a profile from the group
0183     group->removeProfile(profile[0]);
0184     QVERIFY(!group->profiles().contains(profile[0]));
0185     group->updateValues();
0186 
0187     // check that profile is no longer affected by group
0188     group->setProperty(Profile::Command, QStringLiteral("fish"));
0189     QVERIFY(profile[0]->property<QString>(Profile::Command) != QLatin1String("fish"));
0190 }
0191 
0192 // Verify the correct file name is created from the UntranslatedName
0193 void ProfileTest::testProfileFileNames()
0194 {
0195     Profile::Ptr profile = Profile::Ptr(new Profile);
0196     QFileInfo fileInfo;
0197     ProfileWriter writer;
0198 
0199     profile->setProperty(Profile::UntranslatedName, QStringLiteral("Indiana"));
0200     fileInfo.setFile(writer.getPath(profile));
0201     QCOMPARE(fileInfo.fileName(), QStringLiteral("Indiana.profile"));
0202 
0203     profile->setProperty(Profile::UntranslatedName, QStringLiteral("Old Paris"));
0204     fileInfo.setFile(writer.getPath(profile));
0205     QCOMPARE(fileInfo.fileName(), QStringLiteral("Old Paris.profile"));
0206 
0207     /* FIXME: deal w/ file systems that are case-insensitive
0208        This leads to confusion as both Test and test can appear in the Manager
0209        Profile dialog while really there is only 1 test.profile file.
0210        Suggestions:  all lowercase, testing the file system, ...
0211     */
0212     /*
0213     profile->setProperty(Profile::UntranslatedName, "New Profile");
0214     fileInfo.setFile(writer.getPath(profile));
0215     QCOMPARE(fileInfo.fileName(), QString("new profile.profile"));
0216     */
0217 
0218     /* FIXME: don't allow certain characters in file names
0219        Consider: ,^@=+{}[]~!?:&*\"|#%<>$\"'();`'/\
0220        Suggestions: changing them all to _, just remove them, ...
0221        Bug 315086 comes from a user using / in the profile name - multiple
0222          issues there.
0223     */
0224     /*
0225     profile->setProperty(Profile::UntranslatedName, "new/profile");
0226     fileInfo.setFile(writer.getPath(profile));
0227     QCOMPARE(fileInfo.fileName(), QString("new_profile.profile"));
0228     */
0229 }
0230 
0231 void ProfileTest::testProfileNameSorting()
0232 {
0233     auto *manager = ProfileManager::instance();
0234 
0235     const int origCount = manager->allProfiles().size();
0236 
0237     Profile::Ptr profile1 = Profile::Ptr(new Profile);
0238     profile1->setProperty(Profile::UntranslatedName, QStringLiteral("Indiana"));
0239     manager->addProfile(profile1);
0240     auto list = manager->allProfiles();
0241     int counter = 1;
0242     QCOMPARE(list.size(), origCount + counter++);
0243     // Built-in profile always at the top
0244     QCOMPARE(list.at(0)->name(), QStringLiteral("Built-in"));
0245 
0246     QVERIFY(std::is_sorted(list.cbegin(), list.cend(), profileNameLessThan));
0247 
0248     Profile::Ptr profile2 = Profile::Ptr(new Profile);
0249     profile2->setProperty(Profile::UntranslatedName, QStringLiteral("Old Paris"));
0250     manager->addProfile(profile2);
0251     list = manager->allProfiles();
0252     QCOMPARE(list.size(), origCount + counter++);
0253     QVERIFY(std::is_sorted(list.cbegin(), list.cend(), profileNameLessThan));
0254 
0255     Profile::Ptr profile3 = Profile::Ptr(new Profile);
0256     profile3->setProperty(Profile::UntranslatedName, QStringLiteral("New Zealand"));
0257     manager->addProfile(profile3);
0258     list = manager->allProfiles();
0259     QCOMPARE(list.size(), origCount + counter++);
0260     QVERIFY(std::is_sorted(list.cbegin(), list.cend(), profileNameLessThan));
0261 
0262     QCOMPARE(list.at(0)->name(), QStringLiteral("Built-in"));
0263 }
0264 
0265 void ProfileTest::testBuiltinProfile()
0266 {
0267     // create a new profile
0268     Profile::Ptr builtin = Profile::Ptr(new Profile);
0269     QVERIFY(!builtin->isBuiltin());
0270 
0271     builtin->useBuiltin();
0272     QVERIFY(builtin->isBuiltin());
0273     QCOMPARE(builtin->untranslatedName(), QStringLiteral("Built-in"));
0274     QCOMPARE(builtin->path(), QStringLiteral("FALLBACK/"));
0275 }
0276 
0277 void ProfileTest::testLoadProfileNamedAsBuiltin()
0278 {
0279     // Create a new profile data which is literally named "Built-in".
0280     // New code should support loading such profiles created in older versions,
0281     // but new profiles must not be saved with such name.
0282     Profile::Ptr builtin = Profile::Ptr(new Profile);
0283     builtin->useBuiltin();
0284 
0285     QString profileStr = QStringLiteral(
0286         "[General]\n"
0287         "Icon=terminator\n"
0288         "Name=Built-in\n"
0289         "Parent=FALLBACK/\n");
0290 
0291     QTemporaryFile file(QStringLiteral("konsole.XXXXXX.profile"));
0292     QVERIFY(file.open());
0293     QTextStream(&file) << profileStr;
0294 
0295     Profile::Ptr profile = Profile::Ptr(new Profile(builtin));
0296 
0297     ProfileReader reader;
0298     QString parentProfilePath;
0299     QVERIFY(reader.readProfile(file.fileName(), profile, parentProfilePath));
0300 
0301     QCOMPARE(profile->property<QString>(Profile::Icon), QStringLiteral("terminator"));
0302     // It's called "Built-in", but its parent is the real built-in profile
0303     QCOMPARE(profile->name(), builtin->name());
0304     QCOMPARE(parentProfilePath, builtin->path());
0305 }
0306 
0307 void ProfileTest::testInvalidParentProfile()
0308 {
0309     auto *manager = ProfileManager::instance();
0310 
0311     QString profileStr = QStringLiteral(
0312         "[General]\n"
0313         "Name=TestInvalidParentProfile\n"
0314         "Parent=/this/doesnt/exist/X.profile/\n");
0315 
0316     QTemporaryFile file(QStringLiteral("konsole.XXXXXX.profile"));
0317     QVERIFY(file.open());
0318     QTextStream(&file) << profileStr;
0319 
0320     auto profile = manager->loadProfile(file.fileName());
0321     QVERIFY(profile);
0322     QCOMPARE(profile->property<QString>(Profile::Name), QStringLiteral("TestInvalidParentProfile"));
0323 
0324     Profile::Ptr parent = profile->parent();
0325     QVERIFY(parent);
0326     QCOMPARE(parent->property<QString>(Profile::Name), QStringLiteral("Built-in"));
0327 }
0328 
0329 QTEST_GUILESS_MAIN(ProfileTest)
0330 
0331 #include "moc_ProfileTest.cpp"