module thread_test; import std::thread::channel; import std::thread; import std::time; import std::io; fn void init_destroy_buffered() @test { for (usz i = 0; i < 20; i++) { BufferedChannel{int} c; c.init(mem, 1)!!; defer c.destroy(); } } fn void init_destroy_unbuffered() @test { for (usz i = 0; i < 20; i++) { UnbufferedChannel{int} c; c.init(mem)!!; defer c.destroy(); } } fn void push_to_buffered_channel_no_lock() @test { BufferedChannel{int} c; c.init(mem, 1)!!; defer c.destroy(); c.push(1)!!; } fn void push_pop_buffered_no_locks() @test { BufferedChannel{int} c; c.init(mem, 1)!!; defer c.destroy(); c.push(123)!!; int got = c.pop()!!; assert(got == 123); } fn void push_pop_unbuffered_with_locks() @test { UnbufferedChannel{int} c; c.init(mem)!!; defer c.destroy(); Thread thread; defer thread.join(); thread.create(fn int(void* arg) { UnbufferedChannel{int} c = (UnbufferedChannel{int})arg; c.push(123)!!; c.push(321)!!; return 0; }, (void*)c)!!; int got = c.pop()!!; assert(got == 123); got = c.pop()!!; assert(got == 321); } fn void sending_to_closed_unbuffered_chan_is_forbidden() @test { UnbufferedChannel{int} c; c.init(mem, )!!; defer c.destroy(); c.close(); if (catch err = c.push(123)) { assert(err == thread::CHANNEL_CLOSED); return; } assert(false); } fn void sending_to_closed_buffered_chan_is_forbidden() @test { BufferedChannel{int} c; c.init(mem, 1)!!; defer c.destroy(); c.close(); if (catch err = c.push(123)) { assert(err == thread::CHANNEL_CLOSED); return; } assert(false); } fn void reading_from_empty_closed_unbuffered_chan_is_forbidden() @test { UnbufferedChannel{int} c; c.init(mem, )!!; defer c.destroy(); c.close(); if (catch err = c.pop()) { assert(err == thread::CHANNEL_CLOSED); return; } assert(false); } fn void reading_from_empty_closed_buffered_chan_is_forbidden() @test { BufferedChannel{int} c; c.init(mem, 1)!!; defer c.destroy(); c.close(); if (catch err = c.pop()) { assert(err == thread::CHANNEL_CLOSED); return; } assert(false); } fn void reading_from_non_empty_closed_buffered_chan_is_ok() @test { BufferedChannel{int} c; c.init(mem, 3)!!; defer c.destroy(); c.push(1)!!; c.push(2)!!; c.push(3)!!; c.close(); int got = c.pop()!!; assert(got == 1); got = c.pop()!!; assert(got == 2); got = c.pop()!!; assert(got == 3); int? got_err = c.pop(); if (catch err = got_err) { assert(err == thread::CHANNEL_CLOSED); return; } assert(false); } fn void reading_from_empty_buffered_chan_aborted_by_close() @test { BufferedChannel{int} c; c.init(mem, 3)!!; defer c.destroy(); Thread thread; defer thread.join(); thread.create(fn int(void* arg) { BufferedChannel{int} c = (BufferedChannel{int})arg; c.close(); return 0; }, (void*)c)!!; int? res = c.pop(); if (catch err = res) { assert(err == thread::CHANNEL_CLOSED); return; } assert(false); } fn void reading_from_unbuffered_chan_aborted_by_close() @test { UnbufferedChannel{int} c; c.init(mem, )!!; defer c.destroy(); Thread thread; defer thread.join(); thread.create(fn int(void* arg) { UnbufferedChannel{int} c = (UnbufferedChannel{int})arg; c.close(); return 0; }, (void*)c)!!; int? res = c.pop(); if (catch err = res) { assert(err == thread::CHANNEL_CLOSED); return; } assert(false); } fn void sending_to_full_buffered_chan_aborted_by_close() @test { BufferedChannel{int} c; c.init(mem, 1)!!; defer c.destroy(); c.push(1)!!; Thread thread; defer thread.join(); thread.create(fn int(void* arg) { BufferedChannel{int} c = (BufferedChannel{int})arg; c.close(); return 0; }, (void*)c)!!; fault err = @catch(c.push(1)); if (err) { assert(err == thread::CHANNEL_CLOSED); return; } assert(false); } fn void sending_to_unbuffered_chan_aborted_by_close() @test { UnbufferedChannel{int} c; c.init(mem, )!!; defer c.destroy(); Thread thread; defer thread.join(); thread.create(fn int(void* arg) { UnbufferedChannel{int} c = (UnbufferedChannel{int})arg; c.close(); return 0; }, (void*)c)!!; fault err = @catch(c.push(1)); if (err) { assert(err == thread::CHANNEL_CLOSED); return; } assert(false); } fn void multiple_actions_unbuffered() @test { UnbufferedChannel{int} c; c.init(mem, )!!; defer c.destroy(); Thread thread; defer thread.join(); thread.create(fn int(void* arg) { UnbufferedChannel{int} c = (UnbufferedChannel{int})arg; for (int i = 0; i <= 100; i++) { c.push(i)!!; } return 0; }, (void*)c)!!; int sum; for (int i = 0; i <= 100; i++) { int? res = c.pop(); if (catch err = res) { assert(false); } sum += res; } assert(sum == 5050); } fn void multiple_actions_buffered() @test { BufferedChannel{int} c; c.init(mem, 10)!!; defer c.destroy(); Thread thread; defer thread.join(); thread.create(fn int(void* arg) { BufferedChannel{int} c = (BufferedChannel{int})arg; for (int i = 0; i <= 100; i++) { c.push(i)!!; } return 0; }, (void*)c)!!; int sum; for (int i = 0; i <= 100; i++) { int? res = c.pop(); if (catch err = res) { assert(false); } sum += res; } assert(sum == 5050); }