local lanes = require "lanes".configure{strip_functions = true}

local fixture = require "fixture"
lanes.finally(fixture.throwing_finalizer)

local utils = lanes.require "_utils"
local PRINT = utils.MAKE_PRINT()

-- a lane coroutine that yields back what got in, one element at a time
local yielder = function(...)
    local utils = lanes.require "_utils"
    local PRINT = utils.MAKE_PRINT()
    PRINT "In lane"
    for _i  = 1, select('#', ...) do
        local _val = select(_i, ...)
        PRINT("yielding #", _i, _val)
        local _ack = coroutine.yield(_val)
        assert(_ack == _i, "unexpected reply ".._ack)
    end
    return "done!"
end

local force_error_test = function(error_trace_level_)
    -- the generator, minimal error handling
    local coro_g = lanes.coro("*", {name = "auto", error_trace_level = error_trace_level_}, yielder)

    -- launch coroutine lane
    local h = coro_g("hello", "world", "!")
    -- read the yielded values, sending back the expected index
    assert(h:resume(1) == "hello")
    assert(h:resume(2) == "world")
    -- mistake: we resume with 0 when the lane expects 3 -> assert() in the lane body!
    assert(h:resume(0) == "!")
    local a, b, c = h:join()
    PRINT(error_trace_level_ .. ":", a, b, c)
    local expected_c_type = error_trace_level_ == "minimal" and "nil" or "table"
    assert(h.status == "error" and string.find(b, "unexpected reply 0", 1, true) and type(c) == expected_c_type, "error message is " .. b)
    utils.dump_error_stack(error_trace_level_, c)
end

if true then
    force_error_test("minimal")
end

if true then
    force_error_test("basic")
end

if true then
    force_error_test("extended")
end

if true then
    -- start a coroutine lane that ends with a non-string error
    local non_string_thrower = function()
        error({"string in table"})
    end
    local coro_g = lanes.coro("*", {name = "auto"}, non_string_thrower)
    local h = coro_g()
    local a, b, c = h:join()
    -- we get the expected error back
    PRINT("non_string_thrower:", a, b, c)
    assert(a == nil and type(b) == "table" and b[1] == "string in table" and c == nil, "a=" .. tostring(a) .. " b=" .. tostring(b))
end
