#!/usr/bin/env qore
# -*- mode: qore; indent-tabs-mode: nil -*-

%new-style
%enable-all-warnings
%require-types
%strict-args

# try importing JSON and YAML modules
%try-module json
%define NoJson
%endtry
%try-module yaml
%define NoYaml
%endtry

%requires ../../../../qlib/Util.qm
%requires ../../../../qlib/Mime.qm
%requires ../../../../qlib/QUnit.qm
%requires ../../../../qlib/Logger.qm
%requires ../../../../qlib/DataProvider
%requires ../../../../qlib/HttpServerUtil.qm
%requires ../../../../qlib/RestSchemaValidator.qm
%requires ../../../../qlib/Swagger.qm
%requires ../../../../qlib/ConnectionProvider
%requires ../../../../qlib/RestClient.qm
%requires ../../../../qlib/SwaggerDataProvider

%exec-class SwaggerDataProviderTest

public class SwaggerDataProviderTest inherits QUnit::Test {
    constructor() : Test("SwaggerDataProviderTest", "1.0") {
        addTestCase("swagger data provider test", \testSwaggerDataProvider());
        set_return_value(main());
    }

    checkModules() {
%ifdef NoJson
        testSkip("no json module");
%endif
%ifdef NoYaml
        testSkip("no yaml module");
%endif
    }

    testSwaggerDataProvider() {
        checkModules();

        bool set = AbstractDataProvider::setDynamicValueCallbacks(
            bool sub (auto uri_path) { return uri_path =~ /\$/; },
            auto sub (auto uri_path) { uri_path =~ s/\$id/1/; return uri_path; });
        assertTrue(set);
        assertFalse(AbstractDataProvider::setDynamicValueCallbacks());

        hash<auto> opts = {
            "schema": get_script_dir() + "/PetStore.swagger.yaml",
        };
        SwaggerDataProvider provider(opts);
        assertEq("Swagger Petstore", provider.getName());

        {
            AbstractDataProvider p0 = provider.getChildProviderPath("pet/findByStatus/GET");
            AbstractDataProviderType req = p0.getRequestType();
            assertEq(NT_HASH, req.getField("query").getType().getBaseTypeCode());
            AbstractDataProviderType resp = p0.getResponseType();
            AbstractDataProviderType type = resp.getField("body").getType().getElementType();
            assertEq("*softint", type.getFieldType("id").getName());
            assertEq("softstring", type.getFieldType("name").getName());
            assertEq(("id", "category", "name", "photoUrls", "tags", "status"), keys type.getFields());

            assertThrows("SCHEMA-VALIDATION-ERROR", "enumerated values.*x", \p0.doRequest(),
                {"query": {"status": ("x",)}});

            # the following call depends on the public "pet shop" example Swagger server
            #assertEq(Type::List, p0.doRequest({"query": {"status": ("pending")}}).body.type());
        }

        {
            AbstractDataProvider p0 = provider.getChildProviderPath("pet/$id/POST");
            assertEq("POST", p0.getInfo().name);
            AbstractDataProviderType req = p0.getRequestType();
            assertEq(NT_HASH, req.getField("formData").getType().getBaseTypeCode());
        }

        opts.schema = File::readTextFile(opts.schema);
        provider = new SwaggerDataProvider(opts);
        {
            AbstractDataProvider p0 = provider.getChildProviderPath("pet/findByStatus/GET");
            AbstractDataProviderType req = p0.getRequestType();
            assertEq(NT_HASH, req.getField("query").getType().getBaseTypeCode());
        }

        {
            SwaggerDataProviderFactory factory();
            hash<DataProviderFactoryInfo> info = factory.getInfo();
            assertTrue(info.api_management);
            assertEq(("rest",), info.api_profiles);
        }
    }
}
