1.3.72
 
Loading...
Searching...
No Matches
test_helpers.h
Go to the documentation of this file.
1
16#pragma once
17
18#ifdef HELIOS_HAVE_VULKAN
19#include "VulkanDevice.h"
20#endif
21
22#include <memory>
23#include <cstdlib>
24#include <iostream>
25#include <stdexcept>
26
27namespace helios {
28
52 public:
53#ifdef HELIOS_HAVE_VULKAN
63 static VulkanDevice *getSharedDevice() {
64 static std::unique_ptr<VulkanDevice> shared_device;
65 static bool initialized = false;
66 static bool available = false;
67
68 if (!initialized) {
69 initialized = true;
70
71 // Allow forcing GPU tests to be skipped (e.g., for local CI simulation)
72 // Usage: HELIOS_NO_GPU=1 ./run_tests.sh --test radiation
73 const char *no_gpu = std::getenv("HELIOS_NO_GPU");
74 if (no_gpu && std::string(no_gpu) != "0") {
75 std::cout << "[Vulkan Test] HELIOS_NO_GPU is set. Skipping GPU tests." << std::endl;
76 available = false;
77 return nullptr;
78 }
79
80 try {
81 shared_device = std::make_unique<VulkanDevice>();
82 shared_device->initialize(false); // No validation for test performance
83 available = true;
84
85 // Register cleanup at process exit for clean driver state
86 std::atexit([]() {
87 if (shared_device) {
88 shared_device->shutdown();
89 shared_device.reset();
90 }
91 });
92 } catch (const std::exception &e) {
93 std::cout << "[Vulkan Test] No Vulkan device available: " << e.what() << std::endl;
94 std::cout << "[Vulkan Test] GPU-dependent radiation tests will be skipped." << std::endl;
95 shared_device.reset();
96 available = false;
97 }
98 }
99
100 return available ? shared_device.get() : nullptr;
101 }
102#endif // HELIOS_HAVE_VULKAN
103
113 static bool isVulkanAvailable() {
114#ifdef HELIOS_HAVE_VULKAN
115 if (gpu_runtime_failed) {
116 return false;
117 }
118 return getSharedDevice() != nullptr;
119#else
120 return false;
121#endif
122 }
123
130 static void markGPURuntimeFailed() {
131 gpu_runtime_failed = true;
132 }
133
134 // Disable construction - static-only interface
135 TestVulkanDeviceManager() = delete;
137 TestVulkanDeviceManager &operator=(const TestVulkanDeviceManager &) = delete;
138
139 private:
140 static inline bool gpu_runtime_failed = false;
141 };
142
143} // namespace helios
144
145// ============================================================================
146// GPU_TEST_CASE macro: wraps a doctest test case with GPU availability check
147// and runtime DEVICE_LOST detection.
148//
149// Usage (replaces DOCTEST_TEST_CASE + SKIP_IF_NO_GPU):
150// GPU_TEST_CASE("test name") {
151// // test body — no SKIP_IF_NO_GPU() needed
152// }
153//
154// Behavior:
155// 1. If GPU is known unavailable (no driver, HELIOS_NO_GPU, or previous DEVICE_LOST),
156// the test immediately reports SKIPPED and returns.
157// 2. Otherwise, runs the test body inside a try/catch. If the body throws an exception
158// containing "DEVICE_LOST" or "VkResult: -4", marks the GPU as failed at runtime
159// so all subsequent GPU tests skip instead of repeating the same failure.
160// 3. Any other exception is re-thrown for doctest to handle normally.
161// ============================================================================
162
163#define GPU_TEST_CASE_IMPL(name, unique_inner) \
164 static void unique_inner(); \
165 DOCTEST_TEST_CASE(name) { \
166 using helios::RadiationModelTestHelper; \
167 using helios::TestVulkanDeviceManager; \
168 if (!RadiationModelTestHelper::isGPUAvailable()) { \
169 DOCTEST_MESSAGE("SKIPPED: No GPU/Vulkan device available"); \
170 return; \
171 } \
172 try { \
173 unique_inner(); \
174 } catch (const std::exception &_gpu_ex) { \
175 std::string _gpu_msg(_gpu_ex.what()); \
176 if (_gpu_msg.find("DEVICE_LOST") != std::string::npos || \
177 _gpu_msg.find("VkResult: -4") != std::string::npos || \
178 _gpu_msg.find("VkResult: -9") != std::string::npos) { \
179 TestVulkanDeviceManager::markGPURuntimeFailed(); \
180 std::cout << "[Vulkan Test] GPU device lost: " << _gpu_msg << std::endl; \
181 std::cout << "[Vulkan Test] Remaining GPU tests will be skipped." << std::endl; \
182 DOCTEST_MESSAGE("SKIPPED: GPU device lost during execution"); \
183 return; \
184 } \
185 throw; \
186 } \
187 } \
188 static void unique_inner()
189
190#define GPU_TEST_CASE(name) \
191 GPU_TEST_CASE_IMPL(name, DOCTEST_ANONYMOUS(DOCTEST_ANON_GPU_FUNC_))