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() c; c.init(mem, 1)!!; defer c.destroy()!!; } } fn void init_destroy_unbuffered() @test { for (usz i = 0; i < 20; i++) { UnbufferedChannel() c; c.new_init()!!; defer c.destroy()!!; } } fn void push_to_buffered_channel_no_lock() @test { BufferedChannel() c; c.init(mem, 1)!!; defer c.destroy()!!; c.push(1)!!; } fn void push_pop_buffered_no_locks() @test { BufferedChannel() c; c.new_init(1)!!; defer c.destroy()!!; c.push(123)!!; int got = c.pop()!!; assert(got == 123); } fn void push_pop_unbuffered_with_locks() @test { UnbufferedChannel() c; c.new_init()!!; defer c.destroy()!!; Thread thread; defer thread.join()!!; thread.create(fn int(void* arg) { UnbufferedChannel() c = (UnbufferedChannel())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() c; c.new_init()!!; defer c.destroy()!!; c.close()!!; if (catch err = c.push(123)) { assert(err == ThreadFault.CHANNEL_CLOSED); return; } assert(false); } fn void sending_to_closed_buffered_chan_is_forbidden() @test { BufferedChannel() c; c.new_init(1)!!; defer c.destroy()!!; c.close()!!; if (catch err = c.push(123)) { assert(err == ThreadFault.CHANNEL_CLOSED); return; } assert(false); } fn void reading_from_empty_closed_unbuffered_chan_is_forbidden() @test { UnbufferedChannel() c; c.new_init()!!; defer c.destroy()!!; c.close()!!; if (catch err = c.pop()) { assert(err == ThreadFault.CHANNEL_CLOSED); return; } assert(false); } fn void reading_from_empty_closed_buffered_chan_is_forbidden() @test { BufferedChannel() c; c.new_init(1)!!; defer c.destroy()!!; c.close()!!; if (catch err = c.pop()) { assert(err == ThreadFault.CHANNEL_CLOSED); return; } assert(false); } fn void reading_from_non_empty_closed_buffered_chan_is_ok() @test { BufferedChannel() c; c.new_init(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 == ThreadFault.CHANNEL_CLOSED); return; } assert(false); } fn void reading_from_empty_buffered_chan_aborted_by_close() @test { BufferedChannel() c; c.new_init(3)!!; defer c.destroy()!!; Thread thread; defer thread.join()!!; thread.create(fn int(void* arg) { BufferedChannel() c = (BufferedChannel())arg; c.close()!!; return 0; }, (void*)c)!!; int! res = c.pop(); if (catch err = res) { assert(err == ThreadFault.CHANNEL_CLOSED); return; } assert(false); } fn void reading_from_unbuffered_chan_aborted_by_close() @test { UnbufferedChannel() c; c.new_init()!!; defer c.destroy()!!; Thread thread; defer thread.join()!!; thread.create(fn int(void* arg) { UnbufferedChannel() c = (UnbufferedChannel())arg; c.close()!!; return 0; }, (void*)c)!!; int! res = c.pop(); if (catch err = res) { assert(err == ThreadFault.CHANNEL_CLOSED); return; } assert(false); } fn void sending_to_full_buffered_chan_aborted_by_close() @test { BufferedChannel() c; c.new_init(1)!!; defer c.destroy()!!; c.push(1)!!; Thread thread; defer thread.join()!!; thread.create(fn int(void* arg) { BufferedChannel() c = (BufferedChannel())arg; c.close()!!; return 0; }, (void*)c)!!; anyfault err = @catch(c.push(1)); if (err) { assert(err == ThreadFault.CHANNEL_CLOSED); return; } assert(false); } fn void sending_to_unbuffered_chan_aborted_by_close() @test { UnbufferedChannel() c; c.new_init()!!; defer c.destroy()!!; Thread thread; defer thread.join()!!; thread.create(fn int(void* arg) { UnbufferedChannel() c = (UnbufferedChannel())arg; c.close()!!; return 0; }, (void*)c)!!; anyfault err = @catch(c.push(1)); if (err) { assert(err == ThreadFault.CHANNEL_CLOSED); return; } assert(false); } fn void multiple_actions_unbuffered() @test { UnbufferedChannel() c; c.new_init()!!; defer c.destroy()!!; Thread thread; defer thread.join()!!; thread.create(fn int(void* arg) { UnbufferedChannel() c = (UnbufferedChannel())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() c; c.new_init(10)!!; defer c.destroy()!!; Thread thread; defer thread.join()!!; thread.create(fn int(void* arg) { BufferedChannel() c = (BufferedChannel())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); }