/*
    SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
    SPDX-FileCopyrightText: 2025 Archaeopteryx Lithographica
*/

#include <QStandardPaths>
#include <QTest>
#include <QUrlQuery>

#include <KIO/ListJob>

#include <filesystem>

class FilenameSearchTest : public QObject
{
    Q_OBJECT
private Q_SLOTS:

    QUrl buildSearchQuery(QByteArray searchString, QByteArray searchOptions, QString path);
    QByteArrayList doSearchQuery(QUrl url, KIO::ListJob::ListFlags listFlags);

    void initTestCase();

    void optionCase_data();
    void optionCase();

    void stringMatch_data();
    void stringMatch();

    void phraseMatch_data();
    void phraseMatch();

    void regexMatch_data();
    void regexMatch();

    void wordListMatch_data();
    void wordListMatch();

    void filenameContent_data();
    void filenameContent();

    void folderTree_data();
    void folderTree();

    void folderTreeSymlinks_data();
    void folderTreeSymlinks();

    void hiddenFiles_data();
    void hiddenFiles();

    void hiddenFolders_data();
    void hiddenFolders();

    void hiddenFilesAndFolders_data();
    void hiddenFilesAndFolders();

    void cleanupTestCase();

private:
    QString m_workingFolder = "";
};

namespace
{

void addColumns()
{
    QTest::addColumn<QByteArray>("searchOptions");
    QTest::addColumn<QByteArray>("searchString");
    QTest::addColumn<QByteArrayList>("expectedFiles");
};

auto addRow = [](const char *name, const QByteArray &searchOptions, const QByteArray &searchString, const QByteArrayList &expectedFiles) {
    QTest::addRow("%s", name) << searchOptions << searchString << expectedFiles;
};
}

QUrl FilenameSearchTest::buildSearchQuery(QByteArray searchString, QByteArray searchOptions, QString path)
{
    //  Encode the testfile directory

    QUrl searchFrom;
    searchFrom.setPath(QString(QUrl::toPercentEncoding(QStringLiteral("file://") + path)), QUrl::StrictMode);

    //  Parse the search options, create a map and build the query
    //  Add a "src=internal" option to all queries

    QUrlQuery queryOptions(searchOptions);
    QList<QPair<QString, QString>> map = {{QStringLiteral("search"), QString(searchString)}};
    map.append({{QStringLiteral("src"), QStringLiteral("internal")}});
    map.append({{QStringLiteral("url"), searchFrom.toString()}});
    map.append(queryOptions.queryItems());

    QUrlQuery urlQuery;
    urlQuery.setQueryItems(map);

    //  Build the search Url

    QUrl url;
    url.setScheme("filenamesearch");
    url.setQuery(urlQuery);

    return (url);
}

QByteArrayList FilenameSearchTest::doSearchQuery(QUrl url, KIO::ListJob::ListFlags listFlags)
{
    QByteArrayList results;

    KIO::ListJob *listJob = KIO::listDir(url, KIO::HideProgressInfo, listFlags);

    connect(this, &QObject::destroyed, listJob, [listJob]() {
        listJob->kill();
    });

    //  ListJob with IncludeHidden will read the match for "."

    connect(listJob, &KIO::ListJob::entries, this, [&](KJob *, const KIO::UDSEntryList &list) {
        if (listJob->error()) {
            qWarning() << "Searching failed:" << listJob->errorText();
            return;
        }

        for (auto entry : list) {
            const QByteArray fileName = entry.stringValue(KIO::UDSEntry::UDS_NAME).toUtf8();
            if (fileName != QByteArrayLiteral(".")) {
                results += fileName;
            }
        }
    });

    listJob->exec();

    std::sort(results.begin(), results.end());
    return results;
}

void FilenameSearchTest::initTestCase()
{
    const QString sourcePath = QFINDTESTDATA("data/folderTree");
    QString destinationPath = sourcePath;
    destinationPath.replace("/folderTree", "/folderTreeSymlinks");

    if (sourcePath.indexOf(QStringLiteral("filenamesearch/autotests/data")) < 0) {
        qInfo() << "Cannot find location of \"data/folderTree\"";
        m_workingFolder = "";
        return;
    } else {
        QDir destination(destinationPath);
        if (destination.removeRecursively()) {
            m_workingFolder = "";
        }
    }

    //  Programatically add a .bak file to the test data, a static file fails an audit
    //  when being uploaded to invent. Use QFile::copy

    QFile::remove(sourcePath + QStringLiteral("/alice1.txt.bak"));

    if (!QFile::copy(sourcePath + QStringLiteral("/alice1.txt"), sourcePath + QStringLiteral("/alice1.txt.bak"))) {
        qInfo() << "Failed copying testfile alice1.txt to alice1.txt.bak";
    }

    //  Use std::filesystem::copy to copy folderTree as there's not a Qt equivalent.

    std::error_code result;
    std::filesystem::path sourceStdPath(sourcePath.toStdString());
    std::filesystem::path destinationStdPath(destinationPath.toStdString());

    std::filesystem::copy(sourceStdPath, destinationStdPath, std::filesystem::copy_options::recursive | std::filesystem::copy_options::skip_symlinks, result);

    if (result.value() != 0) {
        qWarning() << "Copy failed" << result.message();
        m_workingFolder = "";
    } else {
        m_workingFolder = destinationPath;
        const QString childParentLink = destinationPath + QStringLiteral("/child/parent");
        const QString grandchildParentLink = destinationPath + QStringLiteral("/child/grandchild/parent");
        const QString grandchildGrandparentLink = destinationPath + QStringLiteral("/child/grandchild/grandparent");
        QFile::link(QStringLiteral("../"), childParentLink);
        QFile::link(QStringLiteral("../"), grandchildParentLink);
        QFile::link(QStringLiteral("../../"), grandchildGrandparentLink);

        const QString hiddenChildParentLink = destinationPath + QStringLiteral("/.child/parent");
        QFile::link(QStringLiteral("../"), hiddenChildParentLink);
    }
};

void FilenameSearchTest::cleanupTestCase()
{
    const QString sourcePath = QFINDTESTDATA("data/folderTree");
    if (sourcePath.indexOf(QStringLiteral("filenamesearch/autotests/data")) > 0) {
        QFile::remove(sourcePath + QStringLiteral("/alice1.txt.bak"));
    }

    if (m_workingFolder.indexOf(QStringLiteral("filenamesearch/autotests/data")) >= 0) {
        QDir dir(m_workingFolder);
        if (!dir.removeRecursively()) {
            qWarning() << "Failed to clean:" << m_workingFolder;
        }
    }
};

//  TODO: the optionCase test relies on filenameContent, ought to have an option/query that does not depend on test files.

void FilenameSearchTest::optionCase_data()
{
    addColumns();

    addRow("No Match", QByteArrayLiteral("checkContent=no"), QByteArrayLiteral("curiouser"), {});
    addRow("Lower Case", QByteArrayLiteral("checkContent=yes"), QByteArrayLiteral("curiouser"), {QByteArrayLiteral("alice2.txt")});
    addRow("Mixed Case", QByteArrayLiteral("checkContent=Yes"), QByteArrayLiteral("curiouser"), {QByteArrayLiteral("alice2.txt")});
    addRow("Upper Case", QByteArrayLiteral("checkContent=YES"), QByteArrayLiteral("curiouser"), {QByteArrayLiteral("alice2.txt")});
}

void FilenameSearchTest::optionCase()
{
    QFETCH(QByteArray, searchOptions);
    QFETCH(QByteArray, searchString);
    QFETCH(QByteArrayList, expectedFiles);

    const QString path = QFINDTESTDATA("data/filename-content");
    QByteArrayList results = doSearchQuery(buildSearchQuery(searchString, searchOptions, path), {});

    QCOMPARE(results, expectedFiles);
}

void FilenameSearchTest::stringMatch_data()
{
    addColumns();

    addRow("No Filename Match", QByteArray(""), QByteArrayLiteral("Cheshire"), {});
    addRow("Filename Match", QByteArray(""), QByteArrayLiteral("alice.txt"), {QByteArrayLiteral("alice.txt")});
    addRow("Filename Word Match", QByteArray(""), QByteArrayLiteral("alice"), {QByteArrayLiteral("alice.txt")});
    addRow("Filename Extension Match",
           QByteArray(""),
           QByteArrayLiteral(".txt"),
           {QByteArrayLiteral("Rabbit.TXT"), QByteArrayLiteral("alice.txt"), QByteArrayLiteral("rabbit.txt"), QByteArrayLiteral("walrus.txt")});
    addRow("Filename Leading Substring Match", QByteArray(""), QByteArrayLiteral("alic"), {QByteArrayLiteral("alice.txt")});
    addRow("Filename Trailing Substring Match", QByteArray(""), QByteArrayLiteral("lice.txt"), {QByteArrayLiteral("alice.txt")});
    addRow("Filename Substring Match", QByteArray(""), QByteArrayLiteral("lic"), {QByteArrayLiteral("alice.txt")});
    addRow("Filename Case Insensitive Match", QByteArray(""), QByteArrayLiteral("rabbit"), {QByteArrayLiteral("Rabbit.TXT"), QByteArrayLiteral("rabbit.txt")});

    addRow("No Content Match", QByteArray("checkContent=yes"), QByteArrayLiteral("Cheshire"), {});
    addRow("Content Word Match", QByteArray("checkContent=yes"), QByteArrayLiteral("Wonderland"), {QByteArrayLiteral("alice.txt")});
    addRow("Content Leading Substring Match", QByteArray("checkContent=yes"), QByteArrayLiteral("Wonder"), {QByteArrayLiteral("alice.txt")});
    addRow("Content Trailing Substring Match", QByteArray("checkContent=yes"), QByteArrayLiteral("land"), {QByteArrayLiteral("alice.txt")});
    addRow("Content Substring Match", QByteArray("checkContent=yes"), QByteArrayLiteral("derl"), {QByteArrayLiteral("alice.txt")});
    addRow("Content Case Insensitive Match",
           QByteArray("checkContent=yes"),
           QByteArrayLiteral("white"),
           {QByteArrayLiteral("Rabbit.TXT"), QByteArrayLiteral("rabbit.txt")});

    addRow("Content Word Apostrophe Match", QByteArray("checkContent=yes"), QByteArrayLiteral("Alice's"), {QByteArrayLiteral("alice.txt")});
    addRow("Content Word Escaped Apostrophe Match", QByteArray("checkContent=yes"), QByteArrayLiteral("Alice\'s"), {QByteArrayLiteral("alice.txt")});
}

void FilenameSearchTest::stringMatch()
{
    QFETCH(QByteArray, searchOptions);
    QFETCH(QByteArray, searchString);
    QFETCH(QByteArrayList, expectedFiles);

    const QString path = QFINDTESTDATA("data/stringMatch");
    QByteArrayList results = doSearchQuery(buildSearchQuery(searchString, searchOptions, path), {});

    QCOMPARE(results, expectedFiles);
}

void FilenameSearchTest::phraseMatch_data()
{
    addColumns();

    addRow("No Content Phrase Match", QByteArray("syntax=phrase&checkContent=yes"), QByteArrayLiteral("Cheshire Cat"), {});
    addRow("Content Exact Phrase Match",
           QByteArray("syntax=phrase&checkContent=yes"),
           QByteArrayLiteral("Adventures in Wonderland"),
           {QByteArrayLiteral("alice.txt")});

    //  Check explicit phrase syntax searches

    addRow("Filename Phrase Query with Phrase Match", QByteArray("syntax=phrase"), QByteArrayLiteral("alice"), {QByteArrayLiteral("alice.txt")});
    addRow("Filename Phrase Query with Regex Match", QByteArray("syntax=phrase"), QByteArrayLiteral("al.*ce"), {});
    addRow("Content Phrase Query with Phrase Match",
           QByteArray("syntax=phrase&checkContent=yes"),
           QByteArrayLiteral("Adventures in Wonderland"),
           {QByteArrayLiteral("alice.txt")});
    addRow("No Content Phrase Query with Regex Match", QByteArray("syntax=phrase&checkContent=yes"), QByteArrayLiteral("Advent.* in Wond.*"), {});
}

void FilenameSearchTest::phraseMatch()
{
    QFETCH(QByteArray, searchOptions);
    QFETCH(QByteArray, searchString);
    QFETCH(QByteArrayList, expectedFiles);

    const QString path = QFINDTESTDATA("data/stringMatch");
    QByteArrayList results = doSearchQuery(buildSearchQuery(searchString, searchOptions, path), {});

    QCOMPARE(results, expectedFiles);
}

void FilenameSearchTest::regexMatch_data()
{
    addColumns();

    addRow("Filename Regex Query with Regex Match", QByteArray("syntax=regex"), QByteArrayLiteral("al.*ce"), {QByteArrayLiteral("alice.txt")});
    addRow("Content Regex Query with Regex Match",
           QByteArray("syntax=regex&checkContent=yes"),
           QByteArrayLiteral("Advent.* in Wond.*"),
           {QByteArrayLiteral("alice.txt")});

    addRow("Content Start of String Match",
           QByteArrayLiteral("syntax=regex&checkContent=yes"),
           QByteArrayLiteral("^Walrus"),
           {QByteArrayLiteral("walrus.txt")});
    addRow("No Content Start of String Match", QByteArrayLiteral("syntax=regex&checkContent=yes"), QByteArrayLiteral("^Carpenter"), {});
    addRow("Content End of String Match",
           QByteArrayLiteral("syntax=regex&checkContent=yes"),
           QByteArrayLiteral("Carpenter$"),
           {QByteArrayLiteral("walrus.txt")});
    addRow("No Content End of String Match", QByteArrayLiteral("syntax=regex&checkContent=yes"), QByteArrayLiteral("Walrus$"), {});

    addRow("Content Word Escaped Backslash Match",
           QByteArray("syntax=regex&checkContent=yes"),
           QByteArrayLiteral("Alice\\'s"),
           {QByteArrayLiteral("alice.txt")});

    addRow("Content Invalid Regular Expression", QByteArrayLiteral("syntax=regex&checkContent=yes"), QByteArrayLiteral("+"), {});
    addRow("Content Escaped Regex Special Character",
           QByteArrayLiteral("syntax=regex&checkContent=yes"),
           QByteArrayLiteral("\\+"),
           {QByteArrayLiteral("walrus.txt")});
    addRow("No Content Escaped Regex Special Character", QByteArrayLiteral("syntax=regex&checkContent=yes"), QByteArrayLiteral("\\*"), {});
}

void FilenameSearchTest::regexMatch()
{
    QFETCH(QByteArray, searchOptions);
    QFETCH(QByteArray, searchString);
    QFETCH(QByteArrayList, expectedFiles);

    const QString path = QFINDTESTDATA("data/stringMatch");
    QByteArrayList results = doSearchQuery(buildSearchQuery(searchString, searchOptions, path), {});

    QCOMPARE(results, expectedFiles);
}

void FilenameSearchTest::wordListMatch_data()
{
    addColumns();

    //  Check searches for collections of words work rather than exact phrases.

    addRow("Content Soup Match", QByteArray("syntax=wordList&checkContent=yes"), QByteArrayLiteral("Adventures Wonderland"), {QByteArrayLiteral("alice.txt")});
    addRow("Content Random Soup Match",
           QByteArray("syntax=wordList&checkContent=yes"),
           QByteArrayLiteral("Wonderland Adventures"),
           {QByteArrayLiteral("alice.txt")});
    addRow("Content Quoted Phrase Match",
           QByteArray("syntax=wordList&checkContent=yes"),
           QByteArrayLiteral("'Adventures in Wonderland'"),
           {QByteArrayLiteral("alice.txt")});
    addRow("Content Underscore Separated Phrase Match",
           QByteArray("syntax=wordList&checkContent=yes"),
           QByteArrayLiteral("Adventures_in_Wonderland"),
           {QByteArrayLiteral("alice.txt")});
    addRow("Content Quoted Multiline Phrase Match",
           QByteArray("syntax=wordList&checkContent=yes"),
           QByteArrayLiteral("'Wonderland Lewis'"),
           {QByteArrayLiteral("alice.txt")});
    addRow("No Content Single Quoted Phrase Match", QByteArray("syntax=wordList&checkContent=yes"), QByteArrayLiteral("'Wonderland Adventures'"), {});
    addRow("No Content Double Quoted Phrase Match", QByteArray("syntax=wordList&checkContent=yes"), QByteArrayLiteral("\"Wonderland Adventures\""), {});
    addRow("No Content Underscore Separated Phrase Match", QByteArray("syntax=wordList&checkContent=yes"), QByteArrayLiteral("Wonderland_Adventures"), {});
    addRow("Content Quoted Phrases Match",
           QByteArray("syntax=wordList&checkContent=yes"),
           QByteArrayLiteral("\"Adventures in Wonderland\" 'Lewis Carroll'"),
           {QByteArrayLiteral("alice.txt")});
    addRow("Content Single Quoted Apostrophe Match",
           QByteArray("syntax=wordList&checkContent=yes"),
           QByteArrayLiteral("'Alice's Adventures'"),
           {QByteArrayLiteral("alice.txt")});
    addRow("Content Double Quoted Apostrophe Match",
           QByteArray("syntax=wordList&checkContent=yes"),
           QByteArrayLiteral("\"Alice's Adventures\""),
           {QByteArrayLiteral("alice.txt")});
    addRow("Content Underscore Separated Apostrophe Match",
           QByteArray("syntax=wordList&checkContent=yes"),
           QByteArrayLiteral("Alice's_Adventures"),
           {QByteArrayLiteral("alice.txt")});
    addRow("Content Single Quoted Escaped Apostrophe Match",
           QByteArray("syntax=wordList&checkContent=yes"),
           QByteArrayLiteral("'Alice\\'s Adventures'"),
           {QByteArrayLiteral("alice.txt")});
    addRow("Content Double Quoted Escaped Apostrophe Match",
           QByteArray("syntax=wordList&checkContent=yes"),
           QByteArrayLiteral("\"Alice\\'s Adventures\""),
           {QByteArrayLiteral("alice.txt")});

    addRow("Content Regex Special Character", QByteArrayLiteral("syntax=wordList&checkContent=yes"), QByteArrayLiteral("+"), {QByteArrayLiteral("walrus.txt")});
    addRow("No Content Escaped Regex Special Character", QByteArrayLiteral("syntax=wordList&checkContent=yes"), QByteArrayLiteral("\\*"), {});
    addRow("No Content Quoted Regex Special Character", QByteArrayLiteral("syntax=wordList&checkContent=yes"), QByteArrayLiteral("'*'"), {});
}

void FilenameSearchTest::wordListMatch()
{
    QFETCH(QByteArray, searchOptions);
    QFETCH(QByteArray, searchString);
    QFETCH(QByteArrayList, expectedFiles);

    const QString path = QFINDTESTDATA("data/stringMatch");
    QByteArrayList results = doSearchQuery(buildSearchQuery(searchString, searchOptions, path), {});

    QCOMPARE(results, expectedFiles);
}

void FilenameSearchTest::filenameContent_data()
{
    addColumns();

    addRow("Filename Match", QByteArrayLiteral(""), QByteArrayLiteral("alice1"), {QByteArrayLiteral("alice1.txt")});

    addRow("Content Match", QByteArrayLiteral("checkContent=yes"), QByteArrayLiteral("curiouser"), {QByteArrayLiteral("alice2.txt")});

    addRow("Filename and Content Match",
           QByteArrayLiteral("checkContent=yes"),
           QByteArrayLiteral("alice"),
           {QByteArrayLiteral("alice1.txt"), QByteArrayLiteral("alice2.txt")});
}

void FilenameSearchTest::filenameContent()
{
    QFETCH(QByteArray, searchOptions);
    QFETCH(QByteArray, searchString);
    QFETCH(QByteArrayList, expectedFiles);

    const QString path = QFINDTESTDATA("data/filename-content");
    QByteArrayList results = doSearchQuery(buildSearchQuery(searchString, searchOptions, path), {});

    QCOMPARE(results, expectedFiles);
}

//  Search including hidden files, to catch the .bak (that may be considered hidden)

void FilenameSearchTest::folderTree_data()
{
    addColumns();

    addRow("Filename Match",
           QByteArray(""),
           QByteArrayLiteral("alice"),
           {QByteArrayLiteral("alice1.txt"), QByteArrayLiteral("alice1.txt.bak"), QByteArrayLiteral("alice2.txt"), QByteArrayLiteral("alice3.txt")});

    addRow("Content Match",
           QByteArray("checkContent=yes"),
           QByteArrayLiteral("wonderland"),
           {QByteArrayLiteral("alice1.txt"), QByteArrayLiteral("alice2.txt"), QByteArrayLiteral("alice3.txt")});
}

void FilenameSearchTest::folderTree()
{
    QFETCH(QByteArray, searchOptions);
    QFETCH(QByteArray, searchString);
    QFETCH(QByteArrayList, expectedFiles);

    const QString path = QFINDTESTDATA("data/folderTree");
    QByteArrayList results = doSearchQuery(buildSearchQuery(searchString, searchOptions, path), {KIO::ListJob::ListFlag::IncludeHidden});

    QCOMPARE(results, expectedFiles);
}

//  A filename search for "alice" finds the .bak, backup file,
//  however a content search does not consider .bak text/plain.

void FilenameSearchTest::folderTreeSymlinks_data()
{
    addColumns();

    addRow("Filename Match",
           QByteArray(""),
           QByteArrayLiteral("alice"),
           {QByteArrayLiteral("alice1.txt"), QByteArrayLiteral("alice1.txt.bak"), QByteArrayLiteral("alice2.txt"), QByteArrayLiteral("alice3.txt")});

    addRow("Content Match",
           QByteArray("checkContent=yes"),
           QByteArrayLiteral("wonderland"),
           {QByteArrayLiteral("alice1.txt"), QByteArrayLiteral("alice2.txt"), QByteArrayLiteral("alice3.txt")});
}

void FilenameSearchTest::folderTreeSymlinks()
{
    QFETCH(QByteArray, searchOptions);
    QFETCH(QByteArray, searchString);
    QFETCH(QByteArrayList, expectedFiles);

    const QString path = QFINDTESTDATA("data/folderTreeSymlinks/child");
    QByteArrayList results = doSearchQuery(buildSearchQuery(searchString, searchOptions, path), {});

    QCOMPARE(results, expectedFiles);
}

void FilenameSearchTest::hiddenFiles_data()
{
    addColumns();

    addRow("Filename Match",
           QByteArray("includeHidden=files"),
           QByteArrayLiteral("alice"),
           {QByteArrayLiteral(".alice2.txt"), QByteArrayLiteral("alice1.txt")});

    addRow("Content Match",
           QByteArray("includeHidden=files&checkContent=yes"),
           QByteArrayLiteral("wonderland"),
           {QByteArrayLiteral(".alice2.txt"), QByteArrayLiteral("alice1.txt")});
}

void FilenameSearchTest::hiddenFiles()
{
    QFETCH(QByteArray, searchOptions);
    QFETCH(QByteArray, searchString);
    QFETCH(QByteArrayList, expectedFiles);

    const QString path = QFINDTESTDATA("data/hiddenFilesAndFolders");
    QByteArrayList results = doSearchQuery(buildSearchQuery(searchString, searchOptions, path), {KIO::ListJob::ListFlag::IncludeHidden});

    QCOMPARE(results, expectedFiles);
}

void FilenameSearchTest::hiddenFolders_data()
{
    addColumns();

    addRow("Filename Match",
           QByteArray("includeHidden=folders"),
           QByteArrayLiteral("alice"),
           {QByteArrayLiteral("alice1.txt"), QByteArrayLiteral("alice3.txt")});

    addRow("Content Match",
           QByteArray("includeHidden=folders&checkContent=yes"),
           QByteArrayLiteral("wonderland"),
           {QByteArrayLiteral("alice1.txt"), QByteArrayLiteral("alice3.txt")});
}

void FilenameSearchTest::hiddenFolders()
{
    QFETCH(QByteArray, searchOptions);
    QFETCH(QByteArray, searchString);
    QFETCH(QByteArrayList, expectedFiles);

    const QString path = QFINDTESTDATA("data/hiddenFilesAndFolders");
    QByteArrayList results = doSearchQuery(buildSearchQuery(searchString, searchOptions, path), {KIO::ListJob::ListFlag::IncludeHidden});

    QCOMPARE(results, expectedFiles);
}

void FilenameSearchTest::hiddenFilesAndFolders_data()
{
    addColumns();

    addRow("Filename Match",
           QByteArray("includeHidden=yes"),
           QByteArrayLiteral("alice"),
           {QByteArrayLiteral(".alice2.txt"), QByteArrayLiteral(".alice4.txt"), QByteArrayLiteral("alice1.txt"), QByteArrayLiteral("alice3.txt")});

    addRow("Content Match",
           QByteArray("includeHidden=yes&checkContent=yes"),
           QByteArrayLiteral("wonderland"),
           {QByteArrayLiteral(".alice2.txt"), QByteArrayLiteral(".alice4.txt"), QByteArrayLiteral("alice1.txt"), QByteArrayLiteral("alice3.txt")});
}

void FilenameSearchTest::hiddenFilesAndFolders()
{
    QFETCH(QByteArray, searchOptions);
    QFETCH(QByteArray, searchString);
    QFETCH(QByteArrayList, expectedFiles);

    const QString path = QFINDTESTDATA("data/hiddenFilesAndFolders");
    QByteArrayList results = doSearchQuery(buildSearchQuery(searchString, searchOptions, path), KIO::ListJob::ListFlag::IncludeHidden);

    QCOMPARE(results, expectedFiles);
}

QTEST_MAIN(FilenameSearchTest)

#include "filenamesearchtest.moc"
