100 lines
2.6 KiB
C++
100 lines
2.6 KiB
C++
#include <catch2/catch_test_macros.hpp>
|
|
#include <kpn/channel.hpp>
|
|
#include <thread>
|
|
|
|
using namespace kpn;
|
|
|
|
TEST_CASE("channel storage policy: small trivial type by value", "[channel]") {
|
|
STATIC_REQUIRE(channel_storage_policy<int>::by_value);
|
|
STATIC_REQUIRE(channel_storage_policy<float>::by_value);
|
|
}
|
|
|
|
TEST_CASE("channel storage policy: large type by shared_ptr", "[channel]") {
|
|
struct Big { char data[64]; };
|
|
STATIC_REQUIRE(!channel_storage_policy<Big>::by_value);
|
|
}
|
|
|
|
TEST_CASE("push and pop single value", "[channel]") {
|
|
Channel<int> ch(5);
|
|
ch.push(42);
|
|
REQUIRE(ch.pop() == 42);
|
|
}
|
|
|
|
TEST_CASE("channel respects capacity", "[channel]") {
|
|
Channel<int> ch(2);
|
|
ch.push(1);
|
|
ch.push(2);
|
|
REQUIRE_THROWS_AS(ch.push(3), ChannelOverflowError);
|
|
}
|
|
|
|
TEST_CASE("pop blocks until value available", "[channel]") {
|
|
Channel<int> ch(5);
|
|
int result = 0;
|
|
std::thread producer([&] {
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
|
ch.push(99);
|
|
});
|
|
result = ch.pop();
|
|
producer.join();
|
|
REQUIRE(result == 99);
|
|
}
|
|
|
|
TEST_CASE("try_pop returns false on timeout", "[channel]") {
|
|
Channel<int> ch(5);
|
|
int out = 0;
|
|
REQUIRE_FALSE(ch.try_pop(out, std::chrono::milliseconds(10)));
|
|
}
|
|
|
|
TEST_CASE("try_pop succeeds when value present", "[channel]") {
|
|
Channel<int> ch(5);
|
|
ch.push(7);
|
|
int out = 0;
|
|
REQUIRE(ch.try_pop(out, std::chrono::milliseconds(10)));
|
|
REQUIRE(out == 7);
|
|
}
|
|
|
|
TEST_CASE("disable unblocks waiting pop", "[channel]") {
|
|
Channel<int> ch(5);
|
|
std::thread disabler([&] {
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
|
ch.disable();
|
|
});
|
|
REQUIRE_THROWS_AS(ch.pop(), ChannelClosedError);
|
|
disabler.join();
|
|
}
|
|
|
|
TEST_CASE("push to disabled channel is silently dropped", "[channel]") {
|
|
Channel<int> ch(5);
|
|
ch.disable();
|
|
ch.push(99); // must not throw, must not enqueue
|
|
REQUIRE(ch.size() == 0);
|
|
}
|
|
|
|
TEST_CASE("disable clears existing queue contents", "[channel]") {
|
|
Channel<int> ch(5);
|
|
ch.push(1);
|
|
ch.push(2);
|
|
REQUIRE(ch.size() == 2);
|
|
ch.disable();
|
|
REQUIRE(ch.size() == 0);
|
|
}
|
|
|
|
TEST_CASE("enable re-accepts pushes after disable", "[channel]") {
|
|
Channel<int> ch(5);
|
|
ch.disable();
|
|
ch.push(1);
|
|
REQUIRE(ch.size() == 0);
|
|
ch.enable();
|
|
ch.push(42);
|
|
REQUIRE(ch.pop() == 42);
|
|
}
|
|
|
|
TEST_CASE("large type stored as shared_ptr — no copy on pop", "[channel]") {
|
|
struct Big { char data[64]; int tag; };
|
|
Channel<Big> ch(5);
|
|
Big b{}; b.tag = 123;
|
|
ch.push(b);
|
|
auto out = ch.pop();
|
|
REQUIRE(out.tag == 123);
|
|
}
|