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

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

%disable-warning module-only

%requires ../../../../qlib/FixedLengthUtil

%requires reflection

%include ../../../../qlib/QUnit.qm

%exec-class DIJClass

public class A {
    constructor() {
        throw "TEST-EXCEPTION", "This should never happen!";
    }

    public bool test() {
        return False;
    }
}

public class Aalt {
    constructor() {
    }

    public bool test() {
        return True;
    }
}

public class B inherits A {
    public bool test() {
        return A::test();
    }
}

public class InputStreamLineIteratorFake inherits Qore::AbstractLineIterator {
    constructor(InputStream is, *string encoding, *string eol, bool trimEol = True) {
        throw "TEST-EXCEPTION", "this signifies that it actually works";
    }
    bool next() {
        return False;
    }
    string getValue() {
        return "";
    }
    string getLine() {
        return "";
    }
    int index() {
        return 0;
    }
    bool valid() {
        return False;
    }
}

public class MyClass inherits Class {
    constructor(string path) : Class(path) {
    }

    static Class forName(string path) {
        return Class::forName("Mutex");
    }
}

public class DIJClass inherits QUnit::DependencyInjectedTest {
    constructor() : DependencyInjectedTest("Inject", "1.0") {
        addTestCase("builtin module", \testBuiltinModuleInjection());
        addTestCase("Directly instantiate injected classes", \testDirectlyInjectedClass());
        addTestCase("Instantiate classes with an injected ancestor", \testInheritedInjectedClass());
        addTestCase("Instantiate class from a module with injected ancestor", \testModuleInjectedClass());

        set_return_value(main());
    }

    private string getScriptPathImpl() {
        return get_script_path();
    }

    private performInjectionsImpl() {
        # do builtin module injections here
        injectClass("MyClass", "Class");

        injectUserModule("../../../../qlib/FixedLengthUtil");
    }

    private performCommonInjections(Program p) {
        p.importClass("Aalt", "A", True);
        p.importClass("InputStreamLineIteratorFake", "Qore::InputStreamLineIterator", True);
    }

    testBuiltinModuleInjection() {
        Class c = Class::forName("invalid");
        assertEq("Mutex", c.getName());
    }

    testDirectlyInjectedClass() {
        A a();
        testAssertion("run test", \a.test(), list());
    }

    testInheritedInjectedClass() {
        B b();
        testAssertion("run test", \b.test(), list());
    }

    bool createIterator() {
        FixedLengthUtil::FixedLengthDataIterator it("", ("wrong": False), ("unknown": "????"));
        return True;
    }

    testModuleInjectedClass() {
        # Since FixedLengthAbstract validated options in the constructor, this will succeed as soon as our constructor of FixedLengthAbstractIteratorFake is called
        testAssertion("instantiate iterator", \createIterator(), list(), new QUnit::TestResultExceptionRegexp("TEST-EXCEPTION", "this signifies that it actually works"));
    }
}
