From a919e29aa8d3aaf506a52baa906997282953f0f8 Mon Sep 17 00:00:00 2001 From: "kingstom.chen" Date: Wed, 25 Mar 2026 12:46:40 +0800 Subject: [PATCH] refactor(util): consume goggles_core for error and profiling types - Delete duplicated error.hpp and profiling.hpp from src/util/ - Link goggles_core through goggles_util and visual test targets - Remove fragile GOGGLES_ERROR_TYPES_DEFINED ODR guards - Rewrite all include paths in src/ and tests/ to - Update boundary contract test to reflect relocated canonical headers --- filter-chain | 2 +- src/app/application.cpp | 2 +- src/app/application.hpp | 2 +- src/app/cli.cpp | 2 +- src/app/cli.hpp | 3 +- src/app/main.cpp | 4 +- src/compositor/compositor_core.cpp | 2 +- src/compositor/compositor_cursor.cpp | 2 +- src/compositor/compositor_focus.cpp | 2 +- src/compositor/compositor_input.cpp | 2 +- src/compositor/compositor_layer_shell.cpp | 2 +- src/compositor/compositor_present.cpp | 2 +- src/compositor/compositor_server.cpp | 2 +- src/compositor/compositor_server.hpp | 2 +- src/compositor/compositor_xdg.cpp | 2 +- src/compositor/compositor_xwayland.cpp | 2 +- .../backend/external_frame_importer.hpp | 2 +- .../backend/filter_chain_controller.cpp | 2 +- src/render/backend/render_output.hpp | 2 +- src/render/backend/vulkan_backend.cpp | 2 +- src/render/backend/vulkan_debug.cpp | 2 +- src/render/backend/vulkan_debug.hpp | 2 +- src/render/backend/vulkan_error.hpp | 2 +- src/ui/imgui_layer.cpp | 2 +- src/ui/imgui_layer.hpp | 2 +- src/util/CMakeLists.txt | 3 +- src/util/config.cpp | 3 +- src/util/config.hpp | 2 +- src/util/error.hpp | 162 ------------------ src/util/job_system.cpp | 3 +- src/util/logging.cpp | 3 +- src/util/logging.hpp | 3 +- src/util/paths.cpp | 2 +- src/util/paths.hpp | 3 +- src/util/profiling.hpp | 40 ----- src/util/serializer.hpp | 3 +- .../render/test_filter_boundary_contracts.cpp | 9 +- tests/util/test_error.cpp | 3 +- tests/visual/CMakeLists.txt | 2 +- tests/visual/image_compare.hpp | 2 +- 40 files changed, 41 insertions(+), 255 deletions(-) delete mode 100644 src/util/error.hpp delete mode 100644 src/util/profiling.hpp diff --git a/filter-chain b/filter-chain index 28345aba..0873141f 160000 --- a/filter-chain +++ b/filter-chain @@ -1 +1 @@ -Subproject commit 28345abac2495cb564cc112158a38f9d69c413e0 +Subproject commit 0873141f783efaf5ae8930c52521d14b5786fe76 diff --git a/src/app/application.cpp b/src/app/application.cpp index ac8b6bed..ef15a6bd 100644 --- a/src/app/application.cpp +++ b/src/app/application.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -21,7 +22,6 @@ #include #include #include -#include #include #include diff --git a/src/app/application.hpp b/src/app/application.hpp index 28ac8f80..c4231180 100644 --- a/src/app/application.hpp +++ b/src/app/application.hpp @@ -3,13 +3,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include #include #include diff --git a/src/app/cli.cpp b/src/app/cli.cpp index 58963be7..dc48f3e7 100644 --- a/src/app/cli.cpp +++ b/src/app/cli.cpp @@ -1,7 +1,7 @@ #include "app/cli.hpp" #include -#include +#include namespace goggles::app { namespace { diff --git a/src/app/cli.hpp b/src/app/cli.hpp index 3168d72d..c9dc1b32 100644 --- a/src/app/cli.hpp +++ b/src/app/cli.hpp @@ -1,9 +1,8 @@ #pragma once -#include "util/error.hpp" - #include #include +#include #include #include #include diff --git a/src/app/main.cpp b/src/app/main.cpp index bd292cde..74f6948d 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include #include @@ -21,10 +23,8 @@ #include #include #include -#include #include #include -#include #include #include diff --git a/src/compositor/compositor_core.cpp b/src/compositor/compositor_core.cpp index dd248f9f..49b43b7c 100644 --- a/src/compositor/compositor_core.cpp +++ b/src/compositor/compositor_core.cpp @@ -32,8 +32,8 @@ extern "C" { #endif } +#include #include -#include namespace goggles::compositor { diff --git a/src/compositor/compositor_cursor.cpp b/src/compositor/compositor_cursor.cpp index 692d8779..85b281e9 100644 --- a/src/compositor/compositor_cursor.cpp +++ b/src/compositor/compositor_cursor.cpp @@ -13,9 +13,9 @@ extern "C" { #include } +#include #include #include -#include namespace goggles::compositor { diff --git a/src/compositor/compositor_focus.cpp b/src/compositor/compositor_focus.cpp index f0d80ace..7fd56022 100644 --- a/src/compositor/compositor_focus.cpp +++ b/src/compositor/compositor_focus.cpp @@ -37,8 +37,8 @@ extern "C" { #endif } +#include #include -#include namespace goggles::compositor { diff --git a/src/compositor/compositor_input.cpp b/src/compositor/compositor_input.cpp index c8828068..14034925 100644 --- a/src/compositor/compositor_input.cpp +++ b/src/compositor/compositor_input.cpp @@ -14,8 +14,8 @@ extern "C" { #include } +#include #include -#include namespace goggles::compositor { diff --git a/src/compositor/compositor_layer_shell.cpp b/src/compositor/compositor_layer_shell.cpp index 8abe253b..db744fbb 100644 --- a/src/compositor/compositor_layer_shell.cpp +++ b/src/compositor/compositor_layer_shell.cpp @@ -24,8 +24,8 @@ extern "C" { #endif } +#include #include -#include namespace goggles::compositor { diff --git a/src/compositor/compositor_present.cpp b/src/compositor/compositor_present.cpp index d9123344..281dc3f0 100644 --- a/src/compositor/compositor_present.cpp +++ b/src/compositor/compositor_present.cpp @@ -44,10 +44,10 @@ extern "C" { #endif } +#include #include #include #include -#include namespace goggles::compositor { diff --git a/src/compositor/compositor_server.cpp b/src/compositor/compositor_server.cpp index e456d17b..b4afad13 100644 --- a/src/compositor/compositor_server.cpp +++ b/src/compositor/compositor_server.cpp @@ -1,8 +1,8 @@ #include "compositor_state.hpp" +#include #include #include -#include namespace goggles::compositor { diff --git a/src/compositor/compositor_server.hpp b/src/compositor/compositor_server.hpp index 65a7c94f..82c3ee80 100644 --- a/src/compositor/compositor_server.hpp +++ b/src/compositor/compositor_server.hpp @@ -2,10 +2,10 @@ #include #include +#include #include #include #include -#include #include #include #include diff --git a/src/compositor/compositor_xdg.cpp b/src/compositor/compositor_xdg.cpp index 9480aebe..1d96a78b 100644 --- a/src/compositor/compositor_xdg.cpp +++ b/src/compositor/compositor_xdg.cpp @@ -9,8 +9,8 @@ extern "C" { #include } +#include #include -#include namespace goggles::compositor { diff --git a/src/compositor/compositor_xwayland.cpp b/src/compositor/compositor_xwayland.cpp index d8b73b42..48f98e25 100644 --- a/src/compositor/compositor_xwayland.cpp +++ b/src/compositor/compositor_xwayland.cpp @@ -21,8 +21,8 @@ extern "C" { #endif } +#include #include -#include namespace goggles::compositor { diff --git a/src/render/backend/external_frame_importer.hpp b/src/render/backend/external_frame_importer.hpp index 778eb6cb..88437ec0 100644 --- a/src/render/backend/external_frame_importer.hpp +++ b/src/render/backend/external_frame_importer.hpp @@ -3,7 +3,7 @@ #include "vulkan_context.hpp" #include -#include +#include #include #include diff --git a/src/render/backend/filter_chain_controller.cpp b/src/render/backend/filter_chain_controller.cpp index 80768b79..bedbba79 100644 --- a/src/render/backend/filter_chain_controller.cpp +++ b/src/render/backend/filter_chain_controller.cpp @@ -6,12 +6,12 @@ #include #include #include +#include #include #include #include #include #include -#include #include namespace goggles::render::backend_internal { diff --git a/src/render/backend/render_output.hpp b/src/render/backend/render_output.hpp index 01bb0051..ba3fd0a9 100644 --- a/src/render/backend/render_output.hpp +++ b/src/render/backend/render_output.hpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/render/backend/vulkan_backend.cpp b/src/render/backend/vulkan_backend.cpp index 3ea138fc..23cc9360 100644 --- a/src/render/backend/vulkan_backend.cpp +++ b/src/render/backend/vulkan_backend.cpp @@ -8,8 +8,8 @@ #include #include +#include #include -#include namespace goggles::render { diff --git a/src/render/backend/vulkan_debug.cpp b/src/render/backend/vulkan_debug.cpp index 805f362d..a6393223 100644 --- a/src/render/backend/vulkan_debug.cpp +++ b/src/render/backend/vulkan_debug.cpp @@ -2,8 +2,8 @@ #include #include +#include #include -#include namespace goggles::render { diff --git a/src/render/backend/vulkan_debug.hpp b/src/render/backend/vulkan_debug.hpp index 8d778ffb..733d6349 100644 --- a/src/render/backend/vulkan_debug.hpp +++ b/src/render/backend/vulkan_debug.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include namespace goggles::render { diff --git a/src/render/backend/vulkan_error.hpp b/src/render/backend/vulkan_error.hpp index fa044c74..8f395f71 100644 --- a/src/render/backend/vulkan_error.hpp +++ b/src/render/backend/vulkan_error.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include // NOLINTBEGIN(cppcoreguidelines-macro-usage) diff --git a/src/ui/imgui_layer.cpp b/src/ui/imgui_layer.cpp index 9c70f443..9eed55fe 100644 --- a/src/ui/imgui_layer.cpp +++ b/src/ui/imgui_layer.cpp @@ -6,12 +6,12 @@ #include #include #include +#include #include #include #include #include #include -#include #include namespace goggles::ui { diff --git a/src/ui/imgui_layer.hpp b/src/ui/imgui_layer.hpp index c15f8633..e6894da7 100644 --- a/src/ui/imgui_layer.hpp +++ b/src/ui/imgui_layer.hpp @@ -3,11 +3,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 6c5da03a..b4d1e5e5 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -10,6 +10,7 @@ target_include_directories(goggles_util_logging_obj PRIVATE ) target_link_libraries(goggles_util_logging_obj PRIVATE + goggles_core spdlog::spdlog ) @@ -30,7 +31,7 @@ target_include_directories(goggles_util PUBLIC # Link dependencies (provided by Pixi) target_link_libraries(goggles_util PUBLIC - nonstd::expected-lite + goggles_core spdlog::spdlog toml11::toml11 BS_thread_pool diff --git a/src/util/config.cpp b/src/util/config.cpp index 224992e7..efb8a644 100644 --- a/src/util/config.cpp +++ b/src/util/config.cpp @@ -1,7 +1,6 @@ #include "config.hpp" -#include "profiling.hpp" - +#include #include namespace goggles { diff --git a/src/util/config.hpp b/src/util/config.hpp index 098459ee..2b911b7f 100644 --- a/src/util/config.hpp +++ b/src/util/config.hpp @@ -1,10 +1,10 @@ #pragma once -#include "error.hpp" #include "scale_mode.hpp" #include #include +#include #include #include diff --git a/src/util/error.hpp b/src/util/error.hpp deleted file mode 100644 index 74b1e385..00000000 --- a/src/util/error.hpp +++ /dev/null @@ -1,162 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef GOGGLES_ERROR_TYPES_DEFINED -#define GOGGLES_ERROR_TYPES_DEFINED - -namespace goggles { - -/// @brief Error codes used by `goggles::Error`. -enum class ErrorCode : std::uint8_t { - ok, - file_not_found, - file_read_failed, - file_write_failed, - parse_error, - invalid_config, - vulkan_init_failed, - vulkan_device_lost, - shader_compile_failed, - shader_load_failed, - input_init_failed, - invalid_data, - unknown_error -}; - -/// @brief Structured error for `Result` operations. -struct Error { - ErrorCode code; - std::string message; - std::source_location location; - - Error(ErrorCode error_code, std::string msg, - std::source_location loc = std::source_location::current()) - : code(error_code), message(std::move(msg)), location(loc) {} -}; - -/// @brief Project-wide fallible operation return type. -template -using Result = nonstd::expected; - -/// @brief Convenience alias for `Result>`. -template -using ResultPtr = Result>; - -template -[[nodiscard]] inline auto make_error(ErrorCode code, std::string message, - std::source_location loc = std::source_location::current()) - -> Result { - return nonstd::make_unexpected(Error{code, std::move(message), loc}); -} - -template -[[nodiscard]] inline auto make_result_ptr(std::unique_ptr ptr) -> ResultPtr { - return ResultPtr{std::move(ptr)}; -} - -template -[[nodiscard]] inline auto -make_result_ptr_error(ErrorCode code, std::string message, - std::source_location loc = std::source_location::current()) -> ResultPtr { - return nonstd::make_unexpected(Error{code, std::move(message), loc}); -} - -/// @brief Returns a stable string name for an `ErrorCode` value. -[[nodiscard]] constexpr auto error_code_name(ErrorCode code) -> const char* { - switch (code) { - case ErrorCode::ok: - return "ok"; - case ErrorCode::file_not_found: - return "file_not_found"; - case ErrorCode::file_read_failed: - return "file_read_failed"; - case ErrorCode::file_write_failed: - return "file_write_failed"; - case ErrorCode::parse_error: - return "parse_error"; - case ErrorCode::invalid_config: - return "invalid_config"; - case ErrorCode::vulkan_init_failed: - return "vulkan_init_failed"; - case ErrorCode::vulkan_device_lost: - return "vulkan_device_lost"; - case ErrorCode::shader_compile_failed: - return "shader_compile_failed"; - case ErrorCode::shader_load_failed: - return "shader_load_failed"; - case ErrorCode::input_init_failed: - return "input_init_failed"; - case ErrorCode::invalid_data: - return "invalid_data"; - case ErrorCode::unknown_error: - return "unknown_error"; - } - return "unknown"; -} - -} // namespace goggles - -#endif // GOGGLES_ERROR_TYPES_DEFINED - -// NOLINTBEGIN(cppcoreguidelines-macro-usage) - -#ifndef GOGGLES_ERROR_MACROS_DEFINED -#define GOGGLES_ERROR_MACROS_DEFINED - -/// @brief Propagates an error or returns the contained value (expression-style). -/// -/// Similar to Rust's `?` operator. The expression must yield a `Result`. -// NOLINTNEXTLINE(bugprone-macro-parentheses) -#define GOGGLES_TRY(expr) \ - ({ \ - auto _try_result = (expr); \ - if (!_try_result) \ - return nonstd::make_unexpected(_try_result.error()); \ - std::move(_try_result).value(); \ - }) - -/// @brief Aborts on error or returns the contained value (expression-style). -/// -/// Use for internal invariants where failure indicates a bug. -// NOLINTNEXTLINE(bugprone-macro-parentheses) -#define GOGGLES_MUST(expr) \ - ({ \ - auto _must_result = (expr); \ - if (!_must_result) { \ - auto& _err = _must_result.error(); \ - std::fprintf(stderr, "GOGGLES_MUST failed at %s:%u in %s\n %s: %s\n", \ - _err.location.file_name(), _err.location.line(), \ - _err.location.function_name(), goggles::error_code_name(_err.code), \ - _err.message.c_str()); \ - std::abort(); \ - } \ - std::move(_must_result).value(); \ - }) - -/// @brief Aborts when an invariant is violated. -// NOLINTNEXTLINE(bugprone-macro-parentheses) -#define GOGGLES_ASSERT(condition, ...) \ - do { \ - if (!(condition)) { \ - std::fprintf(stderr, "GOGGLES_ASSERT failed: %s at %s:%u in %s\n", #condition, \ - __FILE__, __LINE__, __func__); \ - __VA_OPT__(do { \ - std::fprintf(stderr, " "); \ - std::fprintf(stderr, __VA_ARGS__); \ - std::fprintf(stderr, "\n"); \ - } while (false);) \ - std::abort(); \ - } \ - } while (false) - -#endif // GOGGLES_ERROR_MACROS_DEFINED - -// NOLINTEND(cppcoreguidelines-macro-usage) diff --git a/src/util/job_system.cpp b/src/util/job_system.cpp index b7cdbdd6..c96f47a4 100644 --- a/src/util/job_system.cpp +++ b/src/util/job_system.cpp @@ -1,7 +1,6 @@ #include "job_system.hpp" -#include "profiling.hpp" - +#include #include namespace goggles::util { diff --git a/src/util/logging.cpp b/src/util/logging.cpp index c5b44cbe..2fbebe68 100644 --- a/src/util/logging.cpp +++ b/src/util/logging.cpp @@ -1,9 +1,8 @@ #include "logging.hpp" -#include "profiling.hpp" - #include #include +#include #include #include #include diff --git a/src/util/logging.hpp b/src/util/logging.hpp index 9757c083..3af03f0e 100644 --- a/src/util/logging.hpp +++ b/src/util/logging.hpp @@ -4,9 +4,8 @@ #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE #endif -#include "error.hpp" - #include +#include #include #include #include diff --git a/src/util/paths.cpp b/src/util/paths.cpp index 325370fc..c6d3374a 100644 --- a/src/util/paths.cpp +++ b/src/util/paths.cpp @@ -1,9 +1,9 @@ #include "paths.hpp" #include "config.hpp" -#include "profiling.hpp" #include +#include #include #include diff --git a/src/util/paths.hpp b/src/util/paths.hpp index d55a5ec9..b80f8633 100644 --- a/src/util/paths.hpp +++ b/src/util/paths.hpp @@ -1,8 +1,7 @@ #pragma once -#include "error.hpp" - #include +#include namespace goggles { struct Config; diff --git a/src/util/profiling.hpp b/src/util/profiling.hpp deleted file mode 100644 index be6409e6..00000000 --- a/src/util/profiling.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -// ============================================================================= -// Profiling Macros -// ============================================================================= -/// @brief Tracy profiling macros. -/// -/// When `TRACY_ENABLE` is not defined, all macros expand to no-ops (zero overhead). - -// NOLINTBEGIN(cppcoreguidelines-macro-usage) - -#ifdef TRACY_ENABLE - -#include -#include - -#define GOGGLES_PROFILE_FRAME(name) FrameMarkNamed(name) - -#define GOGGLES_PROFILE_FUNCTION() ZoneScoped - -#define GOGGLES_PROFILE_SCOPE(name) ZoneScopedN(name) - -#define GOGGLES_PROFILE_TAG(text) \ - do { \ - ZoneText(text, std::strlen(text)); \ - } while (0) - -#define GOGGLES_PROFILE_VALUE(name, value) TracyPlot(name, value) - -#else // !TRACY_ENABLE - -#define GOGGLES_PROFILE_FRAME(name) (void)0 -#define GOGGLES_PROFILE_FUNCTION() (void)0 -#define GOGGLES_PROFILE_SCOPE(name) (void)0 -#define GOGGLES_PROFILE_TAG(text) (void)0 -#define GOGGLES_PROFILE_VALUE(name, value) (void)0 - -#endif // TRACY_ENABLE - -// NOLINTEND(cppcoreguidelines-macro-usage) diff --git a/src/util/serializer.hpp b/src/util/serializer.hpp index 18a7deb0..15da2daa 100644 --- a/src/util/serializer.hpp +++ b/src/util/serializer.hpp @@ -1,11 +1,10 @@ #pragma once -#include "util/error.hpp" - #include #include #include #include +#include #include #include diff --git a/tests/render/test_filter_boundary_contracts.cpp b/tests/render/test_filter_boundary_contracts.cpp index 290790f9..f2b474ab 100644 --- a/tests/render/test_filter_boundary_contracts.cpp +++ b/tests/render/test_filter_boundary_contracts.cpp @@ -364,10 +364,8 @@ TEST_CASE("Filter chain standalone API boundary contract coverage", const auto canonical_vulkan_context_hpp = std::filesystem::path(GOGGLES_SOURCE_DIR) / "filter-chain/include/goggles/filter_chain/vulkan_context.hpp"; - const auto canonical_error_hpp = std::filesystem::path(GOGGLES_SOURCE_DIR) / - "filter-chain/include/goggles/filter_chain/error.hpp"; - const auto canonical_result_hpp = std::filesystem::path(GOGGLES_SOURCE_DIR) / - "filter-chain/include/goggles/filter_chain/result.hpp"; + const auto canonical_error_hpp = + std::filesystem::path(GOGGLES_SOURCE_DIR) / "filter-chain/common/include/goggles/error.hpp"; const auto canonical_scale_mode_hpp = std::filesystem::path(GOGGLES_SOURCE_DIR) / "filter-chain/include/goggles/filter_chain/scale_mode.hpp"; @@ -376,14 +374,12 @@ TEST_CASE("Filter chain standalone API boundary contract coverage", auto canonical_filter_controls_text = read_text_file(canonical_filter_controls_hpp); auto canonical_vulkan_context_text = read_text_file(canonical_vulkan_context_hpp); auto canonical_error_text = read_text_file(canonical_error_hpp); - auto canonical_result_text = read_text_file(canonical_result_hpp); auto canonical_scale_mode_text = read_text_file(canonical_scale_mode_hpp); REQUIRE(c_api_text.has_value()); REQUIRE(canonical_filter_controls_text.has_value()); REQUIRE(canonical_vulkan_context_text.has_value()); REQUIRE(canonical_error_text.has_value()); - REQUIRE(canonical_result_text.has_value()); REQUIRE(canonical_scale_mode_text.has_value()); REQUIRE(c_api_text->find("util/") == std::string::npos); @@ -393,7 +389,6 @@ TEST_CASE("Filter chain standalone API boundary contract coverage", REQUIRE(canonical_filter_controls_text->find("util/") == std::string::npos); REQUIRE(canonical_vulkan_context_text->find("util/") == std::string::npos); REQUIRE(canonical_error_text->find("util/") == std::string::npos); - REQUIRE(canonical_result_text->find("util/") == std::string::npos); REQUIRE(canonical_scale_mode_text->find("util/") == std::string::npos); // Verify the standalone C API stage mask constants cover the expected bit values. diff --git a/tests/util/test_error.cpp b/tests/util/test_error.cpp index 41b2551d..4b2c87b6 100644 --- a/tests/util/test_error.cpp +++ b/tests/util/test_error.cpp @@ -1,6 +1,5 @@ -#include "util/error.hpp" - #include +#include #include using namespace goggles; diff --git a/tests/visual/CMakeLists.txt b/tests/visual/CMakeLists.txt index 6f914bbe..124fa2c2 100644 --- a/tests/visual/CMakeLists.txt +++ b/tests/visual/CMakeLists.txt @@ -7,7 +7,7 @@ target_link_libraries(stb_image_write_test_impl PRIVATE stb_image) add_library(image_compare STATIC image_compare.cpp) target_include_directories(image_compare PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(image_compare PUBLIC - nonstd::expected-lite + goggles_core ) target_link_libraries(image_compare PRIVATE stb_image diff --git a/tests/visual/image_compare.hpp b/tests/visual/image_compare.hpp index 380d4e7e..660e817e 100644 --- a/tests/visual/image_compare.hpp +++ b/tests/visual/image_compare.hpp @@ -2,8 +2,8 @@ #include #include +#include #include -#include #include namespace goggles::test {