// Copyright (c) 2025 YAMS Contributors // SPDX-License-Identifier: GPL-3.0-or-later #include #include #include #include #include using namespace yams::features; TEST_CASE("C++23 feature flags are defined", "[core][cpp23]") { // These should always be defined (either 0 or 1) REQUIRE((YAMS_HAS_CONSTEXPR_VECTOR == 0 || YAMS_HAS_CONSTEXPR_VECTOR == 1)); REQUIRE((YAMS_HAS_CONSTEXPR_STRING == 0 || YAMS_HAS_CONSTEXPR_STRING == 1)); REQUIRE((YAMS_HAS_CONSTEXPR_CONTAINERS == 0 || YAMS_HAS_CONSTEXPR_CONTAINERS == 1)); REQUIRE((YAMS_HAS_PROFILES == 0 || YAMS_HAS_PROFILES == 1)); REQUIRE((YAMS_HAS_REFLECTION == 0 || YAMS_HAS_REFLECTION == 1)); } TEST_CASE("FeatureInfo struct is accessible", "[core][cpp23]") { // Should be able to access static constexpr members bool has_containers = FeatureInfo::has_constexpr_containers; bool has_vector = FeatureInfo::has_constexpr_vector; bool has_string = FeatureInfo::has_constexpr_string; bool has_profiles = FeatureInfo::has_profiles; bool has_reflection = FeatureInfo::has_reflection; REQUIRE((has_containers == 0 || has_containers == 1)); REQUIRE((has_vector == 0 || has_vector == 1)); REQUIRE((has_string == 0 || has_string == 1)); REQUIRE((has_profiles == 0 || has_profiles == 1)); REQUIRE((has_reflection == 0 || has_reflection == 1)); } TEST_CASE("Containers flag is consistent with individual flags", "[core][cpp23]") { if (YAMS_HAS_CONSTEXPR_CONTAINERS) { // If containers are enabled, both vector and string must be enabled REQUIRE(YAMS_HAS_CONSTEXPR_VECTOR == 1); REQUIRE(YAMS_HAS_CONSTEXPR_STRING == 1); } else { // If containers are disabled, at least one of vector/string is disabled REQUIRE((YAMS_HAS_CONSTEXPR_VECTOR == 0 || YAMS_HAS_CONSTEXPR_STRING == 0)); } } TEST_CASE("Compiler info is defined", "[core][cpp23]") { const char* compiler_name = FeatureInfo::compiler_name; int compiler_version = FeatureInfo::compiler_version; long cpp_version = FeatureInfo::cpp_version; REQUIRE(compiler_name != nullptr); REQUIRE(compiler_version > 0); REQUIRE(cpp_version >= 202002L); // At least C++20 } TEST_CASE("Feature summary string is valid", "[core][cpp23]") { const char* summary = get_feature_summary(); REQUIRE(summary != nullptr); REQUIRE(strlen(summary) > 0); // Summary should mention C++20 or C++23 std::string summary_str(summary); bool mentions_std = summary_str.find("C++20") != std::string::npos || summary_str.find("C++23") != std::string::npos; REQUIRE(mentions_std); } TEST_CASE("YAMS_CONSTEXPR_IF_SUPPORTED macro expands correctly", "[core][cpp23]") { // This test verifies the macro expands without syntax errors // The actual behavior (constexpr vs inline) depends on feature detection auto test_func = []() YAMS_CONSTEXPR_IF_SUPPORTED -> int { return 42; }; REQUIRE(test_func() == 42); } TEST_CASE("YAMS_PROFILE macro expands without errors", "[core][cpp23]") { // Profile macro should expand to either [[profile: ...]] or nothing struct YAMS_PROFILE(type) TestStruct { int value = 0; }; TestStruct s; s.value = 10; REQUIRE(s.value == 10); } #if YAMS_HAS_CONSTEXPR_CONTAINERS TEST_CASE("Constexpr vector works when available", "[core][cpp23][constexpr]") { // NOTE: In GCC 15, even with C++23, lambdas with constexpr vector // can have issues with operator new. Use a function instead. constexpr auto make_vec = []() constexpr { std::vector v; v.push_back(1); v.push_back(2); v.push_back(3); return v; }; // Test at runtime (constexpr works but GCC 15 has lambda limitations) auto vec = make_vec(); REQUIRE(vec.size() == 3); REQUIRE(vec[0] == 1); REQUIRE(vec[1] == 2); REQUIRE(vec[2] == 3); } TEST_CASE("Constexpr string works when available", "[core][cpp23][constexpr]") { constexpr auto make_str = []() constexpr { std::string s = "hello"; s += " world"; return s; }; // Test at runtime auto str = make_str(); REQUIRE(str == "hello world"); REQUIRE(str.size() == 11); } TEST_CASE("Constexpr containers work together", "[core][cpp23][constexpr]") { // Simplified test - avoid complex nested constexpr for now struct Data { std::string name; std::vector values; }; auto make_data = []() { std::vector result; result.push_back({"first", {1, 2, 3}}); result.push_back({"second", {4, 5, 6}}); return result; }; auto data = make_data(); REQUIRE(data.size() == 2); REQUIRE(data[0].name == "first"); REQUIRE(data[0].values.size() == 3); REQUIRE(data[1].name == "second"); REQUIRE(data[1].values.size() == 3); } #endif #if !YAMS_HAS_CONSTEXPR_CONTAINERS TEST_CASE("C++20 fallback for vectors works", "[core][cpp23][fallback]") { // In C++20 mode, we should still be able to use vectors and strings // They just won't be constexpr auto make_vec = []() { std::vector v; v.push_back(1); v.push_back(2); v.push_back(3); return v; }; auto vec = make_vec(); REQUIRE(vec.size() == 3); REQUIRE(vec[0] == 1); } TEST_CASE("C++20 fallback for strings works", "[core][cpp23][fallback]") { auto make_str = []() { std::string s = "hello"; s += " world"; return s; }; auto str = make_str(); REQUIRE(str == "hello world"); } #endif TEST_CASE("C++ version is checked correctly", "[core][cpp23]") { long cpp_ver = YAMS_CPP_VERSION; // Should be at least C++20 REQUIRE(cpp_ver >= 202002L); // Note: MSVC may report __cplusplus as 202002L even when C++23 features // are available. The YAMS_HAS_CONSTEXPR_CONTAINERS macro is based on // actual feature detection, not __cplusplus value. // Therefore we only verify the minimum required version (C++20). } TEST_CASE("Deprecation macro compiles without errors", "[core][cpp23]") { YAMS_CPP23_DEPRECATED("test message") auto old_function = []() { return 42; }; #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" #endif REQUIRE(old_function() == 42); #if defined(__clang__) #pragma clang diagnostic pop #endif }