14#include <catch2/catch_test_macros.hpp>
25TEST_CASE(
"DCMTK availability check",
"[dcmtk][utility]") {
29 WARN(
"DCMTK not installed - some tests will be skipped");
30 WARN(
"Install with: brew install dcmtk (macOS) or apt install dcmtk (Linux)");
34 SUCCEED(
"DCMTK availability check completed");
37TEST_CASE(
"DCMTK version detection",
"[dcmtk][utility]") {
39 SKIP(
"DCMTK not installed");
43 REQUIRE(version.has_value());
44 INFO(
"DCMTK version: " << *version);
47 REQUIRE_FALSE(version->empty());
54TEST_CASE(
"dcmtk_result success check",
"[dcmtk][utility]") {
57 SECTION(
"Default result is not success") {
58 REQUIRE_FALSE(result.
success());
61 SECTION(
"Zero exit code is success") {
66 SECTION(
"Non-zero exit code is failure") {
68 REQUIRE_FALSE(result.
success());
72TEST_CASE(
"dcmtk_result error check",
"[dcmtk][utility]") {
75 SECTION(
"Empty stderr has no error") {
79 SECTION(
"Non-empty stderr has error") {
89TEST_CASE(
"DCMTK storescp lifecycle",
"[dcmtk][utility][server]") {
91 SKIP(
"DCMTK not installed");
97 SECTION(
"Server starts and stops correctly") {
103 SKIP(
"Failed to start storescp - may not be installed correctly");
106 REQUIRE(server.is_running());
113 std::this_thread::sleep_for(std::chrono::milliseconds{200});
120TEST_CASE(
"DCMTK echoscp lifecycle",
"[dcmtk][utility][server]") {
122 SKIP(
"DCMTK not installed");
127 SECTION(
"Server starts and stops correctly") {
132 SKIP(
"Failed to start echoscp - may not be installed correctly");
135 REQUIRE(server.is_running());
139 std::this_thread::sleep_for(std::chrono::milliseconds{200});
148TEST_CASE(
"dcmtk_server_guard wait_for_ready",
"[dcmtk][utility][server]") {
150 SKIP(
"DCMTK not installed");
160 if (!server.is_running()) {
161 SKIP(
"Failed to start echoscp");
164 SECTION(
"wait_for_ready returns true when server is listening") {
165 REQUIRE(server.wait_for_ready(std::chrono::seconds{10}));
168 SECTION(
"Port matches") {
169 REQUIRE(server.port() == port);
173TEST_CASE(
"dcmtk_server_guard move semantics",
"[dcmtk][utility][server]") {
175 SKIP(
"DCMTK not installed");
180 SECTION(
"Move construction transfers ownership") {
186 if (!server1.is_running()) {
187 SKIP(
"Failed to start echoscp");
190 auto pid = server1.
pid();
193 REQUIRE(server2.
pid() == pid);
202TEST_CASE(
"background_process_guard with DCMTK",
"[dcmtk][utility]") {
204 SKIP(
"DCMTK not installed");
209 SECTION(
"Guard manages process lifecycle") {
215 SKIP(
"Failed to start echoscp");
218 guard = std::move(temp_guard);
225 std::this_thread::sleep_for(std::chrono::milliseconds{200});
234TEST_CASE(
"find_available_port returns valid port",
"[dcmtk][utility]") {
240 REQUIRE(port1 != port2);
243TEST_CASE(
"is_port_listening detection",
"[dcmtk][utility]") {
246 SECTION(
"Unused port is not listening") {
RAII wrapper for a background process.
void stop()
Stop the process.
bool is_running() const
Check if process is running.
RAII guard for DCMTK server processes.
process_launcher::pid_type pid() const noexcept
static constexpr pid_type invalid_pid
Invalid PID constant (0 is reserved on both platforms)
static bool is_port_listening(uint16_t port, const std::string &host="127.0.0.1")
Check if a port is currently listening.
RAII wrapper for temporary test directory.
const std::filesystem::path & path() const noexcept
uint16_t find_available_port(uint16_t start=default_test_port, int max_attempts=200)
Find an available port for testing.
TEST_CASE("test_data_generator::ct generates valid CT dataset", "[data_generator][ct]")
Result of a DCMTK tool execution.
bool success() const noexcept
int exit_code
Process exit code.
std::string stderr_output
Standard error.
bool has_error() const noexcept