File indexing completed on 2024-04-28 15:19:33
0001 /* This file is part of the KDE libraries 0002 SPDX-FileCopyrightText: 2010 Canonical Ltd 0003 SPDX-FileContributor: Aurélien Gâteau <aurelien.gateau@canonical.com> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 #include "test_kconf_update.h" 0008 0009 #include <memory> 0010 0011 // Qt 0012 #include "config-kconf.h" 0013 #include <QDir> 0014 #include <QFile> 0015 #include <QProcess> 0016 #include <qstandardpaths.h> 0017 #include <qtemporaryfile.h> 0018 0019 #include <qtest.h> 0020 0021 QTEST_GUILESS_MAIN(TestKConfUpdate) 0022 0023 void TestKConfUpdate::initTestCase() 0024 { 0025 QStandardPaths::setTestModeEnabled(true); 0026 0027 // Ensure it all works with spaces in paths (as happens more commonly on OSX where it's ~/Library/Application Support/) 0028 qputenv("XDG_DATA_HOME", "/tmp/a b"); 0029 } 0030 0031 static void writeFile(const QString &path, const QString &content) 0032 { 0033 QFile file(path); 0034 if (!file.open(QIODevice::WriteOnly)) { 0035 qFatal("Could not write to '%s'", qPrintable(path)); 0036 } 0037 file.write(content.toUtf8()); 0038 } 0039 0040 static QString readFile(const QString &path) 0041 { 0042 QFile file(path); 0043 if (!file.open(QIODevice::ReadOnly)) { 0044 qFatal("Could not read '%s'", qPrintable(path)); 0045 } 0046 QString ret = QString::fromUtf8(file.readAll()); 0047 #ifdef Q_OS_WIN 0048 // KConfig always writes files with the native line ending, the test comparison uses \n 0049 ret.replace(QLatin1String{"\r\n"}, QLatin1String{"\n"}); 0050 #endif 0051 return ret; 0052 } 0053 0054 static std::unique_ptr<QTemporaryFile> writeUpdFile(const QString &content) 0055 { 0056 std::unique_ptr<QTemporaryFile> file{new QTemporaryFile(QDir::tempPath() + QLatin1String("/test_kconf_update_XXXXXX.upd"))}; 0057 bool ok = file->open(); 0058 Q_UNUSED(ok) // silence warnings 0059 Q_ASSERT(ok); 0060 file->write(content.toUtf8()); 0061 file->flush(); 0062 return file; 0063 } 0064 0065 static void runKConfUpdate(const QString &updPath) 0066 { 0067 QVERIFY(QFile::exists(QStringLiteral(KCONF_UPDATE_EXECUTABLE))); 0068 QCOMPARE(0, QProcess::execute(QStringLiteral(KCONF_UPDATE_EXECUTABLE), QStringList{QStringLiteral("--testmode"), QStringLiteral("--debug"), updPath})); 0069 } 0070 0071 void TestKConfUpdate::test_data() 0072 { 0073 QTest::addColumn<QString>("updContent"); 0074 QTest::addColumn<QString>("oldConfName"); 0075 QTest::addColumn<QString>("oldConfContent"); 0076 QTest::addColumn<QString>("newConfName"); 0077 QTest::addColumn<QString>("expectedNewConfContent"); 0078 QTest::addColumn<QString>("expectedOldConfContent"); 0079 QTest::addColumn<bool>("useVersion5"); 0080 QTest::addColumn<bool>("shouldUpdateWork"); 0081 0082 QTest::newRow("moveKeysSameFile") << "File=testrc\n" 0083 "Group=group\n" 0084 "Key=old,new\n" 0085 "Options=overwrite\n" 0086 << "testrc" 0087 << "[group]\n" 0088 "old=value\n" 0089 << "testrc" 0090 << "[$Version]\n" 0091 "update_info=%1\n" 0092 "\n" 0093 "[group]\n" 0094 "new=value\n" 0095 << "" << true << true; 0096 QTest::newRow("moveKeysOtherFile") << "File=oldrc,newrc\n" 0097 "Group=group1,group2\n" 0098 "Key=old,new\n" 0099 "Options=overwrite\n" 0100 << "oldrc" 0101 << "[group1]\n" 0102 "old=value\n" 0103 "[stay]\n" 0104 "foo=bar\n" 0105 << "newrc" 0106 << "[$Version]\n" 0107 "update_info=%1\n" 0108 "\n" 0109 "[group2]\n" 0110 "new=value\n" 0111 << "[$Version]\n" 0112 "update_info=%1\n" 0113 "\n" 0114 "[stay]\n" 0115 "foo=bar\n" 0116 << true << true; 0117 QTest::newRow("allKeys") << "File=testrc\n" 0118 "Group=group1,group2\n" 0119 "AllKeys\n" 0120 << "testrc" 0121 << "[group1]\n" 0122 "key1=value1\n" 0123 "key2=value2\n" 0124 "\n" 0125 "[stay]\n" 0126 "foo=bar\n" 0127 << "testrc" 0128 << "[$Version]\n" 0129 "update_info=%1\n" 0130 "\n" 0131 "[group2]\n" 0132 "key1=value1\n" 0133 "key2=value2\n" 0134 "\n" 0135 "[stay]\n" 0136 "foo=bar\n" 0137 << "" << true << true; 0138 QTest::newRow("allKeysSubGroup") << "File=testrc\n" 0139 "Group=[group][sub1],[group][sub2]\n" 0140 "AllKeys\n" 0141 << "testrc" 0142 << "[group][sub1]\n" 0143 "key1=value1\n" 0144 "key2=value2\n" 0145 "\n" 0146 "[group][sub1][subsub]\n" 0147 "key3=value3\n" 0148 "key4=value4\n" 0149 "\n" 0150 "[stay]\n" 0151 "foo=bar\n" 0152 << "testrc" 0153 << "[$Version]\n" 0154 "update_info=%1\n" 0155 "\n" 0156 "[group][sub2]\n" 0157 "key1=value1\n" 0158 "key2=value2\n" 0159 "\n" 0160 "[group][sub2][subsub]\n" 0161 "key3=value3\n" 0162 "key4=value4\n" 0163 "\n" 0164 "[stay]\n" 0165 "foo=bar\n" 0166 << "" << true << true; 0167 QTest::newRow("removeGroup") << "File=testrc\n" 0168 "RemoveGroup=remove\n" 0169 << "testrc" 0170 << "[keep]\n" 0171 "key=value\n" 0172 "" 0173 "[remove]\n" 0174 "key=value\n" 0175 << "testrc" 0176 << "[$Version]\n" 0177 "update_info=%1\n" 0178 "\n" 0179 "[keep]\n" 0180 "key=value\n" 0181 << "" << true << true; 0182 QTest::newRow("moveKeysSameFileDontExist") << "File=testrc\n" 0183 "Group=group,group2\n" 0184 "Key=key1\n" 0185 "Key=key2\n" 0186 << "testrc" 0187 << "[group]\n" 0188 "key1=value1\n" 0189 "key3=value3\n" 0190 << "testrc" 0191 << "[$Version]\n" 0192 "update_info=%1\n" 0193 "\n" 0194 "[group]\n" 0195 "key3=value3\n" 0196 "\n" 0197 "[group2]\n" 0198 "key1=value1\n" 0199 << "" << true << true; 0200 QTest::newRow("DontMigrateWhenFileDoesntHaveVersion") << "File=testrc\n" 0201 "Group=group\n" 0202 "Key=old,new\n" 0203 "Options=overwrite\n" 0204 << "testrc" 0205 << "[group]\n" 0206 "old=value\n" 0207 << "testrc" 0208 << "[group]\n" 0209 "old=value\n" 0210 << "" << false << false; 0211 0212 QTest::newRow("DontMigrateWhenUpdateCantDoItMissingFilename") << "Group=group\n" 0213 "Key=old,new\n" 0214 "Options=overwrite\n" 0215 << "testrc" 0216 << "[group]\n" 0217 "old=value\n" 0218 << "testrc" 0219 << "[group]\n" 0220 "old=value\n" 0221 << "" << true << false; 0222 } 0223 0224 void TestKConfUpdate::test() 0225 { 0226 QFETCH(QString, updContent); 0227 QFETCH(QString, oldConfName); 0228 QFETCH(QString, oldConfContent); 0229 QFETCH(QString, newConfName); 0230 QFETCH(QString, expectedNewConfContent); 0231 QFETCH(QString, expectedOldConfContent); 0232 QFETCH(bool, useVersion5); 0233 QFETCH(bool, shouldUpdateWork); 0234 0235 // Prepend Version and the Id= field to the upd content 0236 const QString header = QLatin1String("Id=%1\n").arg(QLatin1String(QTest::currentDataTag())); 0237 updContent = header + updContent; 0238 if (useVersion5) { 0239 updContent.prepend(QLatin1String{"Version=5\n"}); 0240 } 0241 0242 const QString configDir = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); 0243 QVERIFY(QDir().mkpath(configDir)); 0244 QString oldConfPath = configDir + QLatin1Char('/') + oldConfName; 0245 QString newConfPath = configDir + QLatin1Char('/') + newConfName; 0246 0247 QFile::remove(oldConfPath); 0248 QFile::remove(newConfPath); 0249 0250 writeFile(oldConfPath, oldConfContent); 0251 QCOMPARE(readFile(oldConfPath), oldConfContent); 0252 std::unique_ptr<QTemporaryFile> updFile(writeUpdFile(updContent)); 0253 runKConfUpdate(updFile->fileName()); 0254 0255 QString updateInfo = QLatin1String("%1:%2").arg(updFile->fileName().section(QLatin1Char('/'), -1), QLatin1String{QTest::currentDataTag()}); 0256 0257 QString newConfContentAfter = readFile(newConfPath); 0258 if (shouldUpdateWork) { 0259 expectedNewConfContent = expectedNewConfContent.arg(updateInfo); 0260 } 0261 QCOMPARE(newConfContentAfter, expectedNewConfContent); 0262 0263 if (oldConfName != newConfName) { 0264 QString oldConfContentAfter = readFile(oldConfPath); 0265 if (shouldUpdateWork) { 0266 expectedOldConfContent = expectedOldConfContent.arg(updateInfo); 0267 } 0268 QCOMPARE(oldConfContentAfter, expectedOldConfContent); 0269 } 0270 } 0271 0272 void TestKConfUpdate::testScript_data() 0273 { 0274 #ifdef Q_OS_WIN 0275 // add sh.exe and sed.exe to PATH on Windows 0276 // uncomment and adapt path to run all tests 0277 // qputenv("PATH", qgetenv("PATH") + ";C:\\kde\\msys\\bin"); 0278 #endif 0279 0280 QTest::addColumn<QString>("updContent"); 0281 QTest::addColumn<QString>("updScript"); 0282 QTest::addColumn<QString>("oldConfContent"); 0283 QTest::addColumn<QString>("expectedNewConfContent"); 0284 0285 QTest::newRow("delete-key") << "File=testrc\n" 0286 "Group=group\n" 0287 "Script=test.sh,sh\n" 0288 << "echo '# DELETE deprecated'\n" 0289 << "[group]\n" 0290 "deprecated=foo\n" 0291 "valid=bar\n" 0292 << "[$Version]\n" 0293 "update_info=%1\n" 0294 "\n" 0295 "[group]\n" 0296 "valid=bar\n"; 0297 0298 QTest::newRow("delete-key2") << "File=testrc\n" 0299 "Script=test.sh,sh\n" 0300 << "echo '# DELETE [group]deprecated'\n" 0301 "echo '# DELETE [group][sub]deprecated2'\n" 0302 << "[group]\n" 0303 "deprecated=foo\n" 0304 "valid=bar\n" 0305 "\n" 0306 "[group][sub]\n" 0307 "deprecated2=foo\n" 0308 "valid2=bar\n" 0309 << "[$Version]\n" 0310 "update_info=%1\n" 0311 "\n" 0312 "[group]\n" 0313 "valid=bar\n" 0314 "\n" 0315 "[group][sub]\n" 0316 "valid2=bar\n"; 0317 0318 QTest::newRow("delete-group") << "File=testrc\n" 0319 "Script=test.sh,sh\n" 0320 << "echo '# DELETEGROUP [group1]'\n" 0321 "echo '# DELETEGROUP [group2][sub]'\n" 0322 << "[group1]\n" 0323 "key=value\n" 0324 "\n" 0325 "[group2]\n" 0326 "valid=bar\n" 0327 "\n" 0328 "[group2][sub]\n" 0329 "key=value\n" 0330 << "[$Version]\n" 0331 "update_info=%1\n" 0332 "\n" 0333 "[group2]\n" 0334 "valid=bar\n"; 0335 0336 QTest::newRow("delete-group2") << "File=testrc\n" 0337 "Group=group\n" 0338 "Script=test.sh,sh\n" 0339 << "echo '# DELETEGROUP'\n" 0340 << "[group]\n" 0341 "key=value\n" 0342 "\n" 0343 "[group2]\n" 0344 "valid=bar\n" 0345 << "[$Version]\n" 0346 "update_info=%1\n" 0347 "\n" 0348 "[group2]\n" 0349 "valid=bar\n"; 0350 0351 QTest::newRow("new-key") << "File=testrc\n" 0352 "Script=test.sh,sh\n" 0353 << "echo '[group]'\n" 0354 "echo 'new=value'\n" 0355 << "[group]\n" 0356 "valid=bar\n" 0357 << "[$Version]\n" 0358 "update_info=%1\n" 0359 "\n" 0360 "[group]\n" 0361 "new=value\n" 0362 "valid=bar\n"; 0363 0364 QTest::newRow("modify-key-no-overwrite") << "File=testrc\n" 0365 "Script=test.sh,sh\n" 0366 << "echo '[group]'\n" 0367 "echo 'existing=new'\n" 0368 << "[group]\n" 0369 "existing=old\n" 0370 << "[$Version]\n" 0371 "update_info=%1\n" 0372 "\n" 0373 "[group]\n" 0374 "existing=old\n"; 0375 0376 QTest::newRow("modify-key-overwrite") << "File=testrc\n" 0377 "Options=overwrite\n" 0378 "Script=test.sh,sh\n" 0379 << "echo '[group]'\n" 0380 "echo 'existing=new'\n" 0381 << "[group]\n" 0382 "existing=old\n" 0383 << "[$Version]\n" 0384 "update_info=%1\n" 0385 "\n" 0386 "[group]\n" 0387 "existing=new\n"; 0388 0389 QTest::newRow("new-key-in-subgroup") << "File=testrc\n" 0390 "Script=test.sh,sh\n" 0391 << "echo '[group][sub]'\n" 0392 "echo 'new=value2'\n" 0393 << "[group][sub]\n" 0394 "existing=foo\n" 0395 << "[$Version]\n" 0396 "update_info=%1\n" 0397 "\n" 0398 "[group][sub]\n" 0399 "existing=foo\n" 0400 "new=value2\n"; 0401 0402 QTest::newRow("new-key-in-subgroup2") << "File=testrc\n" 0403 "Script=test.sh,sh\n" 0404 << "echo '[group][sub]'\n" 0405 "echo 'new=value3'\n" 0406 << "[group][sub]\n" 0407 "existing=foo\n" 0408 << "[$Version]\n" 0409 "update_info=%1\n" 0410 "\n" 0411 "[group][sub]\n" 0412 "existing=foo\n" 0413 "new=value3\n"; 0414 0415 if (QStandardPaths::findExecutable(QStringLiteral("sed")).isEmpty()) { 0416 qWarning("sed executable not found, cannot run all tests!"); 0417 } else { 0418 QTest::newRow("filter") << "File=testrc\n" 0419 "Script=test.sh,sh\n" 0420 << "echo '# DELETE [group]changed'\n" 0421 "sed s/value/VALUE/\n" 0422 << "[group]\n" 0423 "changed=value\n" 0424 "unchanged=value\n" 0425 << "[$Version]\n" 0426 "update_info=%1\n" 0427 "\n" 0428 "[group]\n" 0429 "changed=VALUE\n" 0430 "unchanged=value\n"; 0431 0432 QTest::newRow("filter-subgroup") << "File=testrc\n" 0433 "Script=test.sh,sh\n" 0434 << "echo '# DELETE [group][sub]changed'\n" 0435 "sed s/value/VALUE/\n" 0436 << "[group]\n" 0437 "unchanged=value\n" 0438 "\n" 0439 "[group][sub]\n" 0440 "changed=value\n" 0441 "unchanged=value\n" 0442 << "[$Version]\n" 0443 "update_info=%1\n" 0444 "\n" 0445 "[group]\n" 0446 "unchanged=value\n" 0447 "\n" 0448 "[group][sub]\n" 0449 "changed=VALUE\n" 0450 "unchanged=value\n"; 0451 } 0452 } 0453 0454 void TestKConfUpdate::testScript() 0455 { 0456 if (QStandardPaths::findExecutable(QStringLiteral("sh")).isEmpty()) { 0457 QSKIP("Could not find sh executable, cannot run test"); 0458 return; 0459 } 0460 0461 QFETCH(QString, updContent); 0462 QFETCH(QString, updScript); 0463 QFETCH(QString, oldConfContent); 0464 QFETCH(QString, expectedNewConfContent); 0465 0466 // Prepend the Version and Id= field to the upd content 0467 updContent.prepend(QLatin1String("Version=5\nId=%1\n").arg(QLatin1String{QTest::currentDataTag()})); 0468 0469 std::unique_ptr<QTemporaryFile> updFile(writeUpdFile(updContent)); 0470 0471 const QString scriptDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String{"/kconf_update"}; 0472 QVERIFY(QDir().mkpath(scriptDir)); 0473 const QString scriptPath = scriptDir + QLatin1String{"/test.sh"}; 0474 writeFile(scriptPath, updScript); 0475 QCOMPARE(readFile(scriptPath), updScript); 0476 0477 const QString confPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1String{"/testrc"}; 0478 writeFile(confPath, oldConfContent); 0479 QCOMPARE(readFile(confPath), oldConfContent); 0480 0481 runKConfUpdate(updFile->fileName()); 0482 0483 const QString updateInfo = QLatin1String("%1:%2").arg(updFile->fileName().section(QLatin1Char{'/'}, -1), QLatin1String{QTest::currentDataTag()}); 0484 QString newConfContent = readFile(confPath); 0485 expectedNewConfContent = expectedNewConfContent.arg(updateInfo); 0486 QCOMPARE(newConfContent, expectedNewConfContent); 0487 } 0488 0489 #include "moc_test_kconf_update.cpp"