File indexing completed on 2024-12-01 04:35:23
0001 /* 0002 SPDX-FileCopyrightText: 2018-2024 Laurent Montel <montel@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "emojimanagertest.h" 0008 #include "emoticons/customemoji.h" 0009 #include "emoticons/emojimanager.h" 0010 #include "rocketchataccount.h" 0011 #include "ruqola_autotest_helper.h" 0012 #include <QJsonDocument> 0013 #include <QJsonObject> 0014 #include <QSignalSpy> 0015 0016 #include <TextEmoticonsCore/UnicodeEmoticonManager> 0017 QTEST_GUILESS_MAIN(EmojiManagerTest) 0018 0019 EmojiManagerTest::EmojiManagerTest(QObject *parent) 0020 : QObject(parent) 0021 { 0022 } 0023 0024 void EmojiManagerTest::shouldHaveDefaultValue() 0025 { 0026 EmojiManager manager(nullptr); 0027 QVERIFY(manager.serverUrl().isEmpty()); 0028 QCOMPARE(manager.count(), 3671); 0029 QVERIFY(manager.customEmojiList().isEmpty()); 0030 } 0031 0032 void EmojiManagerTest::shouldParseEmoji_data() 0033 { 0034 QTest::addColumn<QString>("name"); 0035 QTest::addColumn<int>("number"); 0036 QTest::addRow("emojiparent") << QStringLiteral("emojiparent") << 3678; 0037 } 0038 0039 void EmojiManagerTest::shouldParseEmoji() 0040 { 0041 QFETCH(QString, name); 0042 QFETCH(int, number); 0043 const QString originalJsonFile = QLatin1String(RUQOLA_DATA_DIR) + QLatin1String("/json/restapi/") + name + QLatin1String(".json"); 0044 auto obj = AutoTestHelper::loadJsonObject(originalJsonFile); 0045 EmojiManager manager(nullptr); 0046 manager.loadCustomEmoji(obj); 0047 QCOMPARE(manager.count(), number); 0048 } 0049 0050 void EmojiManagerTest::shouldDeleteEmojiCustom_data() 0051 { 0052 QTest::addColumn<QString>("initialListName"); 0053 QTest::addColumn<int>("number"); 0054 QTest::addColumn<QString>("deleteName"); 0055 QTest::addColumn<QVector<CustomEmoji>>("original"); 0056 QTest::addColumn<QVector<CustomEmoji>>("customEmoji"); 0057 { 0058 QVector<CustomEmoji> emojiList; 0059 CustomEmoji val; 0060 val.setName(QStringLiteral("kdab")); 0061 val.setIdentifier(QStringLiteral("RyBauhQqnoE5WeJvZ")); 0062 val.setExtension(QStringLiteral("png")); 0063 val.setEmojiIdentifier(QStringLiteral(":kdab:")); 0064 val.setUpdatedAt(1529303015003); 0065 emojiList.append(std::move(val)); 0066 0067 CustomEmoji val1; 0068 val1.setName(QStringLiteral("vader")); 0069 val1.setIdentifier(QStringLiteral("fAiQmJnJPAaEFmps6")); 0070 val1.setExtension(QStringLiteral("png")); 0071 val1.setEmojiIdentifier(QStringLiteral(":vader:")); 0072 val1.setUpdatedAt(1560497261506); 0073 val1.setAliases({QStringLiteral(":darth:")}); 0074 emojiList.append(val1); 0075 0076 QVector<CustomEmoji> emojiListAfterDeleting; 0077 emojiListAfterDeleting.append(val1); 0078 0079 QTest::addRow("delete1") << QStringLiteral("emojiparent2") << 3673 << QStringLiteral("emojicustomdelete1") << emojiList << emojiListAfterDeleting; 0080 } 0081 { 0082 QVector<CustomEmoji> emojiList; 0083 CustomEmoji val; 0084 val.setName(QStringLiteral("kdab")); 0085 val.setIdentifier(QStringLiteral("RyBauhQqnoE5WeJvZ")); 0086 val.setExtension(QStringLiteral("png")); 0087 val.setEmojiIdentifier(QStringLiteral(":kdab:")); 0088 val.setUpdatedAt(1529303015003); 0089 0090 CustomEmoji val1; 0091 val1.setName(QStringLiteral("vader")); 0092 val1.setIdentifier(QStringLiteral("fAiQmJnJPAaEFmps6")); 0093 val1.setExtension(QStringLiteral("png")); 0094 val1.setEmojiIdentifier(QStringLiteral(":vader:")); 0095 val1.setUpdatedAt(1560497261506); 0096 val1.setAliases({QStringLiteral(":darth:")}); 0097 0098 emojiList.append(std::move(val)); 0099 emojiList.append(std::move(val1)); 0100 // We can't delete emoji which is not in liste. 0101 QTest::addRow("delete2") << QStringLiteral("emojiparent2") << 3673 << QStringLiteral("emojicustomdelete2") << emojiList << emojiList; 0102 } 0103 } 0104 0105 void EmojiManagerTest::shouldDeleteEmojiCustom() 0106 { 0107 QFETCH(QString, initialListName); 0108 QFETCH(int, number); 0109 QFETCH(QString, deleteName); 0110 QFETCH(QVector<CustomEmoji>, original); 0111 QFETCH(QVector<CustomEmoji>, customEmoji); 0112 const QString originalJsonFile = QLatin1String(RUQOLA_DATA_DIR) + QLatin1String("/json/restapi/") + initialListName + QLatin1String(".json"); 0113 const auto obj = AutoTestHelper::loadJsonObject(originalJsonFile); 0114 EmojiManager manager(nullptr); 0115 manager.loadCustomEmoji(obj); 0116 QCOMPARE(manager.count(), number); 0117 QCOMPARE(manager.customEmojiList(), original); 0118 0119 const QString deleteJsonFile = QLatin1String(RUQOLA_DATA_DIR) + QLatin1String("/json/restapi/") + deleteName + QLatin1String(".json"); 0120 const auto objDelete = AutoTestHelper::loadJsonArrayObject(deleteJsonFile); 0121 manager.deleteEmojiCustom(objDelete); 0122 // qDebug() << " manager.customEmojiList() " << manager.customEmojiList(); 0123 QCOMPARE(manager.customEmojiList(), customEmoji); 0124 } 0125 0126 void EmojiManagerTest::shouldAddEmojiCustom_data() 0127 { 0128 QTest::addColumn<QString>("initialListName"); 0129 QTest::addColumn<int>("number"); 0130 QTest::addColumn<QString>("addName"); 0131 QTest::addColumn<QVector<CustomEmoji>>("original"); 0132 QTest::addColumn<QVector<CustomEmoji>>("customEmoji"); 0133 0134 { 0135 QVector<CustomEmoji> emojiList; 0136 CustomEmoji val; 0137 val.setName(QStringLiteral("kdab")); 0138 val.setIdentifier(QStringLiteral("RyBauhQqnoE5WeJvZ")); 0139 val.setExtension(QStringLiteral("png")); 0140 val.setEmojiIdentifier(QStringLiteral(":kdab:")); 0141 val.setUpdatedAt(1529303015003); 0142 0143 CustomEmoji val1; 0144 val1.setName(QStringLiteral("vader")); 0145 val1.setIdentifier(QStringLiteral("fAiQmJnJPAaEFmps6")); 0146 val1.setExtension(QStringLiteral("png")); 0147 val1.setEmojiIdentifier(QStringLiteral(":vader:")); 0148 val1.setUpdatedAt(1560497261506); 0149 val1.setAliases({QStringLiteral(":darth:")}); 0150 0151 emojiList.append(std::move(val)); 0152 emojiList.append(std::move(val1)); 0153 0154 QVector<CustomEmoji> emojiListAfterDeleting = emojiList; 0155 CustomEmoji val2; 0156 val2.setName(QStringLiteral("ruqola")); 0157 val2.setIdentifier(QStringLiteral("HdN28k4PQ6J9xLkZ8")); 0158 val2.setExtension(QStringLiteral("png")); 0159 val2.setEmojiIdentifier(QStringLiteral(":ruqola:")); 0160 val2.setUpdatedAt(1631885946222); 0161 val2.setAliases({QStringLiteral(":roo:")}); 0162 emojiList.append(std::move(val2)); 0163 QTest::addRow("emojiparent2") << QStringLiteral("emojiparent2") << 3673 << QStringLiteral("addemojicustom1") << emojiListAfterDeleting << emojiList; 0164 } 0165 } 0166 0167 void EmojiManagerTest::shouldAddEmojiCustom() 0168 { 0169 QFETCH(QString, initialListName); 0170 QFETCH(int, number); 0171 QFETCH(QString, addName); 0172 QFETCH(QVector<CustomEmoji>, original); 0173 QFETCH(QVector<CustomEmoji>, customEmoji); 0174 const QString originalJsonFile = QLatin1String(RUQOLA_DATA_DIR) + QLatin1String("/json/restapi/") + initialListName + QLatin1String(".json"); 0175 auto obj = AutoTestHelper::loadJsonObject(originalJsonFile); 0176 EmojiManager manager(nullptr); 0177 QSignalSpy customEmojiChanged(&manager, &EmojiManager::customEmojiChanged); 0178 manager.loadCustomEmoji(obj); 0179 QCOMPARE(manager.count(), number); 0180 0181 QCOMPARE(manager.customEmojiList(), original); 0182 0183 const QString addJsonFile = QLatin1String(RUQOLA_DATA_DIR) + QLatin1String("/json/restapi/") + addName + QLatin1String(".json"); 0184 const auto objAdd = AutoTestHelper::loadJsonArrayObject(addJsonFile); 0185 manager.addUpdateEmojiCustomList(objAdd); 0186 QCOMPARE(customEmojiChanged.count(), 1); 0187 QCOMPARE(customEmojiChanged.at(0).at(0).toBool(), true); 0188 0189 // qDebug() << " BEFORE " << customEmoji; 0190 // qDebug() << " manager.customEmojiList() " << manager.customEmojiList(); 0191 // QCOMPARE(manager.customEmojiList(), customEmoji); 0192 } 0193 0194 void EmojiManagerTest::shouldUpdateEmojiCustom_data() 0195 { 0196 QTest::addColumn<QString>("initialListName"); 0197 QTest::addColumn<int>("number"); 0198 QTest::addColumn<QString>("addName"); 0199 QTest::addColumn<QVector<CustomEmoji>>("original"); 0200 QTest::addColumn<QVector<CustomEmoji>>("customEmoji"); 0201 { 0202 QVector<CustomEmoji> emojiList; 0203 CustomEmoji val; 0204 val.setName(QStringLiteral("kdab")); 0205 val.setIdentifier(QStringLiteral("RyBauhQqnoE5WeJvZ")); 0206 val.setExtension(QStringLiteral("png")); 0207 val.setEmojiIdentifier(QStringLiteral(":kdab:")); 0208 val.setUpdatedAt(1529303015003); 0209 0210 CustomEmoji val1; 0211 val1.setName(QStringLiteral("vader")); 0212 val1.setIdentifier(QStringLiteral("fAiQmJnJPAaEFmps6")); 0213 val1.setExtension(QStringLiteral("png")); 0214 val1.setEmojiIdentifier(QStringLiteral(":vader:")); 0215 val1.setUpdatedAt(1560497261506); 0216 val1.setAliases({QStringLiteral(":darth:")}); 0217 0218 emojiList.append(std::move(val)); 0219 emojiList.append(std::move(val1)); 0220 0221 QVector<CustomEmoji> emojiListAfterDeleting; 0222 CustomEmoji val2; 0223 val2.setName(QStringLiteral("ruqola")); 0224 val2.setIdentifier(QStringLiteral("RyBauhQqnoE5WeJvZ")); 0225 val2.setExtension(QStringLiteral("png")); 0226 val2.setEmojiIdentifier(QStringLiteral(":ruqola:")); 0227 val2.setUpdatedAt(1631885946222); 0228 val2.setAliases({QStringLiteral("rooss")}); 0229 emojiListAfterDeleting.append(val); 0230 emojiListAfterDeleting.append(val2); 0231 QTest::addRow("emojiparent2") << QStringLiteral("emojiparent2") << 3673 << QStringLiteral("updateemojicustom1") << emojiList << emojiList; 0232 } 0233 } 0234 0235 void EmojiManagerTest::shouldUpdateEmojiCustom() 0236 { 0237 QFETCH(QString, initialListName); 0238 QFETCH(int, number); 0239 QFETCH(QString, addName); 0240 QFETCH(QVector<CustomEmoji>, original); 0241 QFETCH(QVector<CustomEmoji>, customEmoji); 0242 const QString originalJsonFile = QLatin1String(RUQOLA_DATA_DIR) + QLatin1String("/json/restapi/") + initialListName + QLatin1String(".json"); 0243 auto obj = AutoTestHelper::loadJsonObject(originalJsonFile); 0244 EmojiManager manager(nullptr); 0245 QSignalSpy customEmojiChanged(&manager, &EmojiManager::customEmojiChanged); 0246 manager.loadCustomEmoji(obj); 0247 0248 QCOMPARE(manager.count(), number); 0249 QCOMPARE(manager.customEmojiList(), original); 0250 0251 const QString addJsonFile = QLatin1String(RUQOLA_DATA_DIR) + QLatin1String("/json/restapi/") + addName + QLatin1String(".json"); 0252 const auto objAdd = AutoTestHelper::loadJsonArrayObject(addJsonFile); 0253 manager.addUpdateEmojiCustomList(objAdd); 0254 QCOMPARE(customEmojiChanged.count(), 1); 0255 QCOMPARE(customEmojiChanged.at(0).at(0).toBool(), false); 0256 } 0257 0258 void EmojiManagerTest::shouldSupportUnicodeEmojis() 0259 { 0260 // Load list of unicode emoticon 0261 TextEmoticonsCore::UnicodeEmoticonManager::self(); 0262 EmojiManager manager(nullptr); 0263 QString grinning; 0264 grinning += QChar(0xd800 + 61); 0265 grinning += QChar(0xDC00 + 512); 0266 // A basic emoji that was already there in the initial emoji.json from fairchat 0267 QCOMPARE(manager.unicodeEmoticonForEmoji(QStringLiteral(":grinning:")).unicode(), grinning); 0268 // The one that made me use https://raw.githubusercontent.com/joypixels/emoji-toolkit/master/emoji.json instead 0269 QVERIFY(manager.unicodeEmoticonForEmoji(QStringLiteral(":zany_face:")).isValid()); 0270 // A "shortname alternate" 0271 QCOMPARE(manager.unicodeEmoticonForEmoji(QStringLiteral(":water_polo_tone5:")).key(), QStringLiteral("1f93d-1f3ff")); 0272 // One with multiple values below 0x10000, to catch += vs = bug. 0273 QCOMPARE(manager.unicodeEmoticonForEmoji(QStringLiteral(":woman_climbing_tone4:")).unicode().length(), 7); 0274 QCOMPARE(manager.unicodeEmoticonForEmoji(QStringLiteral(":man_health_worker_tone1:")).unicode().length(), 7); 0275 0276 // a smiley with shortname alternates and ascii versions 0277 QString slightSmile; 0278 slightSmile += QChar(0xD83D); 0279 slightSmile += QChar(0xDE42); 0280 QCOMPARE(manager.unicodeEmoticonForEmoji(QStringLiteral(":slight_smile:")).unicode(), slightSmile); 0281 // alternate 0282 QCOMPARE(manager.unicodeEmoticonForEmoji(QStringLiteral(":slightly_smiling_face:")).unicode(), slightSmile); 0283 // ascii 0284 QCOMPARE(manager.unicodeEmoticonForEmoji(QStringLiteral(":)")).unicode(), slightSmile); 0285 QCOMPARE(manager.unicodeEmoticonForEmoji(QStringLiteral(":-)")).unicode(), slightSmile); 0286 0287 QCOMPARE(manager.categories().count(), 9); 0288 QCOMPARE(manager.categories().at(0).category(), QStringLiteral("people")); 0289 QCOMPARE(manager.emojisForCategory(QStringLiteral("people")).count(), 2031); 0290 } 0291 0292 void EmojiManagerTest::shouldOrderUnicodeEmojis() 0293 { 0294 // Load list of unicode emoticon 0295 TextEmoticonsCore::UnicodeEmoticonManager::self(); 0296 EmojiManager manager(nullptr); 0297 const QList<TextEmoticonsCore::UnicodeEmoticon> list = manager.unicodeEmojiList(); 0298 auto hasCategory = [](const QString &category) { 0299 return [category](const TextEmoticonsCore::UnicodeEmoticon &emo) { 0300 return emo.category() == category; 0301 }; 0302 }; 0303 // Check what's the first emoji in the category "symbols" 0304 auto it = std::find_if(list.begin(), list.end(), hasCategory(QStringLiteral("symbols"))); 0305 QVERIFY(it != list.end()); 0306 const TextEmoticonsCore::UnicodeEmoticon firstSymbol = *it; 0307 QCOMPARE(firstSymbol.order(), 3063); 0308 QCOMPARE(firstSymbol.category(), QStringLiteral("symbols")); 0309 QCOMPARE(firstSymbol.identifier(), QStringLiteral(":heart:")); 0310 0311 // Check what's the first emoji in the category "regional" 0312 it = std::find_if(list.begin(), list.end(), hasCategory(QStringLiteral("regional"))); 0313 QVERIFY(it != list.end()); 0314 const TextEmoticonsCore::UnicodeEmoticon firstRegional = *it; 0315 QCOMPARE(firstRegional.identifier(), QStringLiteral(":regional_indicator_z:")); // letters are reversed, weird 0316 } 0317 0318 void EmojiManagerTest::shouldGenerateHtml() 0319 { 0320 const QString originalJsonFile = QLatin1String(RUQOLA_DATA_DIR) + QLatin1String("/json/restapi/emojiparent.json"); 0321 QFile f(originalJsonFile); 0322 QVERIFY(f.open(QIODevice::ReadOnly)); 0323 const QByteArray content = f.readAll(); 0324 f.close(); 0325 const QJsonDocument doc = QJsonDocument::fromJson(content); 0326 const QJsonObject obj = doc.object(); 0327 EmojiManager manager(nullptr); 0328 manager.loadCustomEmoji(obj); 0329 // No serverUrl set. 0330 QCOMPARE(manager.replaceEmojiIdentifier(QStringLiteral(":foo:")), QStringLiteral(":foo:")); 0331 0332 const QString serverUrl = QStringLiteral("www.kde.org"); 0333 manager.setServerUrl(serverUrl); 0334 0335 // :foo: doesn't exist 0336 QCOMPARE(manager.replaceEmojiIdentifier(QStringLiteral(":foo:")), QStringLiteral(":foo:")); 0337 QCOMPARE(manager.customEmojiFileName(QStringLiteral(":foo:")), QString()); 0338 0339 // // Existing emoji 0340 // QCOMPARE(manager.replaceEmojiIdentifier(QStringLiteral(":vader:")), QStringLiteral("<img height='22' width='22' 0341 // src='http://www.kde.org/emoji-custom/vader.png' title=':vader:'/>")); QCOMPARE(manager.customEmojiFileName(QStringLiteral(":vader:")), 0342 // QStringLiteral("/emoji-custom/vader.png")); 0343 0344 // // Alias 0345 // QCOMPARE(manager.replaceEmojiIdentifier(QStringLiteral(":darth:")), QStringLiteral("<img height='22' width='22' 0346 // src='http://www.kde.org/emoji-custom/vader.png' title=':vader:'/>")); QCOMPARE(manager.customEmojiFileName(QStringLiteral(":darth:")), 0347 // QStringLiteral("/emoji-custom/vader.png")); 0348 } 0349 0350 void EmojiManagerTest::shouldChangeServerUrl() 0351 { 0352 // const QString originalJsonFile = QLatin1String(RUQOLA_DATA_DIR) + QLatin1String("/json/restapi/emojiparent.json"); 0353 // QFile f(originalJsonFile); 0354 // QVERIFY(f.open(QIODevice::ReadOnly)); 0355 // const QByteArray content = f.readAll(); 0356 // f.close(); 0357 // const QJsonDocument doc = QJsonDocument::fromJson(content); 0358 // const QJsonObject obj = doc.object(); 0359 // EmojiManager manager(nullptr); 0360 // manager.loadCustomEmoji(obj); 0361 // QString serverUrl = QStringLiteral("www.kde.org"); 0362 // manager.setServerUrl(serverUrl); 0363 0364 // //It exists 0365 // QCOMPARE(manager.replaceEmojiIdentifier(QStringLiteral(":vader:")), QStringLiteral("<img height='22' width='22' src='http://%1/emoji-custom/vader.png' 0366 // title=':vader:'/>").arg(serverUrl)); 0367 0368 // //Change server url => clear cache 0369 // serverUrl = QStringLiteral("www.bla.org"); 0370 // manager.setServerUrl(serverUrl); 0371 // QCOMPARE(manager.replaceEmojiIdentifier(QStringLiteral(":vader:")), QStringLiteral("<img height='22' width='22' src='http://%1/emoji-custom/vader.png' 0372 // title=':vader:'/>").arg(serverUrl)); 0373 } 0374 0375 void EmojiManagerTest::shouldNormalizeReactions_data() 0376 { 0377 QTest::addColumn<QString>("emoji"); 0378 QTest::addColumn<QString>("normalizedEmoji"); 0379 0380 QTest::addRow(":)") << ":)" 0381 << ":slight_smile:"; 0382 QTest::addRow(":slight_simle:") << ":slight_smile:" 0383 << ":slight_smile:"; 0384 QString slightSmile; 0385 slightSmile += QChar(0xD83D); 0386 slightSmile += QChar(0xDE42); 0387 QTest::addRow("unicode-smile") << slightSmile << ":slight_smile:"; 0388 QTest::addRow(":vader:") << ":vader:" 0389 << ":vader:"; 0390 } 0391 0392 void EmojiManagerTest::shouldNormalizeReactions() 0393 { 0394 QFETCH(QString, emoji); 0395 QFETCH(QString, normalizedEmoji); 0396 0397 EmojiManager manager(nullptr); 0398 QCOMPARE(manager.normalizedReactionEmoji(emoji), normalizedEmoji); 0399 } 0400 0401 void EmojiManagerTest::replaceAsciiEmoji_data() 0402 { 0403 QTest::addColumn<QString>("input"); 0404 QTest::addColumn<bool>("replaced"); 0405 0406 QTest::addRow("1") << "hello :)" << true; 0407 QTest::addRow("2") << "Item::Lock" << false; 0408 QTest::addRow("3") << ":)" << true; 0409 QTest::addRow("3") << ":)what" << true; 0410 } 0411 0412 void EmojiManagerTest::replaceAsciiEmoji() 0413 { 0414 QFETCH(QString, input); 0415 QFETCH(bool, replaced); 0416 QString original = input; 0417 0418 TextEmoticonsCore::UnicodeEmoticonManager::self(); 0419 RocketChatAccount account; 0420 account.ownUserPreferences().setConvertAsciiEmoji(true); 0421 EmojiManager manager(&account); 0422 manager.setServerUrl(QStringLiteral("blah blah")); 0423 manager.replaceEmojis(&input); 0424 0425 QCOMPARE(input != original, replaced); 0426 } 0427 0428 #include "moc_emojimanagertest.cpp"