File indexing completed on 2024-05-19 04:42:05

0001 /*
0002     SPDX-FileCopyrightText: 2010 Benjamin Port <port.benjamin@gmail.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "test_qthelpplugin.h"
0008 #include "../qthelpplugin.h"
0009 #include "../qthelpprovider.h"
0010 #include "../qthelp_config_shared.h"
0011 
0012 #include <QCoreApplication>
0013 #include <QTest>
0014 #include <QHelpLink>
0015 
0016 #include <interfaces/idocumentation.h>
0017 #include <language/duchain/duchainlock.h>
0018 #include <language/duchain/declaration.h>
0019 #include <language/duchain/types/identifiedtype.h>
0020 #include <language/duchain/types/pointertype.h>
0021 #include <tests/autotestshell.h>
0022 #include <tests/testfile.h>
0023 
0024 #include "testqthelpconfig.h"
0025 
0026 const QString VALID1 = QTHELP_FILES "/valid1.qch";
0027 const QString VALID2 = QTHELP_FILES "/valid2.qch";
0028 const QString INVALID = QTHELP_FILES "/invalid.qch";
0029 
0030 QTEST_MAIN(TestQtHelpPlugin)
0031 using namespace KDevelop;
0032 
0033 TestQtHelpPlugin::TestQtHelpPlugin()
0034     : m_testCore(nullptr)
0035     , m_plugin(nullptr)
0036 {
0037 }
0038 
0039 void TestQtHelpPlugin::initTestCase()
0040 {
0041     AutoTestShell::init({"kdevqthelp"});
0042 
0043     // Prevent SegFault, then "ICE default IO error handler doing an exit(), pid = <PID>, errno = 32"
0044     // crash when the test runs for at least 60 seconds. This is a workaround for QTBUG-58709.
0045     QCoreApplication::processEvents();
0046 
0047     m_testCore = new TestCore();
0048     m_testCore->initialize();
0049 }
0050 
0051 void TestQtHelpPlugin::init()
0052 {
0053     m_plugin = new QtHelpPlugin(m_testCore, QVariantList());
0054     // write default config and read it
0055     qtHelpWriteConfig(QStringList(), QStringList(), QStringList(), QStringList(), QString(), true);
0056     m_plugin->readConfig();
0057     QTRY_VERIFY(m_plugin->isQtHelpQtDocLoaded());
0058 }
0059 
0060 void TestQtHelpPlugin::cleanup()
0061 {
0062     delete m_plugin;
0063 }
0064 
0065 void TestQtHelpPlugin::cleanupTestCase()
0066 {
0067     m_testCore->cleanup();
0068     delete m_testCore;
0069 }
0070 
0071 void TestQtHelpPlugin::testDefaultValue()
0072 {
0073     QCOMPARE(m_plugin->isQtHelpQtDocLoaded(), true);
0074     QCOMPARE(m_plugin->qtHelpProviderLoaded().size(), 0);
0075     QCOMPARE(m_plugin->providers().size(), 1);
0076 }
0077 
0078 void TestQtHelpPlugin::testUnsetQtHelpDoc()
0079 {
0080     qtHelpWriteConfig(QStringList(), QStringList(), QStringList(), QStringList(), QString(), false);
0081     m_plugin->readConfig();
0082 
0083     QCOMPARE(m_plugin->providers().size(), 0);
0084 }
0085 
0086 void TestQtHelpPlugin::testAddOneValidProvider()
0087 {
0088     QStringList path, name, icon, ghns;
0089     path << VALID1;
0090     name << QStringLiteral("file1");
0091     icon << QStringLiteral("myIcon");
0092     ghns << QStringLiteral("0");
0093     qtHelpWriteConfig(icon, name, path, ghns, QString(), true);
0094     m_plugin->readConfig();
0095 
0096     QCOMPARE(m_plugin->qtHelpProviderLoaded().size(), 1);
0097     QCOMPARE(m_plugin->qtHelpProviderLoaded().at(0)->fileName(), path.at(0));
0098     QCOMPARE(m_plugin->qtHelpProviderLoaded().at(0)->name(), name.at(0));
0099     QCOMPARE(m_plugin->qtHelpProviderLoaded().at(0)->iconName(), icon.at(0));
0100 }
0101 
0102 void TestQtHelpPlugin::testAddTwoDifferentValidProvider()
0103 {
0104     QStringList path, name, icon, ghns;
0105     path << VALID1 << VALID2;
0106     name << QStringLiteral("file1") << QStringLiteral("file2");
0107     icon << QStringLiteral("myIcon") << QStringLiteral("myIcon");
0108     ghns << QStringLiteral("0") << QStringLiteral("0");
0109     qtHelpWriteConfig(icon, name, path, ghns, QString(), true);
0110     m_plugin->readConfig();
0111 
0112     QCOMPARE(m_plugin->qtHelpProviderLoaded().size(), 2);
0113     // first provider
0114     QCOMPARE(m_plugin->qtHelpProviderLoaded().at(0)->fileName(), path.at(0));
0115     QCOMPARE(m_plugin->qtHelpProviderLoaded().at(0)->name(), name.at(0));
0116     QCOMPARE(m_plugin->qtHelpProviderLoaded().at(0)->iconName(), icon.at(0));
0117     // second provider
0118     QCOMPARE(m_plugin->qtHelpProviderLoaded().at(1)->fileName(), path.at(1));
0119     QCOMPARE(m_plugin->qtHelpProviderLoaded().at(1)->name(), name.at(1));
0120     QCOMPARE(m_plugin->qtHelpProviderLoaded().at(1)->iconName(), icon.at(1));
0121 }
0122 
0123 void TestQtHelpPlugin::testAddInvalidProvider()
0124 {
0125     QStringList path, name, icon, ghns;
0126     path << INVALID;
0127     name << QStringLiteral("file1");
0128     icon << QStringLiteral("myIcon");
0129     ghns << QStringLiteral("0");
0130     qtHelpWriteConfig(icon, name, path, ghns, QString(), true);
0131     m_plugin->readConfig();
0132 
0133     QCOMPARE(m_plugin->qtHelpProviderLoaded().size(), 0);
0134 }
0135 
0136 void TestQtHelpPlugin::testAddTwiceSameProvider()
0137 {
0138     QStringList path, name, icon, ghns;
0139     path << VALID1 << VALID1;
0140     name << QStringLiteral("file1") << QStringLiteral("file2");
0141     icon << QStringLiteral("myIcon") << QStringLiteral("myIcon");
0142     ghns << QStringLiteral("0") << QStringLiteral("0");
0143     qtHelpWriteConfig(icon, name, path, ghns, QString(), true);
0144     m_plugin->readConfig();
0145 
0146     QCOMPARE(m_plugin->qtHelpProviderLoaded().size(), 1);
0147 }
0148 
0149 void TestQtHelpPlugin::testRemoveOneProvider()
0150 {
0151     QStringList path, name, icon, ghns;
0152     path << VALID1 << VALID2;
0153     name << QStringLiteral("file1") << QStringLiteral("file2");
0154     icon << QStringLiteral("myIcon") << QStringLiteral("myIcon");
0155     ghns << QStringLiteral("0") << QStringLiteral("0");
0156     qtHelpWriteConfig(icon, name, path, ghns, QString(), true);
0157     m_plugin->readConfig();
0158 
0159     QCOMPARE(m_plugin->qtHelpProviderLoaded().size(), 2);
0160     // we remove the second provider
0161     QtHelpProvider *provider = m_plugin->qtHelpProviderLoaded().at(0);
0162     path.removeAt(1);
0163     name.removeAt(1);
0164     icon.removeAt(1);
0165     ghns.removeAt(1);
0166     qtHelpWriteConfig(icon, name, path, ghns, QString(), true);
0167     m_plugin->readConfig();
0168 
0169     QCOMPARE(m_plugin->qtHelpProviderLoaded().size(), 1);
0170     QCOMPARE(m_plugin->qtHelpProviderLoaded().at(0), provider);
0171 }
0172 
0173 void TestQtHelpPlugin::testDeclarationLookup_Class()
0174 {
0175     init();
0176 
0177     TestFile file(QStringLiteral("class QObject; QObject* o;"), QStringLiteral("cpp"));
0178     QVERIFY(file.parseAndWait());
0179 
0180     DUChainReadLocker lock;
0181     auto ctx = file.topContext();
0182     QVERIFY(ctx);
0183     auto decl = ctx->findDeclarations(QualifiedIdentifier(QStringLiteral("o"))).first();
0184     QVERIFY(decl);
0185     auto typeDecl = dynamic_cast<const IdentifiedType*>(decl->type<PointerType>()->baseType().data())->declaration(nullptr);
0186     QVERIFY(typeDecl);
0187 
0188     auto provider = dynamic_cast<QtHelpProviderAbstract*>(m_plugin->providers().at(0));
0189     QVERIFY(provider);
0190     if (!provider->isValid() || provider->engine()->documentsForIdentifier(QStringLiteral("QObject")).isEmpty()) {
0191         QSKIP("Qt help not available");
0192     }
0193 
0194     auto doc = provider->documentationForDeclaration(typeDecl);
0195     QVERIFY(doc);
0196     QCOMPARE(doc->name(), QStringLiteral("QObject"));
0197     const auto description = doc->description();
0198     QVERIFY(description.contains("QObject"));
0199 }
0200 
0201 void TestQtHelpPlugin::testDeclarationLookup_Method()
0202 {
0203     init();
0204 
0205     TestFile file(QStringLiteral("class QString { static QString fromLatin1(const QByteArray&); };"), QStringLiteral("cpp"));
0206     QVERIFY(file.parseAndWait());
0207 
0208     DUChainReadLocker lock;
0209     auto ctx = file.topContext();
0210     QVERIFY(ctx);
0211     auto decl = ctx->findDeclarations(QualifiedIdentifier(QStringLiteral("QString"))).first();
0212     auto declFromLatin1 = decl->internalContext()->findDeclarations(QualifiedIdentifier(QStringLiteral("fromLatin1"))).first();
0213     QVERIFY(decl);
0214 
0215     auto provider = dynamic_cast<QtHelpProviderAbstract*>(m_plugin->providers().at(0));
0216     QVERIFY(provider);
0217     if (!provider->isValid()
0218         || provider->engine()->documentsForIdentifier(QStringLiteral("QString::fromLatin1")).isEmpty()) {
0219         QSKIP("Qt help not available");
0220     }
0221 
0222     auto doc = provider->documentationForDeclaration(declFromLatin1);
0223     QVERIFY(doc);
0224     QCOMPARE(doc->name(), QStringLiteral("QString::fromLatin1"));
0225     const auto description = doc->description();
0226     QVERIFY(description.contains("fromLatin1"));
0227 }
0228 
0229 void TestQtHelpPlugin::testDeclarationLookup_OperatorFunction()
0230 {
0231     init();
0232 
0233     TestFile file(QStringLiteral("class C {}; bool operator<(const C& a, const C& b) { return true; }"), QStringLiteral("cpp"));
0234     QVERIFY(file.parseAndWait());
0235 
0236     DUChainReadLocker lock;
0237     auto ctx = file.topContext();
0238     auto decl = ctx->findDeclarations(QualifiedIdentifier(QStringLiteral("operator<"))).first();
0239     QVERIFY(decl);
0240 
0241     auto provider = dynamic_cast<QtHelpProviderAbstract*>(m_plugin->providers().at(0));
0242     QVERIFY(provider);
0243     if (!provider->isValid() || provider->engine()->documentsForIdentifier(QStringLiteral("QObject")).isEmpty()) {
0244         QSKIP("Qt help not available");
0245     }
0246 
0247     auto doc = provider->documentationForDeclaration(decl);
0248     // TODO: We should never find a documentation entry for this (but instead, the operator< for QChar is found here)
0249     QEXPECT_FAIL("", "doc should be null here", Continue);
0250     QVERIFY(!doc);
0251 }
0252 
0253 #include "moc_test_qthelpplugin.cpp"