#include <balancer/kernel/helpers/syscalls.h>

#include <library/cpp/testing/unittest/registar.h>


#if defined(__MACH__)
// malloc.h is deprecated
#include <stdlib.h>
#else
#include <malloc.h>
#endif


#ifdef _unix_
#   include <sys/mman.h>
#   include <sys/wait.h>
#endif


using namespace NSrvKernel;

Y_UNIT_TEST_SUITE(TestSyscalls) {
    Y_UNIT_TEST(TestSyscallErr) {
        auto err = Y_SYSCALL(close(-1));
        UNIT_ASSERT(err);
        UNIT_ASSERT(err.GetAs<TSystemError>());
        UNIT_ASSERT_VALUES_EQUAL(err.GetAs<TSystemError>()->Status(), EBADF);
        UNIT_ASSERT_STRING_CONTAINS(GetErrorMessage(err), "close(-1)");
        UNIT_ASSERT_STRING_CONTAINS(GetErrorMessage(err), __SOURCE_FILE__);
    }

    Y_UNIT_TEST(TestRSyscallOk) {
        void* m = nullptr;
        // not a syscall but who cares
        auto err = Y_R_SYSCALL(malloc(1024)).AssignTo(m);
        UNIT_ASSERT(!err);
        free(m);
    }

#ifdef _unix_
    Y_UNIT_TEST(TestRSyscallErr) {
        void* m = nullptr;
        auto err = Y_R_SYSCALL(mmap(nullptr, 0, 0, 0, -1, 0)).AssignTo(m);
        UNIT_ASSERT(!m);
        UNIT_ASSERT(err);
        UNIT_ASSERT(err.GetAs<TSystemError>());
        UNIT_ASSERT(IsIn({EBADF, EINVAL}, err.GetAs<TSystemError>()->Status()));
        UNIT_ASSERT_STRING_CONTAINS(GetErrorMessage(err), "mmap(nullptr, 0, 0, 0, -1, 0)");
        UNIT_ASSERT_STRING_CONTAINS(GetErrorMessage(err), __SOURCE_FILE__);
    }

    Y_UNIT_TEST(TestRSyscall0) {
        pid_t p = 0;
        auto err = Y_R_SYSCALL(fork()).AssignTo(p);
        if (!p) {
            // there is no point in wrapping nonfailing syscalls
            _exit(0);
        } else {
            int res = 0;
            err = Y_SYSCALL(waitpid(p, &res, 0));
        }
        UNIT_ASSERT(!err);
    }
#endif

}
