Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
--------------------------------------------------------------------------------
-- 0050-coro.lua: tests for coroutine module extensions
-- This file is a part of lua-nucleo library
-- Copyright (c) lua-nucleo authors (see file `COPYRIGHT` for the license)
--------------------------------------------------------------------------------
local make_suite = assert(loadfile('test/test-lib/init/strict.lua'))(...)
local select, assert, type, tostring = select, assert, type, tostring
local table_concat = table.concat
local coroutine_create, coroutine_yield, coroutine_status, coroutine_resume =
coroutine.create, coroutine.yield, coroutine.status, coroutine.resume
local ensure,
ensure_equals,
ensure_tequals
= import 'lua-nucleo/ensure.lua'
{
'ensure',
'ensure_equals',
'ensure_tequals'
}
local make_concatter = import 'lua-nucleo/string.lua' { 'make_concatter' }
local eat_true = import 'lua-nucleo/args.lua' { 'eat_true' }
local coro = import 'lua-nucleo/coro.lua' ()
--------------------------------------------------------------------------------
local eat_tag = function(v, ...)
if not coro.is_outer_yield_tag(v) then
error("can't eat outer yield tag, it is: "..tostring(v), 2)
end
return ...
end
local eat_true_tag = function(...)
return eat_tag(eat_true(...))
end
--------------------------------------------------------------------------------
local test = make_suite("coro", coro)
--------------------------------------------------------------------------------
-- NOTE: Tests below check all these functions in conjunction,
-- so we're simply declaring them here as tested.
-- When adding function to this list, make sure it has tests first.
test:tests_for 'resume_inner'
--------------------------------------------------------------------------------
test "yield_inner" (function()
local co = coroutine_create(function(A)
ensure_equals("A", A, "A")
ensure_equals("C", coroutine_yield("B"), "C")
return "D"
end)
ensure_equals("B", eat_true(coro.resume_inner(co, "A")), "B")
ensure_equals("D", eat_true(coro.resume_inner(co, "C")), "D")
ensure_equals("coroutine dead", coroutine_status(co), "dead")
end)
--------------------------------------------------------------------------------
test:test_for "yield_outer" (function()
local co = coroutine_create(function(A)
ensure_equals("A", A, "A")
ensure_equals("C", coro.yield_outer("B"), "C")
return "D"
end)
ensure_equals("B", eat_true_tag(coroutine_resume(co, "A")), "B")
ensure_equals("D", eat_true(coro.resume_inner(co, "C")), "D")
ensure_equals("coroutine dead", coroutine_status(co), "dead")
end)
--------------------------------------------------------------------------------
test "inner-inner-yield_inner" (function()
local inner1 = coroutine_create(function(A)
assert(A == "A")
local inner2 = coroutine_create(function(B)
assert(B == "B")
assert(coroutine_yield("C") == "D")
return "E"
end)
assert(eat_true(coro.resume_inner(inner2, "B")) == "C")
assert(eat_true(coro.resume_inner(inner2, "D")) == "E")
assert(coroutine_status(inner2) == "dead")
return "F"
end)
assert(eat_true(coro.resume_inner(inner1, "A")) == "F")
assert(coroutine_status(inner1) == "dead")
end)
--------------------------------------------------------------------------------
test "outer-inner-inner-yield_outer" (function()
local outer = coroutine_create(function(A)
ensure_equals("A", A, "A")
local inner1 = coroutine_create(function(B)
ensure_equals("B", B, "B")
local inner2 = coroutine_create(function(C)
ensure_equals("C", C, "C")
ensure_equals("E", coro.yield_outer("D"), "E")
return "F"
end)
ensure_equals("F", eat_true(coro.resume_inner(inner2, "C")), "F")
ensure_equals("inner2 dead", coroutine_status(inner2), "dead")
return "G"
end)
ensure_equals("G", eat_true(coro.resume_inner(inner1, "B")), "G")
ensure_equals("inner1 dead", coroutine_status(inner1), "dead")
return "H"
end)
ensure_equals("D", eat_true_tag(coroutine_resume(outer, "A")),"D")
ensure_equals("H", eat_true(coroutine_resume(outer, "E")), "H")
ensure_equals("outer dead", coroutine_status(outer), "dead")
end)
--------------------------------------------------------------------------------
test "outer-inner-inner-yield_outer-twice" (function()
local outer = coroutine_create(function(A)
ensure_equals("A", A, "A")
local inner1 = coroutine_create(function(B)
ensure_equals("B", B, "B")
local inner2 = coroutine_create(function(C)
ensure_equals("C", C, "C")
ensure_equals("E", coro.yield_outer("D"), "E")
ensure_equals("G", coro.yield_outer("F"), "G")
return "H"
end)
ensure_equals("H", eat_true(coro.resume_inner(inner2, "C")), "H")
ensure_equals("inner2 dead", coroutine_status(inner2), "dead")
return "I"
end)
ensure_equals("F", eat_true(coro.resume_inner(inner1, "B")), "I")
ensure_equals("inner1 dead", coroutine_status(inner1), "dead")
return "J"
end)
ensure_equals("D", eat_true_tag(coroutine_resume(outer, "A")), "D")
ensure_equals("J", eat_true_tag(coroutine_resume(outer, "E")), "F")
ensure_equals("J", eat_true(coroutine_resume(outer, "G")), "J")
ensure_equals("outer dead", coroutine_status(outer), "dead")
end)
--------------------------------------------------------------------------------
--[[
Mesage passing scheme for basic test:
main outer inner1 inner2
| . . .
A--------c->* . .
| | . .
*<=g========B . .
| | . .
C========g=>* . .
| | . .
*<-l--------D . .
| | . .
E--------l->* . .
| | . .
| F--------c->* .
| | | .
*<=g========o===========G .
| | | .
H===========o========g=>* .
| | | .
| <-l---------I .
| | | .
| J--------l->* .
| | | .
| | K----------c->*
| | | |
*<=g========o===========o=============L
| | | |
M===========o===========o==========g=>*
| | | |
| | *<-l----------N
| | | |
| | O----------l->*
| | | |
| | *<-r----------P
| | | .
| *<-r--------Q .
| | . .
*<-r--------R . .
| . . .
--]]
test "basic" (function()
local cat, concat = make_concatter()
do
local outer = coroutine_create(function(A)
cat(A) --> A
cat(coro.yield_outer("B")) --> C
-- Outer coroutines may do inner yields
-- (in case they're held by inner corouines).
cat(coroutine_yield("D")) --> E
local inner1 = coroutine_create(function(F)
cat(F) --> F
cat(coro.yield_outer("G")) --> H
cat(coroutine_yield("I")) --> J
local inner2 = coroutine_create(function(K)
cat(K)
cat(coro.yield_outer("L")) --> M
cat(coroutine_yield("N")) --> O
return "P"
end)
cat(eat_true(coro.resume_inner(inner2, "K"))) --> N
cat(eat_true(coro.resume_inner(inner2, "O"))) --> P
assert(coroutine_status(inner2) == "dead")
return "Q"
end)
cat(eat_true(coro.resume_inner(inner1, "F"))) --> I
cat(eat_true(coro.resume_inner(inner1, "J"))) --> Q
assert(coroutine_status(inner1) == "dead")
return "R"
end)
cat(eat_true_tag(coroutine_resume(outer, "A"))) --> B
cat(eat_true(coroutine_resume(outer, "C"))) --> D
cat(eat_true_tag(coroutine_resume(outer, "E"))) --> G
cat(eat_true_tag(coroutine_resume(outer, "H"))) --> L
cat(eat_true(coroutine_resume(outer, "M"))) --> R
assert(coroutine_status(outer) == "dead")
end
assert(concat() == "ABCDEFGHIJKLMNOPQR")
end)
--------------------------------------------------------------------------------
-- NOTE: Tests below check all these functions in conjunction,
-- so we're simply declaring them here as tested.
-- When adding function to this list, make sure it has tests first.
test:tests_for 'eat_tag'
'is_outer_yield_tag'
--------------------------------------------------------------------------------
test:test "eat_tag-is_outer_yield_tag-not-tag" (function()
ensure_equals("that is not the tag", coro.is_outer_yield_tag(42), false)
ensure_tequals(
"do not eat non-tag true",
{ coro.eat_tag(true, 42) },
{ true, 42 }
)
ensure_tequals(
"do not eat non-tag false",
{ coro.eat_tag(false, 42) },
{ false, 42 }
)
end)
test:test "eat_tag-is_outer_yield_tag-actual-tag" (function()
local tag
do
local co = coroutine_create(function()
coro.yield_outer()
end)
local _
_, tag = assert(coroutine.resume(co))
end
ensure_equals("that is the tag", coro.is_outer_yield_tag(tag), true)
ensure_tequals(
"eat tag true",
{ coro.eat_tag(true, tag, 42) },
{ true, 42 }
)
ensure_tequals(
"eat tag false",
{ coro.eat_tag(false, tag, 42) },
{ false, 42 }
)
end)