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"