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

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

%requires ../../../../../qlib/Util.qm
%requires ../../../../../qlib/FsUtil.qm
%requires ../../../../../qlib/QUnit.qm

%exec-class FileTest

class FileTest inherits QUnit::Test {
    public {
        const Data = "äsdfaä";

        const Script = "printf(\"%s\", stdin.readBinary(10).toHex());";
    }

    constructor() : QUnit::Test("File", "1.0") {
        addTestCase("non-blocking I/O", \testNonBlockingIo());
        addTestCase("FileTest", \fileTest());
        addTestCase("issue 3061", \issue3061());
        addTestCase("redirect test", \redirectTest());
        set_return_value(main());
    }

    testNonBlockingIo() {
        data content = get_random_string(512);
        testNonBlockingIoIntern(content);

        content = get_random_bytes(512);
        testNonBlockingIoIntern(content);

        content = get_random_bytes(10 * 1024 * 1024);
        testNonBlockingIoIntern(content);
    }

    testNonBlockingIoIntern(data content) {
        TmpFile tmp("qore-File-");
        tmp.file.write(content);
        tmp.file.close();

        File f();
        FilePollOperation fpop = f.startPollRead(tmp.path, content.typeCode() == NT_STRING);
        string label = sprintf("%d byte %s file: ", content.size(), content.type());
        assertEq("read-done", fpop.getGoal(), label + "goal: read-done");
        assertEq("reading", fpop.getState(), label + "reading");

        list<hash<SocketPollInfo>> new_list;
        while (*hash<SocketPollInfo> info = fpop.continuePoll()) {
            #printf("info: %y\n", info);
            new_list = Socket::poll((info,), 1s);
        }
        assertEq("read-done", fpop.getState(), label + "state: read-done");
        assertTrue(fpop.goalReached(), label + "goal reached");

        assertEq(content, fpop.getOutput(), label + "content matches");
    }

    fileTest() {
        string file = sprintf(tmp_location() + DirSep + get_random_string());
        {
            File f();
            f.open2(file, O_CREAT|O_WRONLY|O_TRUNC, 0666, "utf-8");
            f.write(Data);
        }
        on_exit unlink(file);

        ReadOnlyFile f(file);
        # issue 1547
        assertEq("ä", f.getchar());
        assertEq("s", f.getchar());
        f.setPos(0);
        # issue 1548
        assertEq("ä", f.read(1));
        assertEq("s", f.read(1));
        assertEq("dfaä", f.read(4));
        f.setPos(0);
        assertEq(Data, f.read(-1));
    }

    issue3061() {
        # create a temporary Qore script
        string fn = sprintf("%s/%s", tmp_location(), get_random_string());
        {
            File f();
            f.open2(fn, O_CREAT|O_WRONLY|O_TRUNC);
            f.write(Script);
        }
        on_exit unlink(fn);

        # this test works on all platforms but was made for Windows
        string hex = backquote('qore -ne "printf(\"a\r\n\");" | qore ' + fn);
        assertEq("610d0a", hex);
    }

    redirectTest() {
        string file = sprintf(tmp_location() + DirSep + get_random_string());
        File f();
        f.open2(file, O_CREAT|O_WRONLY|O_TRUNC);
        on_exit unlink(file);

        f.write("test1");
        assertEq("test1", ReadOnlyFile::readTextFile(file));
        assertEq("test", File::readTextFile(file, NOTHING, 4));
        assertEq("test".toBinary(), File::readBinaryFile(file, 4));

        stderr.redirect(f);
        stderr.setPos(0);
        stderr.write("test2");

        assertEq("test2", ReadOnlyFile::readTextFile(file));
    }
}
