/*
 * Copyright 2018 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "tools/skqp/src/skqp.h"

#include "gm/gm.h"
#include "include/core/SkGraphics.h"
#include "include/core/SkStream.h"
#include "include/core/SkSurface.h"
#include "include/gpu/GrContextOptions.h"
#include "include/gpu/GrDirectContext.h"
#include "src/core/SkFontMgrPriv.h"
#include "src/core/SkOSFile.h"
#include "src/utils/SkOSPath.h"
#include "tests/Test.h"
#include "tests/TestHarness.h"
#include "tools/Resources.h"
#include "tools/fonts/TestFontMgr.h"
#ifdef SK_GL
#include "tools/gpu/gl/GLTestContext.h"
#endif
#ifdef SK_VULKAN
#include "tools/gpu/vk/VkTestContext.h"
#endif

#ifdef SK_BUILD_FOR_ANDROID
#include <sys/system_properties.h>
#endif

#include <algorithm>
#include <regex>

static constexpr char kUnitTestReportPath[] = "unit_tests.txt";

// Kind of like Python's readlines(), but without any allocation.
// Calls `lineFn` on each line.
static void read_lines(const void* data,
                       size_t size,
                       const std::function<void(std::string_view)>& lineFn) {
    const char* start = (const char*)data;
    const char* end = start + size;
    const char* ptr = start;
    while (ptr < end) {
        while (*ptr++ != '\n' && ptr < end) {}
        size_t len = ptr - start;
        lineFn(std::string_view(start, len));
        start = ptr;
    }
}

// Returns a list of every unit test to be run.
static std::vector<SkQP::UnitTest> get_unit_tests(int enforcedAndroidAPILevel) {
    std::vector<SkQP::UnitTest> unitTests;
    for (const skiatest::Test& test : skiatest::TestRegistry::Range()) {
        const auto ctsMode = test.fCTSEnforcement.eval(enforcedAndroidAPILevel);
        if (ctsMode != CtsEnforcement::RunMode::kSkip) {
            SkASSERTF(test.fNeedsGpu, "Non-GPU test was included in SkQP: %s\n", test.fName);
            unitTests.push_back(&test);
        }
    }
    auto lt = [](SkQP::UnitTest u, SkQP::UnitTest v) { return strcmp(u->fName, v->fName) < 0; };
    std::sort(unitTests.begin(), unitTests.end(), lt);
    return unitTests;
}

/**
 * SkSL error tests are used by CTS to verify that Android's RuntimeShader API fails when certain
 * shader programs are compiled.  Unlike unit tests these error tests are defined in resource files
 * not source code.  As such, we are unable to mark each test with a CtsEnforcement value.  This
 * list of exclusion rules excludes tests based on their file name so that we can have some form of
 * control for which Android version an SkSL error test is expected to run.
 */
static const std::pair<std::regex, CtsEnforcement> sExclusionRulesForSkSLTests[] = {
        // disable all ES3 tests until AGSL supports it.
        {std::regex(".*ES3.*"), CtsEnforcement::kNever}};

// Returns a list of every SkSL error test to be run.
static std::vector<SkQP::SkSLErrorTest> get_sksl_error_tests(SkQPAssetManager* assetManager,
                                                             int enforcedAndroidAPILevel) {
    std::vector<SkQP::SkSLErrorTest> skslErrorTests;
    auto iterateFn = [&](const char* directory, const char* extension) {
        std::vector<std::string> paths = assetManager->iterateDir(directory, extension);
        for (const std::string& path : paths) {
            SkString name = SkOSPath::Basename(path.c_str());
            for (auto& exclusionEntry : sExclusionRulesForSkSLTests) {
                if (std::regex_match(name.c_str(), exclusionEntry.first) &&
                    exclusionEntry.second.eval(enforcedAndroidAPILevel) ==
                            CtsEnforcement::RunMode::kSkip) {
                    continue;
                }
            }
            sk_sp<SkData> shaderText = GetResourceAsData(path.c_str());
            if (!shaderText) {
                continue;
            }
            skslErrorTests.push_back({
                name.c_str(),
                std::string(static_cast<const char*>(shaderText->data()), shaderText->size())
            });
        }
    };

    // Android only supports runtime shaders, not fragment shaders, color filters or blenders.
    iterateFn("sksl/errors/", ".rts");
    iterateFn("sksl/runtime_errors/", ".rts");

    auto lt = [](const SkQP::SkSLErrorTest& a, const SkQP::SkSLErrorTest& b) {
        return a.name < b.name;
    };
    std::sort(skslErrorTests.begin(), skslErrorTests.end(), lt);
    return skslErrorTests;
}

////////////////////////////////////////////////////////////////////////////////

TestHarness CurrentTestHarness() {
    return TestHarness::kSkQP;
}

////////////////////////////////////////////////////////////////////////////////

const char* SkQP::GetUnitTestName(SkQP::UnitTest t) { return t->fName; }

SkQP::SkQP() {}

SkQP::~SkQP() {}

void SkQP::init(SkQPAssetManager* assetManager, const char* reportDirectory) {
    SkASSERT_RELEASE(assetManager);
    fReportDirectory = reportDirectory;

    SkGraphics::Init();
    gSkFontMgr_DefaultFactory = &ToolUtils::MakePortableFontMgr;

#ifdef SK_BUILD_FOR_ANDROID
    // ro.vendor.api_level contains the minAPI level based on the order defined in
    // docs.partner.android.com/gms/building/integrating/extending-os-upgrade-support-windows
    //  1. board's current api level (for boards that have been upgraded by the SoC vendor)
    //  2. board's first api level (for devices that initially shipped with an older version)
    //  3. product's first api level
    //  4. product's current api level
    char minAPIVersionStr[PROP_VALUE_MAX];
    int strLength = __system_property_get("ro.vendor.api_level", minAPIVersionStr);
    if (strLength != 0) {
        fEnforcedAndroidAPILevel = atoi(minAPIVersionStr);
    }
#endif

    fUnitTests = get_unit_tests(fEnforcedAndroidAPILevel);
    fSkSLErrorTests = get_sksl_error_tests(assetManager, fEnforcedAndroidAPILevel);

    printBackendInfo((fReportDirectory + "/grdump.txt").c_str());
}

std::vector<std::string> SkQP::executeTest(SkQP::UnitTest test) {
    struct : public skiatest::Reporter {
        std::vector<std::string> fErrors;
        void reportFailed(const skiatest::Failure& failure) override {
            SkString desc = failure.toString();
            fErrors.push_back(std::string(desc.c_str(), desc.size()));
        }
    } r;
    GrContextOptions options;
    if (test->fCTSEnforcement.eval(fEnforcedAndroidAPILevel) ==
        CtsEnforcement::RunMode::kRunStrict) {
        options.fDisableDriverCorrectnessWorkarounds = true;
    }
    if (test->fContextOptionsProc) {
        test->fContextOptionsProc(&options);
    }
    test->fProc(&r, options);
    fTestResults.push_back(TestResult{test->fName, r.fErrors});
    return r.fErrors;
}

////////////////////////////////////////////////////////////////////////////////

template <typename T>
inline void write(SkWStream* wStream, const T& text) {
    wStream->write(text.c_str(), text.size());
}

void SkQP::makeReport() {
    if (!sk_isdir(fReportDirectory.c_str())) {
        SkDebugf("Report destination does not exist: '%s'\n", fReportDirectory.c_str());
        return;
    }
    SkFILEWStream report(SkOSPath::Join(fReportDirectory.c_str(), kUnitTestReportPath).c_str());
    SkASSERT_RELEASE(report.isValid());
    for (const SkQP::TestResult& result : fTestResults) {
        report.writeText(result.name.c_str());
        if (result.errors.empty()) {
            report.writeText(" PASSED\n* * *\n");
        } else {
            write(&report, SkStringPrintf(" FAILED (%zu errors)\n", result.errors.size()));
            for (const std::string& err : result.errors) {
                write(&report, err);
                report.newline();
            }
            report.writeText("* * *\n");
        }
    }
}
