File indexing completed on 2024-12-01 03:42:31

0001 /*
0002     This file is part of the KDE project
0003     SPDX-FileCopyrightText: 2001, 2003 Peter Kelly <pmk@post.com>
0004     SPDX-FileCopyrightText: 2003, 2004 Stephan Kulow <coolo@kde.org>
0005     SPDX-FileCopyrightText: 2004 Dirk Mueller <mueller@kde.org>
0006     SPDX-FileCopyrightText: 2006, 2007 Leo Savernik <l.savernik@aon.at>
0007     SPDX-FileCopyrightText: 2010 Milian Wolff <mail@milianw.de>
0008     SPDX-FileCopyrightText: 2013 Gerald Senarclens de Grancy <oss@senarclens.eu>
0009 
0010     SPDX-License-Identifier: LGPL-2.0-or-later
0011 */
0012 
0013 // BEGIN Includes
0014 
0015 #include "kateconfig.h"
0016 #include "katedocument.h"
0017 #include "kateglobal.h"
0018 #include "kateview.h"
0019 
0020 #include <QCryptographicHash>
0021 #include <QDir>
0022 #include <QFileInfo>
0023 #include <QJSEngine>
0024 #include <QMainWindow>
0025 #include <QProcess>
0026 #include <QStandardPaths>
0027 #include <QTest>
0028 
0029 #include <iostream>
0030 
0031 #include "script_test_base.h"
0032 #include "testutils.h"
0033 
0034 const QString testDataPath(QLatin1String(TEST_DATA_DIR));
0035 
0036 QtMessageHandler ScriptTestBase::m_msgHandler = nullptr;
0037 void noDebugMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
0038 {
0039     switch (type) {
0040     case QtDebugMsg:
0041         break;
0042     default:
0043         ScriptTestBase::m_msgHandler(type, context, msg);
0044     }
0045 }
0046 
0047 void ScriptTestBase::initTestCase()
0048 {
0049     KTextEditor::EditorPrivate::enableUnitTestMode();
0050     m_msgHandler = qInstallMessageHandler(noDebugMessageOutput);
0051     m_toplevel = new QMainWindow();
0052     m_document = new KTextEditor::DocumentPrivate(true, false, m_toplevel);
0053     m_view = static_cast<KTextEditor::ViewPrivate *>(m_document->widget());
0054     m_view->config()->setValue(KateViewConfig::AutoBrackets, false);
0055     m_env = new TestScriptEnv(m_document, m_outputWasCustomised);
0056 }
0057 
0058 void ScriptTestBase::cleanupTestCase()
0059 {
0060     qInstallMessageHandler(m_msgHandler);
0061 }
0062 
0063 void ScriptTestBase::getTestData(const QString &script)
0064 {
0065     QTest::addColumn<QString>("testcase");
0066 
0067     // make sure the script files are valid
0068     if (!m_script_dir.isEmpty()) {
0069         QFile scriptFile(QLatin1String(JS_DATA_DIR) + m_script_dir + QLatin1Char('/') + script + QLatin1String(".js"));
0070         if (scriptFile.exists()) {
0071             QVERIFY(scriptFile.open(QFile::ReadOnly));
0072             QJSValue result = m_env->engine()->evaluate(QString::fromLatin1(scriptFile.readAll()), scriptFile.fileName());
0073             QVERIFY2(!result.isError(), (result.toString() + QLatin1String(" in file ") + scriptFile.fileName()).toUtf8().constData());
0074         }
0075     }
0076 
0077     const QDir testDir(testDataPath + m_section + QLatin1Char('/') + script + QLatin1Char('/'));
0078     if (!testDir.exists()) {
0079         QSKIP(qPrintable(QString(testDir.path() + QLatin1String(" does not exist"))), SkipAll);
0080     }
0081     const auto testList = testDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name);
0082     for (const auto &info : testList) {
0083         QTest::newRow(info.baseName().toUtf8().constData()) << info.absoluteFilePath();
0084     }
0085 }
0086 
0087 /**
0088  * helper to compare files
0089  * @param refFile reference file
0090  * @param outFile output file
0091  */
0092 inline bool filesEqual(const QString &refFile, const QString &outFile)
0093 {
0094     /**
0095      * quick compare, all fine, if no diffs!
0096      * use text mode + text streams to avoid unix/windows mismatches
0097      */
0098     QFile ref(refFile);
0099     QFile out(outFile);
0100     ref.open(QIODevice::ReadOnly | QIODevice::Text);
0101     out.open(QIODevice::ReadOnly | QIODevice::Text);
0102     QTextStream refIn(&ref);
0103     QTextStream outIn(&out);
0104     const QString refContent = refIn.readAll();
0105     const QString outContent = outIn.readAll();
0106     const bool equalResults = refContent == outContent;
0107     if (equalResults) {
0108         return true;
0109     }
0110 
0111     /**
0112      * elaborate diff output, if possible
0113      */
0114     static const QString diffExecutable = QStandardPaths::findExecutable(QStringLiteral("diff"));
0115     if (!diffExecutable.isEmpty()) {
0116         QProcess proc;
0117         proc.setProcessChannelMode(QProcess::ForwardedChannels);
0118         proc.start(diffExecutable, {QStringLiteral("-u"), refFile, outFile});
0119         proc.waitForFinished();
0120     }
0121 
0122     /**
0123      * else: trivial output of mismatching characters, e.g. for windows testing without diff
0124      */
0125     else {
0126         qDebug() << "'diff' executable is not in the PATH, no difference output";
0127     }
0128 
0129     // there were diffs
0130     return false;
0131 }
0132 
0133 void ScriptTestBase::runTest(const ExpectedFailures &failures)
0134 {
0135     if (!QFile::exists(testDataPath + m_section)) {
0136         QSKIP(qPrintable(QString(testDataPath + m_section + QLatin1String(" does not exist"))), SkipAll);
0137     }
0138 
0139     QFETCH(QString, testcase);
0140 
0141     m_toplevel->resize(800, 600); // restore size
0142 
0143     // load page
0144     QUrl url;
0145     url.setScheme(QLatin1String("file"));
0146     url.setPath(testcase + QLatin1String("/origin"));
0147     m_document->openUrl(url);
0148 
0149     // evaluate test-script
0150     QFile sourceFile(testcase + QLatin1String("/input.js"));
0151     if (!sourceFile.open(QFile::ReadOnly)) {
0152         QFAIL(qPrintable(QString::fromLatin1("Failed to open file: %1").arg(sourceFile.fileName())));
0153     }
0154 
0155     QTextStream stream(&sourceFile);
0156     QString code = stream.readAll();
0157     sourceFile.close();
0158 
0159     // Execute script
0160     QJSValue result = m_env->engine()->evaluate(code, testcase + QLatin1String("/input.js"), 1);
0161     QVERIFY2(!result.isError(), result.toString().toUtf8().constData());
0162 
0163     const QString fileExpected = testcase + QLatin1String("/expected");
0164     const QString fileActual = testcase + QLatin1String("/actual");
0165 
0166     url.setPath(fileActual);
0167     m_document->saveAs(url);
0168     m_document->closeUrl();
0169 
0170     for (const Failure &failure : failures) {
0171         QEXPECT_FAIL(failure.first, failure.second, Abort);
0172     }
0173 
0174     // compare files, expected fail will invert this verify
0175     QVERIFY(filesEqual(fileExpected, fileActual));
0176 }
0177 
0178 #include "moc_script_test_base.cpp"