/*************************************************************************************
  Copyright (C) 2004 by Jeroen Wijnhout (Jeroen.Wijnhout@kdemail.net)
                2012-2024 by Michel Ludwig (michel.ludwig@kdemail.net)
 *************************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "configtester.h"

#include <okular/interfaces/viewerinterface.h>

#include <QTimer>

#include <KAboutData>
#include <KConfig>
#include <KIO/CopyJob>
#include <KJob>
#include <KLocalizedString>
#include <KPluginFactory>
#include <KProcess>

#include <QPluginLoader>
#include <QTemporaryDir>

#include "documentinfo.h"
#include "kiledebug.h"
#include "kiledocmanager.h"
#include "kiletoolmanager.h"
#include "kileinfo.h"
#include "kileconfig.h"
#include "kiletool.h"
#include "kiletool_enums.h"
#include "kileversion.h"
#include "utilities.h"

ConfigTest::ConfigTest(const QString& testGroup, const QString &name, bool isCritical)
    : m_testGroup(testGroup)
    , m_name(name)
    , m_isCritical(isCritical)
    , m_isSilent(false)
    , m_status(NotRun)
{
}

ConfigTest::~ConfigTest()
{
}

int ConfigTest::status() const
{
    return m_status;
}

QString ConfigTest::name() const
{
    return m_name;
}

QString ConfigTest::testGroup() const
{
    return m_testGroup;
}

QString ConfigTest::resultText() const
{
    return m_resultText;
}

void ConfigTest::addDependency(ConfigTest *test)
{
    m_dependencyTestList.push_back(test);
}

bool ConfigTest::allDependenciesSucceeded() const
{
    for(ConfigTest *test : m_dependencyTestList) {
        if(test->status() != Success) {
            return false;
        }
    }
    return true;
}

bool ConfigTest::isCritical() const
{
    return m_isCritical;
}

bool ConfigTest::isSilent() const
{
    return m_isSilent;
}

void ConfigTest::setSilent(bool b)
{
    m_isSilent = b;
}

void ConfigTest::setName(const QString& name)
{
    m_name = name;
}

Tester::Tester(KileInfo *kileInfo, QObject *parent)
    : QObject(parent),
      m_ki(kileInfo),
      m_tempDir(nullptr),
      m_testsDone(0)
{
    m_tempDir = new QTemporaryDir();

    setupTests();
    m_nextTestIterator = m_testList.begin();
}

Tester::~Tester()
{
    if (m_tempDir) m_tempDir->remove();
    delete m_tempDir;
    qDeleteAll(m_testList);
}

void Tester::runTests()
{
    const QString& destinationDirectory = m_tempDir->path();
    const QString& testDirectory =
#ifdef Q_OS_WIN
        KileUtilities::locate(QStandardPaths::AppDataLocation, QLatin1String("kile/test"), QStandardPaths::LocateDirectory);
#else
        KileUtilities::locate(QStandardPaths::AppDataLocation, QLatin1String("test"), QStandardPaths::LocateDirectory);
#endif
    KIO::CopyJob *copyJob = KIO::copyAs(QUrl::fromLocalFile(testDirectory), QUrl::fromLocalFile(destinationDirectory), KIO::HideProgressInfo | KIO::Overwrite);
    connect(copyJob, SIGNAL(result(KJob*)), this, SLOT(handleFileCopyResult(KJob*)));
    Q_EMIT(percentageDone(0));
}

void Tester::handleFileCopyResult(KJob* job)
{
    if(job->error()) {
        Q_EMIT(finished(false));
    }
    else {
        startNextTest();
    }
}

void Tester::addResult(const QString &tool, ConfigTest* testResult)
{
    m_results[tool].push_back(testResult);
}

QStringList Tester::testGroups()
{
    return m_results.keys();
}

QList<ConfigTest*> Tester::resultForGroup(const QString & tool)
{
    return m_results[tool];
}

// 'isCritical' is set to true iff one tool that failed was critical
int Tester::statusForGroup(const QString &testGroup, bool *isCritical)
{
    if(isCritical) {
        *isCritical = false;
    }
    QList<ConfigTest*> tests = m_results[testGroup];
    int status = ConfigTest::Success;
    for(int i = 0; i < tests.count(); ++i) {
        if(tests[i]->status() == ConfigTest::Failure) {
            if(isCritical && tests[i]->isCritical()) {
                *isCritical = true;
            }
            status = ConfigTest::Failure;
        }
    }
    return status;
}

void Tester::startNextTest()
{
    KILE_DEBUG_MAIN;
    if(m_nextTestIterator != m_testList.end()) {
        m_currentTest = *m_nextTestIterator;
        ++m_nextTestIterator;
        if(!m_currentTest->allDependenciesSucceeded()) {
            QTimer::singleShot(0, this, SLOT(startNextTest()));
            return;
        }
        // we want events to be handled inbetween tests -> QueuedConnection
        connect(m_currentTest, SIGNAL(testComplete(ConfigTest*)), this, SLOT(handleTestComplete(ConfigTest*)), Qt::QueuedConnection);
        m_currentTest->call();
    }
    else {
        Q_EMIT(percentageDone(100));
        Q_EMIT(finished(true));
    }
}

void Tester::handleTestComplete(ConfigTest *test)
{
    KILE_DEBUG_MAIN;
    if(!test->isSilent()) {
        addResult(test->testGroup(), test);
    }
    ++m_testsDone;
    Q_EMIT(percentageDone((m_testsDone / (float) m_testList.size()) * 100.0));
    startNextTest();
}


TestToolInKileTest::TestToolInKileTest(const QString& testGroup, KileInfo *kileInfo, const QString& toolName,
                                       const QString& filePath,
                                       bool isCritical)
    : ConfigTest(testGroup, i18n("Running in Kile"), isCritical),
      m_ki(kileInfo),
      m_toolName(toolName),
      m_filePath(filePath)
{
}

TestToolInKileTest::~TestToolInKileTest()
{
}

void TestToolInKileTest::call()
{
    KileDocument::TextInfo *textInfo = m_ki->docManager()->fileOpen(QUrl::fromLocalFile(m_filePath));
    if(!textInfo) {
        reportFailure();
        return;
    }
    m_documentUrl = textInfo->url();

    KileTool::Base *tool = m_ki->toolManager()->createTool(m_toolName, QString(), false);
    if(!tool) {
        m_ki->docManager()->fileClose(m_documentUrl);
        m_status = Failure;
        m_resultText = i18n("Tool not found.\n"
                            "Kile is not configured correctly. Go to Settings->Configure Kile->Tools "
                            "and either fix the problem or change to the default settings."
                           );
        Q_EMIT(testComplete(this));
        return;
    }
    // We don't want the tool to spawn subtools (especially, for LaTeX-style tools).
    // If we did, we might come into the situation that a subtool is launched before the
    // parsing is complete, which could trigger a "root document not found" error message.
    tool->setEntry(QLatin1String("autoRun"), QLatin1String("no"));
    connect(tool, SIGNAL(done(KileTool::Base*,int,bool)), this, SLOT(handleToolExit(KileTool::Base*,int,bool)), Qt::UniqueConnection);
    connect(tool, SIGNAL(failedToRun(KileTool::Base*,int)), this, SLOT(reportFailure()));
    m_ki->toolManager()->run(tool);
}

void TestToolInKileTest::reportSuccess()
{
    m_ki->docManager()->fileClose(m_documentUrl);
    m_documentUrl.clear();

    m_status = Success;
    m_resultText = i18n("Passed");
    Q_EMIT(testComplete(this));
}

void TestToolInKileTest::reportFailure()
{
    m_ki->docManager()->fileClose(m_documentUrl);
    m_documentUrl.clear();

    m_status = Failure;
    m_resultText = i18n("Failed");
    Q_EMIT(testComplete(this));
}


void TestToolInKileTest::handleToolExit(KileTool::Base *tool, int status, bool childToolSpawned)
{
    Q_UNUSED(tool);
    Q_UNUSED(childToolSpawned);

    if(status == KileTool::Success) {
        reportSuccess();
    }
    else {
        reportFailure();
    }
}

OkularVersionTest::OkularVersionTest(const QString& testGroup, bool isCritical)
    : ConfigTest(testGroup, i18n("Version"), isCritical)
{
}

OkularVersionTest::~OkularVersionTest()
{
}

void OkularVersionTest::call()
{
    QPluginLoader pluginLoader(QStringLiteral(OKULAR_LIBRARY_NAME));
    KPluginFactory *factory = qobject_cast<KPluginFactory *>(pluginLoader.instance());

    if (!factory) {
        m_status = Failure;
    }
    else {
        KParts::ReadOnlyPart *part = factory->create<KParts::ReadOnlyPart>();
        Okular::ViewerInterface *viewerInterface = qobject_cast<Okular::ViewerInterface*>(part);

        if(!viewerInterface) {
            // OkularPart doesn't provide the ViewerInterface
            m_status = Failure;
        }
        else {
            m_status = Success;
            // it seems that the version of OkularPart cannot be detected, so we don't try it
            m_resultText = i18n("Embedding of Okular is supported");
        }
        delete part;
    }

    pluginLoader.unload();

    Q_EMIT(testComplete(this));
}


FindProgramTest::FindProgramTest(const QString& testGroup, const QString& programName, bool isCritical)
    : ConfigTest(testGroup, i18n("Binary"), isCritical),
      m_programName(programName)
{
}

FindProgramTest::~FindProgramTest()
{
}

void FindProgramTest::call()
{
    QString execPath = QStandardPaths::findExecutable(m_programName);
#ifdef Q_OS_WIN
    if(execPath.isEmpty()) {
        execPath = QStandardPaths::findExecutable(m_programName, QStringList(QCoreApplication::applicationDirPath()));
    }
#endif
    bool thisIsWindowsConvertExe = false;
#ifdef Q_OS_WIN
    QFileInfo execPathInfo(execPath);
    thisIsWindowsConvertExe = (m_programName == QLatin1String("convert")) && (execPathInfo.dir().dirName() == QLatin1String("system32"));
#endif
    if(execPath.isEmpty() || thisIsWindowsConvertExe) {
        m_status = Failure;
        if(!m_additionalFailureMessage.isEmpty()) {
            if(isCritical()) {
                m_resultText = i18nc("additional failure message given as argument",
                                     "Could not find the binary for this essential tool. %1", m_additionalFailureMessage);
            }
            else {
                m_resultText = i18nc("additional failure message given as argument",
                                     "No executable '%1' found. %2", m_programName, m_additionalFailureMessage);
            }
        }
        else {
            if(isCritical()) {
                m_resultText = i18n("Could not find the binary for this essential tool");
            }
            else {
                m_resultText = i18n("No executable '%1' found", m_programName);
            }
        }
    }
    else {
        m_status = Success;
        m_resultText = i18nc("executable => path", "Found (%1 => %2)", m_programName, execPath);
    }
    Q_EMIT(testComplete(this));
}

void FindProgramTest::setAdditionalFailureMessage(const QString& s)
{
    m_additionalFailureMessage = s;
}

ProgramTest::ProgramTest(const QString& testGroup, const QString& programName, const QString& workingDir,
                         const QString& arg0,
                         const QString& arg1,
                         const QString& arg2,
                         bool isCritical)
    : ConfigTest(testGroup, i18n("Simple Test"), isCritical),
      m_testProcess(nullptr),
      m_programName(programName),
      m_workingDir(workingDir),
      m_arg0(arg0),
      m_arg1(arg1),
      m_arg2(arg2)
{
}

ProgramTest::~ProgramTest()
{
    delete m_testProcess;
}

void ProgramTest::call()
{
    m_testProcess = new KProcess();
    m_testProcess->setWorkingDirectory(m_workingDir);
    QStringList argList;
    if(!m_arg0.isEmpty()) {
        argList.push_back(m_arg0);
    }
    if(!m_arg1.isEmpty()) {
        argList.push_back(m_arg1);
    }
    if(!m_arg2.isEmpty()) {
        argList.push_back(m_arg2);
    }
    m_testProcess->setProgram(m_programName, argList);
    if (!KileConfig::teXPaths().isEmpty()) {
        m_testProcess->setEnv(QLatin1String("TEXINPUTS"), KileInfo::expandEnvironmentVars(KileConfig::teXPaths() + QLatin1String(":$TEXINPUTS")));
    }
    connect(m_testProcess, &KProcess::finished, this, &ProgramTest::handleTestProcessFinished);
    connect(m_testProcess, &KProcess::errorOccurred, this, &ProgramTest::handleTestProcessError);
    m_testProcess->start();
}

void ProgramTest::handleTestProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
    m_testProcess->deleteLater();
    m_testProcess = nullptr;

    if(exitStatus == QProcess::NormalExit && exitCode == 0) {
        processFinishedSuccessfully();
    }
    else {
        reportFailure();
    }
}

void ProgramTest::processFinishedSuccessfully()
{
    reportSuccess();
}

void ProgramTest::handleTestProcessError(QProcess::ProcessError error)
{
    Q_UNUSED(error);

    m_testProcess->deleteLater();
    m_testProcess = nullptr;
    reportFailure();
}

void ProgramTest::reportSuccess()
{
    m_resultText = i18n("Passed");
    m_status = Success;
    Q_EMIT(testComplete(this));
}

void ProgramTest::reportFailure()
{
    if(isCritical()) {
        m_resultText = i18n("This essential tool does not work; please check your installation.");
    }
    else {
        m_resultText = i18n("Failed");
    }
    m_status = Failure;
    Q_EMIT(testComplete(this));
}


LaTeXSrcSpecialsSupportTest::LaTeXSrcSpecialsSupportTest(const QString& testGroup, const QString& workingDir,
        const QString& fileBaseName)
    : ProgramTest(testGroup, QLatin1String("latex"), workingDir, QLatin1String("-src-specials"), QLatin1String("--interaction=nonstopmode"), fileBaseName + QLatin1String(".tex"), false),
      m_fileBaseName(fileBaseName)
{
    setName(i18n("Source Specials Switch"));
}

LaTeXSrcSpecialsSupportTest::~LaTeXSrcSpecialsSupportTest()
{
}

void LaTeXSrcSpecialsSupportTest::processFinishedSuccessfully()
{
    // before we can report success, we still have to perform the
    // following check:
    // src-specials are supported if the created file contains source
    // information (LaTeX doesn't report unknown command line flags as
    // errors). Hence, we now check whether the created file contains
    // the string 'src:'.
    QFile file(m_workingDir + QLatin1Char('/') + m_fileBaseName + QLatin1String(".dvi"));
    if (!file.open(QIODevice::ReadOnly)) {
        reportFailure();
        return;
    }
    // we read everything as it's a small file
    QByteArray array = file.readAll();
    file.close();
    if(!array.contains("src:")) {
        reportFailure();
        return;
    }
    reportSuccess();
}

void LaTeXSrcSpecialsSupportTest::reportSuccess()
{
    m_resultText = i18n("Supported, use the 'Modern' configuration for (La)TeX to auto-enable inverse and forward search capabilities.");
    m_status = Success;
    Q_EMIT(testComplete(this));
}

void LaTeXSrcSpecialsSupportTest::reportFailure()
{
    m_resultText = i18n("Not supported, use the srcltx package to enable the inverse and forward search capabilities.");
    m_status = Failure;
    Q_EMIT(testComplete(this));
}


SyncTeXSupportTest::SyncTeXSupportTest(const QString& testGroup, const QString& toolName, const QString& workingDir,
                                       const QString& fileBaseName)
    : ProgramTest(testGroup, toolName, workingDir, QLatin1String("-synctex=1"), QLatin1String("--interaction=nonstopmode"), fileBaseName + QLatin1String(".tex"), false),
      m_fileBaseName(fileBaseName)
{
    setName(i18n("SyncTeX Support"));
}

SyncTeXSupportTest::~SyncTeXSupportTest()
{
}

void SyncTeXSupportTest::reportSuccess()
{
    m_resultText = i18n("Supported, use the 'Modern' configuration for PDFLaTeX and XeLaTeX to auto-enable inverse and forward search capabilities.");
    m_status = Success;
    Q_EMIT(testComplete(this));
}

void SyncTeXSupportTest::reportFailure()
{
    m_resultText = i18n("Not supported");
    m_status = Failure;
    Q_EMIT(testComplete(this));
}

void SyncTeXSupportTest::processFinishedSuccessfully()
{
    // before we can report success, we still have to check
    // whether a .synctex.gz file has been generated
    QFile file(m_workingDir + QLatin1Char('/') + m_fileBaseName + QLatin1String(".synctex.gz"));
    if (!file.exists()) {
        reportFailure();
        return;
    }
    reportSuccess();
}

void Tester::installConsecutivelyDependentTests(ConfigTest *t1, ConfigTest *t2, ConfigTest *t3, ConfigTest *t4)
{
    if(!t1) {
        return;
    }
    m_testList.push_back(t1);
    if(!t2) {
        return;
    }
    t2->addDependency(t1);
    m_testList.push_back(t2);
    if(!t3) {
        return;
    }
    t3->addDependency(t2);
    m_testList.push_back(t3);
    if(!t4) {
        return;
    }
    t4->addDependency(t3);
    m_testList.push_back(t4);
}

void Tester::setupTests()
{

    /*
    testFile=test_plain.tex
    echo "opening $basedir/$testFile"
    $openDoc"$basedir/$testFile"

    echo "starting test: TeX"
    setTool TeX
    tool="tex --interaction=nonstopmode"
    setKey mustpass "where,basic,kile"
    setKey executable tex
    setKey where `which tex`
    setKey version `getTeXVersion tex`
    performTest basic "$tool test_plain.tex"
    performKileTest kile "run TeX"
    */
    installConsecutivelyDependentTests(
        new FindProgramTest(QLatin1String("TeX"), QLatin1String("tex"), true),
        new ProgramTest(QLatin1String("TeX"), QLatin1String("tex"), m_tempDir->path(), QLatin1String("--interaction=nonstopmode"),  QLatin1String("test_plain.tex"), QString(), true),
        new TestToolInKileTest(QLatin1String("TeX"), m_ki, QLatin1String("TeX"), m_tempDir->path() + QLatin1Char('/') + QLatin1String("test_plain.tex"), true));
    /*
    echo "starting test: PDFTeX"
    setTool PDFTeX
    tool="pdftex --interaction=nonstopmode"
    setKey mustpass ""
    setKey executable pdftex
    setKey where `which pdftex`
    performTest basic "$tool test_plain.tex"
    performKileTest kile "run PDFTeX"
    $closeDoc
    */
    installConsecutivelyDependentTests(
        new FindProgramTest(QLatin1String("PDFTeX"), QLatin1String("pdftex"), false),
        new ProgramTest(QLatin1String("PDFTeX"), QLatin1String("pdftex"), m_tempDir->path(), QLatin1String("--interaction=nonstopmode"), QLatin1String("test_plain.tex"), QString(), false),
        new TestToolInKileTest(QLatin1String("PDFTeX"), m_ki, QLatin1String("PDFTeX"), m_tempDir->path() + QLatin1Char('/') + QLatin1String("test_plain.tex"), false));
    /*
    testFileBase="test"
    testFile=$testFileBase.tex
    echo "opening $basedir/$testFile"
    $openDoc"$basedir/$testFile"
    echo "starting test: LaTeX"
    setTool LaTeX
    tool="latex --interaction=nonstopmode"
    setKey mustpass "where,basic,kile"
    setKey executable latex
    setKey where `which latex`
    performTest basic "$tool $testFile"
    performKileTest kile "run LaTeX"
    performTest src "$tool -src $testFile"
    */
    ProgramTest *latexProgramTest = new ProgramTest(QLatin1String("LaTeX"), QLatin1String("latex"), m_tempDir->path(), QLatin1String("--interaction=nonstopmode"),  QLatin1String("test.tex"), QString(), true);
    m_laTeXSrcSpecialsSupportTest = new LaTeXSrcSpecialsSupportTest(QLatin1String("LaTeX"), m_tempDir->path(), QLatin1String("test"));
    installConsecutivelyDependentTests(
        new FindProgramTest(QLatin1String("LaTeX"), QLatin1String("latex"), true),
        latexProgramTest,
        new TestToolInKileTest(QLatin1String("LaTeX"), m_ki, QLatin1String("LaTeX"), m_tempDir->path() + QLatin1Char('/') + QLatin1String("test.tex"), true),
        m_laTeXSrcSpecialsSupportTest);
    /*
    echo "starting test: PDFLaTeX"
    setTool PDFLaTeX
    setKey mustpass ""
    setKey executable pdflatex
    setKey where `which pdflatex`
    performTest basic "pdflatex $testFile"
    performKileTest kile "run PDFLaTeX"
    */
    m_pdfLaTeXSyncTeXSupportTest = new SyncTeXSupportTest(QLatin1String("PDFLaTeX"), QLatin1String("pdflatex"), m_tempDir->path(), QLatin1String("test"));
    installConsecutivelyDependentTests(
        new FindProgramTest(QLatin1String("PDFLaTeX"), QLatin1String("pdflatex"), false),
        new ProgramTest(QLatin1String("PDFLaTeX"), QLatin1String("pdflatex"), m_tempDir->path(), QLatin1String("--interaction=nonstopmode"),  QLatin1String("test.tex"), QString(), false),
        new TestToolInKileTest(QLatin1String("PDFLaTeX"), m_ki, QLatin1String("PDFLaTeX"), m_tempDir->path() + QLatin1Char('/') + QLatin1String("test.tex"), false),
        m_pdfLaTeXSyncTeXSupportTest);
    /*
    echo "starting test: DVItoPS"
    setTool DVItoPS
    setKey mustpass ""
    setKey executable dvips
    setKey where `which dvips`
    if [ -r $testFileBase.dvi ]; then performKileTest kile "run DVItoPS"; fi
    */
    TestToolInKileTest *dvipsKileTest = new TestToolInKileTest(QLatin1String("DVItoPS"), m_ki, QLatin1String("DVItoPS"), m_tempDir->path() + QLatin1Char('/') + QLatin1String("test.tex"), false);
    dvipsKileTest->addDependency(latexProgramTest);
    installConsecutivelyDependentTests(
        new FindProgramTest(QLatin1String("DVItoPS"), QLatin1String("dvips"), false),
        dvipsKileTest);
    /*
    echo "starting test: DVItoPDF"
    setTool DVItoPDF
    setKey mustpass ""
    setKey executable dvipdfmx
    setKey where `which dvipdfmx`
    if [ -r $testFileBase.dvi ]; then performKileTest kile "run DVItoPDF"; fi
    */
    TestToolInKileTest *dvipdfmxKileTest = new TestToolInKileTest(QLatin1String("DVItoPDF"), m_ki, QLatin1String("DVItoPDF"), m_tempDir->path() + QLatin1Char('/') + QLatin1String("test.tex"), false);
    dvipdfmxKileTest->addDependency(latexProgramTest);
    installConsecutivelyDependentTests(
        new FindProgramTest(QLatin1String("DVItoPDF"), QLatin1String("dvipdfmx"), false),
        dvipdfmxKileTest);
    /*
    echo "starting test: PStoPDF"
    setTool PStoPDF
    setKey mustpass ""
    setKey executable ps2pdf
    setKey where `which ps2pdf`
    if [ -r $testFileBase.ps ]; then performKileTest kile "run PStoPDF"; fi
    $closeDoc
    */
    TestToolInKileTest *ps2pdfKileTest = new TestToolInKileTest(QLatin1String("PStoPDF"), m_ki, QLatin1String("PStoPDF"), m_tempDir->path() + QLatin1Char('/') + QLatin1String("test.tex"), false);
    ps2pdfKileTest->addDependency(dvipsKileTest);
    installConsecutivelyDependentTests(
        new FindProgramTest(QLatin1String("PStoPDF"), QLatin1String("ps2pdf"), false),
        ps2pdfKileTest);
    /*
    echo "starting test: BibTeX"
    setTool BibTeX
    setKey mustpass ""
    setKey executable bibtex
    setKey where `which bibtex`
    if [ -r "test.dvi" ] #LaTeX is working
    then
    	testFileBase=test_bib
    	testFile=$testFileBase.tex
    	$openDoc"$basedir/$testFile"
    	latex --interaction=nonstopmode $testFile
    	performTest basic "bibtex $testFileBase"
    	performKileTest kile "run BibTeX"
    	$closeDoc
    fi
    */
    TestToolInKileTest *latexForBibTeX = new TestToolInKileTest(QLatin1String("BibTeX"), m_ki, QLatin1String("LaTeX"), m_tempDir->path() + QLatin1Char('/') + QLatin1String("test_bib.tex"), false);
    latexForBibTeX->addDependency(latexProgramTest);
    latexForBibTeX->setSilent(true);
    ProgramTest *bibtexProgramTest = new ProgramTest(QLatin1String("BibTeX"), QLatin1String("bibtex"), m_tempDir->path(), QLatin1String("test_bib"),  QString(), QString(), false);
    bibtexProgramTest->addDependency(latexForBibTeX);
    TestToolInKileTest *bibtexKileTest = new TestToolInKileTest(QLatin1String("BibTeX"), m_ki, QLatin1String("BibTeX"), m_tempDir->path() + QLatin1Char('/') + QLatin1String("test_bib.tex"), false);
    bibtexKileTest->addDependency(latexProgramTest);
    installConsecutivelyDependentTests(
        new FindProgramTest(QLatin1String("BibTeX"), QLatin1String("bibtex"), false),
        latexForBibTeX,
        bibtexProgramTest,
        bibtexKileTest);
    /*
    echo "starting test: MakeIndex"
    setTool MakeIndex
    setKey mustpass ""
    setKey executable makeindex
    setKey where `which makeindex`

    if [ -r "test.dvi" ] #LaTeX is working
    then
    	testFileBase=test_index
    	testFile=$testFileBase.tex
    	$openDoc"$basedir/$testFile"
    	latex --interaction=nonstopmode $testFile
    	performTest basic "makeindex $testFileBase"
    	performKileTest kile "run MakeIndex"
    	$closeDoc
    fi
    */
    TestToolInKileTest *latexForMakeIndex = new TestToolInKileTest(QLatin1String("MakeIndex"), m_ki, QLatin1String("LaTeX"), m_tempDir->path() + QLatin1Char('/') + QLatin1String("test_index.tex"), false);
    latexForMakeIndex->addDependency(latexProgramTest);
    latexForMakeIndex->setSilent(true);
    ProgramTest *makeIndexProgramTest = new ProgramTest(QLatin1String("MakeIndex"), QLatin1String("makeindex"), m_tempDir->path(), QLatin1String("test_index"),  QString(), QString(), false);
    makeIndexProgramTest->addDependency(latexProgramTest);
    TestToolInKileTest *makeindexKileTest = new TestToolInKileTest(QLatin1String("MakeIndex"), m_ki, QLatin1String("MakeIndex"), m_tempDir->path() + QLatin1Char('/') + QLatin1String("test_index.tex"), false);
    makeindexKileTest->addDependency(latexProgramTest);
    installConsecutivelyDependentTests(
        new FindProgramTest(QLatin1String("MakeIndex"), QLatin1String("makeindex"), false),
        latexForMakeIndex,
        makeIndexProgramTest,
        makeindexKileTest);
    /*
    echo "starting test: Okular"
    setTool Okular
    setKey mustpass "where"
    setKey executable okular
    setKey version `getOkularVersion okular`
    performTest okular "isTheOkularVersionRecentEnough"
    setKey where `which okular`
    */
    m_okularVersionTest = new OkularVersionTest(QLatin1String("Okular"), false);
    installConsecutivelyDependentTests(
        new FindProgramTest(QLatin1String("Okular"), QLatin1String("okular"), false),
        m_okularVersionTest);
    /*
    echo "starting test: Acroread"
    setTool Acroread
    setKey mustpass ""
    setKey executable acroread
    setKey where `which acroread`
    */

    /*
    echo "starting test: DVItoPNG"
    setTool DVItoPNG
    setKey mustpass ""
    setKey executable dvipng
    setKey where `which dvipng`
    */
    FindProgramTest *dvipngProgramTest = new FindProgramTest(QLatin1String("DVItoPNG"), QLatin1String("dvipng"), false);
    dvipngProgramTest->setAdditionalFailureMessage(i18n("PNG previews cannot be used for mathgroups in the bottom preview pane"));
    m_testList.push_back(dvipngProgramTest);
    /*
    echo "starting test: Convert"
    setTool Convert
    setKey mustpass ""
    setKey executable convert
    setKey where `which convert`
    */
    FindProgramTest *convertProgramTest = new FindProgramTest(QLatin1String("Convert"), QLatin1String("convert"), false);
    convertProgramTest->setAdditionalFailureMessage(i18n("PNG previews cannot be used with conversions 'dvi->ps->png' and 'pdf->png' in the bottom preview pane"));
    m_testList.push_back(convertProgramTest);
}

bool Tester::isSyncTeXSupportedForPDFLaTeX()
{
    return (m_pdfLaTeXSyncTeXSupportTest->status() == ConfigTest::Success);
}

bool Tester::isViewerModeSupportedInOkular()
{
    return (m_okularVersionTest->status() == ConfigTest::Success);
}

bool Tester::areSrcSpecialsSupportedForLaTeX()
{
    return (m_laTeXSrcSpecialsSupportTest->status() == ConfigTest::Success);
}

