From 32e4f67c75f2577f04d0ad99df400b1881fa202a Mon Sep 17 00:00:00 2001 From: AstroAir Date: Thu, 14 Nov 2024 09:18:48 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=20Huffman=20=E7=BC=96?= =?UTF-8?q?=E7=A0=81=E5=AE=9E=E7=8E=B0=EF=BC=8C=E9=87=8D=E6=9E=84=E5=88=86?= =?UTF-8?q?=E6=95=B0=E7=B1=BB=E6=9E=84=E9=80=A0=E5=87=BD=E6=95=B0=EF=BC=8C?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=86=85=E5=AD=98=E5=AF=B9=E9=BD=90=E5=88=86?= =?UTF-8?q?=E9=85=8D=E5=8A=9F=E8=83=BD=EF=BC=8C=E6=9B=B4=E6=96=B0=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E5=A4=84=E7=90=86=EF=BC=8C=E5=A2=9E=E5=BC=BA=20Any=20?= =?UTF-8?q?=E7=B1=BB=E7=9A=84=E7=B1=BB=E5=9E=8B=E5=AE=89=E5=85=A8=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/atom/algorithm/fraction.cpp | 12 +- src/atom/algorithm/fraction.hpp | 27 +- src/atom/algorithm/huffman.cpp | 1 + src/atom/algorithm/huffman.hpp | 2 - src/atom/function/any.hpp | 8 + src/atom/function/field_count.hpp | 205 ++++++++++----- src/atom/function/proxy_params.hpp | 22 +- src/atom/function/type_caster.hpp | 105 +++++--- src/atom/function/vany.hpp | 94 +++++-- src/atom/io/pushd.hpp | 4 +- src/utils/constant.hpp | 2 +- tests/atom/algorithm/fraction.cpp | 239 ++++++++++++----- tests/atom/algorithm/huffman.cpp | 188 ++++++++++++-- tests/components/meta/any.cpp | 306 +++++++++++++--------- tests/components/meta/anymeta.cpp | 342 ++++++++++--------------- tests/components/meta/enum.cpp | 240 ++++++++++------- tests/components/meta/field_count.cpp | 196 ++++++++++---- tests/components/meta/proxy_params.cpp | 67 +++-- tests/components/meta/type_caster.cpp | 220 +++++++++++----- 19 files changed, 1481 insertions(+), 799 deletions(-) diff --git a/src/atom/algorithm/fraction.cpp b/src/atom/algorithm/fraction.cpp index a8826a29..643155b4 100644 --- a/src/atom/algorithm/fraction.cpp +++ b/src/atom/algorithm/fraction.cpp @@ -14,6 +14,9 @@ Description: Implementation of Fraction class #include "fraction.hpp" +#include +#include + namespace atom::algorithm { /* ------------------------ Private Methods ------------------------ */ @@ -39,15 +42,6 @@ void Fraction::reduce() noexcept { denominator /= divisor; } -/* ------------------------ Constructors ------------------------ */ - -constexpr Fraction::Fraction(int n, int d) : numerator(n), denominator(d) { - if (denominator == 0) { - throw FractionException("Denominator cannot be zero."); - } - reduce(); -} - /* ------------------------ Arithmetic Operators ------------------------ */ auto Fraction::operator+=(const Fraction& other) -> Fraction& { diff --git a/src/atom/algorithm/fraction.hpp b/src/atom/algorithm/fraction.hpp index 0513dabf..cd96bc92 100644 --- a/src/atom/algorithm/fraction.hpp +++ b/src/atom/algorithm/fraction.hpp @@ -17,11 +17,7 @@ Description: Implementation of Fraction class #include #include -#include -#include #include -#include -#include #include #include @@ -65,7 +61,23 @@ class Fraction { * @param d The denominator (default is 1). * @throws FractionException if the denominator is zero. */ - explicit constexpr Fraction(int n = 0, int d = 1); + explicit constexpr Fraction(int n, int d) : numerator(n), denominator(d) { + if (denominator == 0) { + throw FractionException("Denominator cannot be zero."); + } + reduce(); + } + + /** + * @brief Constructs a new Fraction object with the given integer value. + * @param value The integer value. + */ + explicit constexpr Fraction(int value) : numerator(value), denominator(1) {} + + /** + * @brief Default constructor. Initializes the fraction as 0/1. + */ + constexpr Fraction() : Fraction(0, 1) {} /** * @brief Adds another fraction to this fraction. @@ -229,7 +241,7 @@ class Fraction { * @param value The integer value. * @return A Fraction representing the integer. */ -inline auto makeFraction(int value) -> Fraction; +auto makeFraction(int value) -> Fraction; /** * @brief Creates a Fraction from a double by approximating it. @@ -238,8 +250,7 @@ inline auto makeFraction(int value) -> Fraction; * approximation. * @return A Fraction approximating the double value. */ -inline auto makeFraction(double value, - int max_denominator = 1000000) -> Fraction; +auto makeFraction(double value, int max_denominator = 1000000) -> Fraction; } // namespace atom::algorithm diff --git a/src/atom/algorithm/huffman.cpp b/src/atom/algorithm/huffman.cpp index 538db423..69bdd500 100644 --- a/src/atom/algorithm/huffman.cpp +++ b/src/atom/algorithm/huffman.cpp @@ -15,6 +15,7 @@ Description: Enhanced implementation of Huffman encoding #include "huffman.hpp" #include #include +#include #include #include diff --git a/src/atom/algorithm/huffman.hpp b/src/atom/algorithm/huffman.hpp index 4feac740..d4c00d2c 100644 --- a/src/atom/algorithm/huffman.hpp +++ b/src/atom/algorithm/huffman.hpp @@ -15,8 +15,6 @@ Description: Enhanced implementation of Huffman encoding #ifndef ATOM_ALGORITHM_HUFFMAN_HPP #define ATOM_ALGORITHM_HUFFMAN_HPP -#include -#include #include #include #include diff --git a/src/atom/function/any.hpp b/src/atom/function/any.hpp index fec99269..405368a2 100644 --- a/src/atom/function/any.hpp +++ b/src/atom/function/any.hpp @@ -26,6 +26,8 @@ #include #include +#include "atom/error/exception.hpp" +#include "atom/function/proxy.hpp" #include "atom/macro.hpp" #include "type_info.hpp" @@ -252,6 +254,12 @@ class BoxedValue { } } + template + auto isType() const -> bool { + std::shared_lock lock(m_mutex_); + return m_data_->mTypeInfo == userType(); + } + /*! * \brief Check if the value is undefined. * \return True if the value is undefined, false otherwise. diff --git a/src/atom/function/field_count.hpp b/src/atom/function/field_count.hpp index 2c4138db..21ace72f 100644 --- a/src/atom/function/field_count.hpp +++ b/src/atom/function/field_count.hpp @@ -1,97 +1,160 @@ -/*! - * \file field_count.hpp - * \brief Field Count - * \author Max Qian - * \date 2024-05-25 - * \copyright Copyright (C) 2023-2024 Max Qian - */ +#ifndef ATOMMETA_FIELD_COUNT_HPP +#define ATOMMETA_FIELD_COUNT_HPP -#ifndef ATOM_META_FIELD_COUNT_HPP -#define ATOM_META_FIELD_COUNT_HPP +#include +namespace atom::meta::details { +struct Any; -#include -#include +struct Any { + constexpr Any(int) {} -namespace atom::meta { + template + requires std::is_copy_constructible_v + operator T&(); -/*! - * \brief A struct that can be converted to any type. - */ -struct Any { - /*! - * \brief Constexpr conversion operator to any type. - * \tparam T The type to convert to. - * \return An instance of type T. - */ template - explicit consteval operator T() const noexcept; + requires std::is_move_constructible_v + operator T&&(); + + struct Empty {}; + + template + requires(!std::is_copy_constructible_v && + !std::is_move_constructible_v && + !std::is_constructible_v) + operator T(); }; -/*! - * \brief Checks if a type T is constructible with braces. - * \tparam T The type to check. - * \tparam I The index sequence. - * \param[in] indices The index sequence. - * \return True if T is constructible with braces, false otherwise. - */ -template -consteval auto isBracesConstructible( - std::index_sequence /*indices*/) noexcept -> bool { - return requires { T{((void)I, std::declval())...}; }; +template +consteval auto tryInitializeWithN() -> std::size_t { + return [](std::index_sequence) { + return requires { T{Any(Is)...}; }; + }(std::make_index_sequence{}); } -/*! - * \brief Recursively counts the number of fields in a type T. - * \tparam T The type to count fields in. - * \tparam N The current count of fields. - * \return The number of fields in type T. - */ template -consteval auto fieldCount() noexcept -> std::size_t { - if constexpr (!isBracesConstructible( - std::make_index_sequence{})) { +consteval auto totalCountOfFields() -> std::size_t { + if constexpr (tryInitializeWithN() && + !tryInitializeWithN()) { return N; } else { - return fieldCount(); + return totalCountOfFields(); } } +} // namespace atom::meta::details -/*! - * \brief A template struct to hold type information. - * \tparam T The type to hold information for. - */ -template -struct TypeInfo; +namespace atom::meta::details { + +template +consteval auto tryInitializeWithThreeParts() -> std::size_t { + return []( + std::index_sequence, std::index_sequence, + std::index_sequence) { + return requires { T{Any(I1)..., {Any(I2)...}, Any(I3)...}; }; + }(std::make_index_sequence{}, std::make_index_sequence{}, + std::make_index_sequence{}); +} + +template +constexpr auto tryPlaceNInPos() -> bool { + constexpr auto Total = totalCountOfFields(); + if constexpr (N == 0) { + return true; + } else if constexpr (position + N <= Total) { + return tryInitializeWithThreeParts(); + } else { + return false; + } +} + +template +constexpr auto hasExtraElements() -> bool { + constexpr auto Total = totalCountOfFields(); + if constexpr (tryInitializeWithThreeParts()) { + return false; + } else if constexpr (N + 1 <= Max) { + return hasExtraElements(); + } else { + return true; + } +} + +template +constexpr auto searchMaxInPos() -> std::size_t { + constexpr auto Total = totalCountOfFields(); + if constexpr (!hasExtraElements()) { + return 1; + } else { + std::size_t result = 0; + [&](std::index_sequence) { + ((tryPlaceNInPos() ? result = Is : 0), ...); + }(std::make_index_sequence()); + return result; + } +} + +template +constexpr auto searchAllExtraIndex(auto&& array) { + constexpr auto total = totalCountOfFields(); + constexpr auto value = std::max(searchMaxInPos(), 1); + array[N] = value; + if constexpr (N + value < total) { + searchAllExtraIndex(array); + } +} -/*! - * \brief Gets the number of fields in a type T. - * \tparam T The type to get the field count for. - * \return The number of fields in type T. - */ template -consteval auto fieldCountOf() noexcept -> std::size_t { - if constexpr (std::is_aggregate_v) { - if constexpr (requires { TypeInfo::count; }) { - return TypeInfo::count; - } else { - return fieldCount(); - } +constexpr auto trueCountOfFields() { + constexpr auto max = totalCountOfFields(); + if constexpr (max == 0) { + return 0; } else { - return 0; // Non-aggregate types are considered to have 0 fields + std::array indices = {1}; + searchAllExtraIndex(indices); + std::size_t result = max; + std::size_t index = 0; + while (index < max) { + auto n = indices[index]; + result -= n - 1; + index += n; + } + return result; } } +} // namespace atom::meta::details + +namespace atom::meta { +template +struct type_info; -/*! - * \brief Gets the number of elements in an array. - * \tparam T The type of the array elements. - * \tparam N The number of elements in the array. - * \return The number of elements in the array. +/** + * @brief Retrieve the count of fields of a struct + * @warning cannot get the count of fields of a struct which has reference + * type member in gcc 13 because the internal error occurs in below occasion + * @code + * struct Number { operator int&(); }; + * int& x = { Number{} }; + * + * internal compiler error: in reference_binding, at cp/call.cc:2020 + * @endcode + * */ -template -consteval auto fieldCountOf() noexcept -> std::size_t { - return N; +template + requires std::is_aggregate_v +consteval auto fieldCountOf() { + if constexpr (requires { type_info::count; }) { + return type_info::count; + } else { + return details::trueCountOfFields(); + } } +template + requires(!std::is_aggregate_v) +consteval auto fieldCountOf() { + return 0; +} } // namespace atom::meta -#endif // ATOM_META_FIELD_COUNT_HPP +#endif // ATOMMETA_FIELD_COUNT_HPP \ No newline at end of file diff --git a/src/atom/function/proxy_params.hpp b/src/atom/function/proxy_params.hpp index 949a06b7..6fb0cbac 100644 --- a/src/atom/function/proxy_params.hpp +++ b/src/atom/function/proxy_params.hpp @@ -60,8 +60,8 @@ inline void to_json(nlohmann::json& j, const std::any& a) { j = std::any_cast(a); } else if (a.type() == typeid(std::string_view)) { j = std::any_cast(a); - } else if (a.type() == typeid(const char *)) { - j = std::any_cast(a); + } else if (a.type() == typeid(const char*)) { + j = std::any_cast(a); } else { throw std::runtime_error("Unsupported type"); } @@ -293,6 +293,24 @@ class FunctionParams { params_[index] = arg; } + template + [[nodiscard]] auto getValueAs(size_t index) const -> std::optional { + if (index >= params_.size()) { + return std::nullopt; + } + + const auto& value = params_[index].getDefaultValue(); + if (!value.has_value()) { + return std::nullopt; + } + + try { + return std::any_cast(value.value()); + } catch (const std::bad_any_cast&) { + return std::nullopt; + } + } + private: std::vector params_; ///< The vector of Arg objects. }; diff --git a/src/atom/function/type_caster.hpp b/src/atom/function/type_caster.hpp index 270db6ac..65538dfc 100644 --- a/src/atom/function/type_caster.hpp +++ b/src/atom/function/type_caster.hpp @@ -10,12 +10,13 @@ #ifndef ATOM_META_TYPE_CASTER_HPP #define ATOM_META_TYPE_CASTER_HPP -#include // Includes for std::any -#include // Includes for std::size_t -#include // Includes for std::function -#include // Includes for std::shared_ptr -#include // Includes for std::mutex -#include // Includes for std::queue +#include // Includes for std::any +#include // Includes for std::size_t +#include // Includes for std::function +#include // Includes for std::shared_ptr +#include // Includes for std::mutex +#include // Includes for std::queue +#include #include // Includes for std::string #include // Includes for std::type_info #include // Includes for std::unordered_map @@ -59,8 +60,14 @@ class TypeCaster { */ template auto convert(const std::any& input) const -> std::any { - auto srcInfo = getTypeInfo(input.type().name()); - auto destInfo = userType(); + // 分段加锁,避免死锁 + TypeInfo destInfo; + std::optional srcInfo; + { + std::shared_lock type_lock(type_mutex_); + srcInfo = getTypeInfo(input.type().name()); + destInfo = userType(); + } if (!srcInfo.has_value()) { THROW_INVALID_ARGUMENT("Source type not found."); @@ -70,10 +77,19 @@ class TypeCaster { return input; } - auto path = findShortestConversionPath(srcInfo.value(), destInfo); + std::vector conversions; + { + std::shared_lock conv_lock(conversion_mutex_); + auto path = findShortestConversionPath(srcInfo.value(), destInfo); + conversions.reserve(path.size() - 1); + for (size_t i = 0; i < path.size() - 1; ++i) { + conversions.push_back(conversions_.at(path[i]).at(path[i + 1])); + } + } + std::any result = input; - for (size_t j = 0; j < path.size() - 1; ++j) { - result = conversions_.at(path[j]).at(path[j + 1])(result); + for (const auto& converter : conversions) { + result = converter(result); } return result; } @@ -88,17 +104,20 @@ class TypeCaster { */ template void registerConversion(ConvertFunc func) { - std::lock_guard lock(mutex_); // Ensure thread safety + std::unique_lock type_lock(type_mutex_); + std::unique_lock conv_lock(conversion_mutex_); + auto srcInfo = userType(); auto destInfo = userType(); - registerType(srcInfo.bareName()); - registerType(destInfo.bareName()); if (srcInfo == destInfo) { THROW_INVALID_ARGUMENT( "Source and destination types must be different."); } + registerType(srcInfo.bareName()); + registerType(destInfo.bareName()); + conversions_[srcInfo][destInfo] = std::move(func); clearCache(); } @@ -110,8 +129,10 @@ class TypeCaster { */ template void registerAlias(const std::string& alias) { - std::lock_guard lock(mutex_); - type_alias_map_[alias] = userType(); + std::unique_lock type_lock(type_mutex_); + auto type_info = userType(); + type_alias_map_[alias] = type_info; + type_name_map_[alias] = type_info; } /*! @@ -121,7 +142,7 @@ class TypeCaster { */ void registerTypeGroup(const std::string& groupName, const std::vector& types) { - std::lock_guard lock(mutex_); + std::unique_lock type_lock(type_mutex_); for (const auto& typeName : types) { type_group_map_[typeName] = groupName; } @@ -149,7 +170,7 @@ class TypeCaster { * \return True if a conversion exists, false otherwise. */ auto hasConversion(TypeInfo src, TypeInfo dst) const -> bool { - std::lock_guard lock(mutex_); + std::shared_lock conv_lock(conversion_mutex_); return conversions_.find(src) != conversions_.end() && conversions_.at(src).find(dst) != conversions_.at(src).end(); } @@ -159,7 +180,7 @@ class TypeCaster { * \return A vector of registered type names. */ auto getRegisteredTypes() const -> std::vector { - std::lock_guard lock(mutex_); + std::shared_lock type_lock(type_mutex_); std::vector typeNames; typeNames.reserve(type_name_map_.size()); for (const auto& [name, info] : type_name_map_) { @@ -175,10 +196,11 @@ class TypeCaster { */ template void registerType(const std::string& name) { - std::lock_guard lock(mutex_); - type_name_map_[name] = userType(); - type_name_map_[typeid(T).name()] = userType(); - detail::getTypeRegistry()[typeid(T).name()] = userType(); + std::unique_lock type_lock(type_mutex_); + auto type_info = userType(); + type_name_map_[name] = type_info; + type_name_map_[typeid(T).name()] = type_info; + detail::getTypeRegistry()[typeid(T).name()] = type_info; } /*! @@ -192,6 +214,7 @@ class TypeCaster { void registerEnumValue(const std::string& enum_name, const std::string& string_value, EnumType enum_value) { + std::unique_lock enum_lock(enum_mutex_); if (!m_enumMaps_.contains(enum_name)) { m_enumMaps_[enum_name] = std::unordered_map(); @@ -200,7 +223,6 @@ class TypeCaster { auto& enumMap = std::any_cast&>( m_enumMaps_[enum_name]); - enumMap[string_value] = enum_value; } @@ -215,6 +237,7 @@ class TypeCaster { template auto enumToString(EnumType value, const std::string& enum_name) -> std::string { + std::shared_lock enum_lock(enum_mutex_); const auto& enumMap = getEnumMap(enum_name); for (const auto& [key, enumValue] : enumMap) { if (enumValue == value) { @@ -235,6 +258,7 @@ class TypeCaster { template auto stringToEnum(const std::string& string_value, const std::string& enum_name) -> EnumType { + std::shared_lock enum_lock(enum_mutex_); const auto& enumMap = getEnumMap(enum_name); auto iterator = enumMap.find(string_value); if (iterator != enumMap.end()) { @@ -252,7 +276,10 @@ class TypeCaster { std::unordered_map type_group_map_; std::unordered_map m_enumMaps_; - mutable std::mutex mutex_; // Ensure thread safety + mutable std::shared_mutex type_mutex_; + mutable std::shared_mutex conversion_mutex_; + mutable std::shared_mutex enum_mutex_; + static inline std::shared_mutex registry_mutex_; /*! * \brief Registers built-in types. @@ -267,7 +294,7 @@ class TypeCaster { registerType("char"); registerType("unsigned char"); registerType("char"); - registerType("char *"); + registerType("char *"); registerType("const char*"); registerType("std::string"); registerType("std::string_view"); @@ -283,16 +310,26 @@ class TypeCaster { */ auto findShortestConversionPath(TypeInfo src, TypeInfo dst) const -> std::vector { + // 已经在调用方获取了读锁,这里不需要重复加锁 std::string cacheKey = makeCacheKey(src, dst); - if (conversion_paths_cache_.find(cacheKey) != - conversion_paths_cache_.end()) { - return conversion_paths_cache_.at(cacheKey); + + if (auto it = conversion_paths_cache_.find(cacheKey); + it != conversion_paths_cache_.end()) { + return it->second; } - std::queue> paths; - paths.push({src}); + // 查找路径的过程中使用已获取的读锁 + auto path = findPath(src, dst); + conversion_paths_cache_[cacheKey] = path; + return path; + } + // 辅助方法:实际的路径查找逻辑 + auto findPath(TypeInfo src, TypeInfo dst) const -> std::vector { + std::queue> paths; std::unordered_set visited; + + paths.push({src}); visited.insert(src); while (!paths.empty()) { @@ -301,13 +338,11 @@ class TypeCaster { auto last = currentPath.back(); if (last == dst) { - conversion_paths_cache_[cacheKey] = currentPath; return currentPath; } - auto findIt = conversions_.find(last); - if (findIt != conversions_.end()) { - for (const auto& [next_type, _] : findIt->second) { + if (auto it = conversions_.find(last); it != conversions_.end()) { + for (const auto& [next_type, _] : it->second) { if (visited.insert(next_type).second) { auto newPath = currentPath; newPath.push_back(next_type); diff --git a/src/atom/function/vany.hpp b/src/atom/function/vany.hpp index e8e27559..c0eacf8f 100644 --- a/src/atom/function/vany.hpp +++ b/src/atom/function/vany.hpp @@ -117,21 +117,31 @@ class Any { public: Any() noexcept : storage{} {} - Any(const Any& other) : vptr_(other.vptr_), is_small_(other.is_small_) { + Any(const Any& other) + : vptr_(other.vptr_), is_small_(other.is_small_), ptr(nullptr) { if (vptr_ != nullptr) { - if (is_small_) { - vptr_->copy(other.getPtr(), storage.data()); - } else { - ptr = std::malloc(vptr_->size()); - if (ptr == nullptr) { - throw std::bad_alloc(); - } - try { + try { + if (is_small_) { + // 小对象直接拷贝到storage + std::memcpy(storage.data(), other.getPtr(), vptr_->size()); + } else { + // 大对象需要动态分配内存 + ptr = std::malloc(vptr_->size()); + if (ptr == nullptr) { + throw std::bad_alloc(); + } + // 拷贝数据 vptr_->copy(other.getPtr(), ptr); - } catch (...) { + } + } catch (...) { + // 清理已分配的资源 + if (!is_small_ && ptr != nullptr) { std::free(ptr); - throw; + ptr = nullptr; } + vptr_ = nullptr; + is_small_ = true; + throw; // 重新抛出异常 } } } @@ -148,21 +158,63 @@ class Any { } } + template + auto allocateAligned(size_t size, size_t alignment) -> T* { + // 确保对齐值是2的幂 + if (alignment & (alignment - 1)) { + alignment = std::bit_ceil(alignment); + } + + // 确保对齐值至少等于sizeof(void*) + alignment = std::max(alignment, sizeof(void*)); + + void* ptr = std::aligned_alloc(alignment, size); + if (!ptr) { + throw std::bad_alloc(); + } + + return static_cast(ptr); + } + template explicit Any(T&& value) { using ValueType = std::remove_cvref_t; - if constexpr (kIsSmallObject) { - new (storage.data()) ValueType(std::forward(value)); - is_small_ = true; - } else { - ptr = std::malloc(sizeof(ValueType)); - if (!ptr) { - throw std::bad_alloc(); + try { + if constexpr (kIsSmallObject) { + // 确保内存对齐 + alignas(std::max_align_t) char* addr = storage.data(); + new (addr) ValueType(std::forward(value)); + is_small_ = true; + } else { + // 使用智能指针临时管理内存 + auto temp = allocateAligned( + sizeof(ValueType), + std::max(alignof(ValueType), alignof(std::max_align_t))); + if (!temp) { + throw std::bad_alloc(); + } + + try { + new (temp) ValueType(std::forward(value)); + ptr = temp; + is_small_ = false; + } catch (...) { + std::free(temp); + throw; + } + } + + // 确保vtable初始化在对象构造完成后 + if constexpr (std::is_trivially_destructible_v) { + vptr_ = &K_V_TABLE; + } else { + static const VTable vtable = K_V_TABLE; + vptr_ = &vtable; } - new (ptr) ValueType(std::forward(value)); - is_small_ = false; + } catch (...) { + reset(); // 清理已分配的资源 + throw; } - vptr_ = &K_V_TABLE; } ~Any() { reset(); } diff --git a/src/atom/io/pushd.hpp b/src/atom/io/pushd.hpp index 6dae1106..65b76f63 100644 --- a/src/atom/io/pushd.hpp +++ b/src/atom/io/pushd.hpp @@ -1,11 +1,13 @@ #ifndef ATOM_IO_PUSHD_HPP #define ATOM_IO_PUSHD_HPP -#include #include #include #include #include +#include + +#include namespace atom::io { // Forward declaration of the implementation class diff --git a/src/utils/constant.hpp b/src/utils/constant.hpp index c2ab8525..73d3dcd5 100644 --- a/src/utils/constant.hpp +++ b/src/utils/constant.hpp @@ -26,7 +26,7 @@ Description: Constants for Lithium #define DEFINE_LITHIUM_CONSTANT(name) \ static constexpr const char* name = "lithium." #name; \ - static constexpr unsigned int name##_hash = hash(name); + static constexpr unsigned int name##_hash = atom::algorithm::hash(name); class Constants { public: diff --git a/tests/atom/algorithm/fraction.cpp b/tests/atom/algorithm/fraction.cpp index 8ae139eb..1cdcff41 100644 --- a/tests/atom/algorithm/fraction.cpp +++ b/tests/atom/algorithm/fraction.cpp @@ -1,89 +1,202 @@ #include "atom/algorithm/fraction.hpp" #include -// Tests for Fraction class -TEST(FractionTest, Constructor) { - atom::algorithm::Fraction f1; - EXPECT_EQ(f1.numerator, 0); - EXPECT_EQ(f1.denominator, 1); +using namespace atom::algorithm; - atom::algorithm::Fraction f2(3, 4); - EXPECT_EQ(f2.numerator, 3); - EXPECT_EQ(f2.denominator, 4); +class FractionTest : public ::testing::Test { +protected: + void SetUp() override {} + void TearDown() override {} +}; - atom::algorithm::Fraction f3(6, -8); - EXPECT_EQ(f3.numerator, -3); - EXPECT_EQ(f3.denominator, 4); +// Construction Tests +TEST_F(FractionTest, DefaultConstructor) { + Fraction f; + EXPECT_EQ(f.toString(), "0/1"); } -TEST(FractionTest, Addition) { - atom::algorithm::Fraction f1(1, 2); - atom::algorithm::Fraction f2(1, 3); - atom::algorithm::Fraction result = f1 + f2; - EXPECT_EQ(result.numerator, 5); - EXPECT_EQ(result.denominator, 6); +TEST_F(FractionTest, ConstructorWithValues) { + Fraction f(3, 4); + EXPECT_EQ(f.toString(), "3/4"); } -TEST(FractionTest, Subtraction) { - atom::algorithm::Fraction f1(1, 2); - atom::algorithm::Fraction f2(1, 3); - atom::algorithm::Fraction result = f1 - f2; - EXPECT_EQ(result.numerator, 1); - EXPECT_EQ(result.denominator, 6); +TEST_F(FractionTest, ConstructorAutoReduces) { + Fraction f(2, 4); + EXPECT_EQ(f.toString(), "1/2"); } -TEST(FractionTest, Multiplication) { - atom::algorithm::Fraction f1(1, 2); - atom::algorithm::Fraction f2(1, 3); - atom::algorithm::Fraction result = f1 * f2; - EXPECT_EQ(result.numerator, 1); - EXPECT_EQ(result.denominator, 6); +TEST_F(FractionTest, ConstructorWithNegatives) { + Fraction f1(-3, 4); + Fraction f2(3, -4); + Fraction f3(-3, -4); + EXPECT_EQ(f1.toString(), "-3/4"); + EXPECT_EQ(f2.toString(), "-3/4"); + EXPECT_EQ(f3.toString(), "3/4"); } -TEST(FractionTest, Division) { - atom::algorithm::Fraction f1(1, 2); - atom::algorithm::Fraction f2(1, 3); - atom::algorithm::Fraction result = f1 / f2; - EXPECT_EQ(result.numerator, 3); - EXPECT_EQ(result.denominator, 2); +TEST_F(FractionTest, ConstructorThrowsOnZeroDenominator) { + EXPECT_THROW(Fraction(1, 0), FractionException); } -TEST(FractionTest, Equality) { - atom::algorithm::Fraction f1(1, 2); - atom::algorithm::Fraction f2(1, 2); - atom::algorithm::Fraction f3(2, 4); - EXPECT_TRUE(f1 == f2); - EXPECT_TRUE(f1 == f3); +// Arithmetic Tests +TEST_F(FractionTest, Addition) { + Fraction f1(1, 2); + Fraction f2(1, 3); + Fraction result = f1 + f2; + EXPECT_EQ(result.toString(), "5/6"); } -TEST(FractionTest, Conversion) { - atom::algorithm::Fraction f1(1, 2); - EXPECT_DOUBLE_EQ(static_cast(f1), 0.5); - EXPECT_FLOAT_EQ(static_cast(f1), 0.5f); - EXPECT_EQ(static_cast(f1), 0); +TEST_F(FractionTest, Subtraction) { + Fraction f1(3, 4); + Fraction f2(1, 4); + Fraction result = f1 - f2; + EXPECT_EQ(result.toString(), "1/2"); } -TEST(FractionTest, ToString) { - atom::algorithm::Fraction f1(1, 2); - EXPECT_EQ(f1.toString(), "1/2"); +TEST_F(FractionTest, Multiplication) { + Fraction f1(2, 3); + Fraction f2(3, 4); + Fraction result = f1 * f2; + EXPECT_EQ(result.toString(), "1/2"); +} - atom::algorithm::Fraction f2(-3, 4); - EXPECT_EQ(f2.toString(), "-3/4"); +TEST_F(FractionTest, Division) { + Fraction f1(1, 2); + Fraction f2(1, 4); + Fraction result = f1 / f2; + EXPECT_EQ(result.toString(), "2/1"); } -TEST(FractionTest, ToDouble) { - atom::algorithm::Fraction f1(1, 2); - EXPECT_DOUBLE_EQ(f1.toDouble(), 0.5); +// Compound Assignment Tests +TEST_F(FractionTest, CompoundAddition) { + Fraction f(1, 2); + f += Fraction(1, 4); + EXPECT_EQ(f.toString(), "3/4"); } -TEST(FractionTest, IOStream) { - atom::algorithm::Fraction f1(1, 2); - std::stringstream ss; - ss << f1; - EXPECT_EQ(ss.str(), "1/2"); +TEST_F(FractionTest, CompoundSubtraction) { + Fraction f(3, 4); + f -= Fraction(1, 4); + EXPECT_EQ(f.toString(), "1/2"); +} + +TEST_F(FractionTest, CompoundMultiplication) { + Fraction f(2, 3); + f *= Fraction(3, 4); + EXPECT_EQ(f.toString(), "1/2"); +} - atom::algorithm::Fraction f2; - ss >> f2; - EXPECT_EQ(f2.numerator, 1); - EXPECT_EQ(f2.denominator, 2); +TEST_F(FractionTest, CompoundDivision) { + Fraction f(1, 2); + f /= Fraction(2, 3); + EXPECT_EQ(f.toString(), "3/4"); } + +// Comparison Tests +TEST_F(FractionTest, Equality) { + EXPECT_EQ(Fraction(1, 2), Fraction(2, 4)); + EXPECT_NE(Fraction(1, 2), Fraction(1, 3)); +} + +#if __cplusplus >= 202002L +TEST_F(FractionTest, ThreeWayComparison) { + EXPECT_TRUE(Fraction(1, 2) < Fraction(2, 3)); + EXPECT_TRUE(Fraction(3, 4) > Fraction(1, 2)); + EXPECT_TRUE(Fraction(1, 2) <= Fraction(1, 2)); + EXPECT_TRUE(Fraction(1, 2) >= Fraction(1, 2)); +} +#endif + +// Conversion Tests +TEST_F(FractionTest, ToDouble) { + Fraction f(1, 2); + EXPECT_DOUBLE_EQ(static_cast(f), 0.5); +} + +TEST_F(FractionTest, ToFloat) { + Fraction f(1, 4); + EXPECT_FLOAT_EQ(static_cast(f), 0.25f); +} + +TEST_F(FractionTest, ToInt) { + EXPECT_EQ(static_cast(Fraction(5, 2)), 2); + EXPECT_EQ(static_cast(Fraction(-5, 2)), -2); +} + +// Helper Method Tests +TEST_F(FractionTest, ToString) { + EXPECT_EQ(Fraction(1, 2).toString(), "1/2"); + EXPECT_EQ(Fraction(-1, 2).toString(), "-1/2"); + EXPECT_EQ(Fraction(0, 1).toString(), "0/1"); +} + +TEST_F(FractionTest, Invert) { + Fraction f(2, 3); + f.invert(); + EXPECT_EQ(f.toString(), "3/2"); +} + +TEST_F(FractionTest, InvertThrowsOnZero) { + Fraction f(0, 1); + EXPECT_THROW(f.invert(), FractionException); +} + +TEST_F(FractionTest, Abs) { + EXPECT_EQ(Fraction(-1, 2).abs(), Fraction(1, 2)); + EXPECT_EQ(Fraction(1, 2).abs(), Fraction(1, 2)); +} + +TEST_F(FractionTest, IsZero) { + EXPECT_TRUE(Fraction(0, 1).isZero()); + EXPECT_FALSE(Fraction(1, 2).isZero()); +} + +TEST_F(FractionTest, IsPositive) { + EXPECT_TRUE(Fraction(1, 2).isPositive()); + EXPECT_FALSE(Fraction(-1, 2).isPositive()); + EXPECT_FALSE(Fraction(0, 1).isPositive()); +} + +TEST_F(FractionTest, IsNegative) { + EXPECT_TRUE(Fraction(-1, 2).isNegative()); + EXPECT_FALSE(Fraction(1, 2).isNegative()); + EXPECT_FALSE(Fraction(0, 1).isNegative()); +} + +// Stream Operation Tests +TEST_F(FractionTest, StreamOutput) { + std::ostringstream oss; + oss << Fraction(1, 2); + EXPECT_EQ(oss.str(), "1/2"); +} + +TEST_F(FractionTest, StreamInput) { + std::istringstream iss("3/4"); + Fraction f; + iss >> f; + EXPECT_EQ(f, Fraction(3, 4)); +} + +// Factory Function Tests +TEST_F(FractionTest, MakeFractionFromInt) { + auto f = makeFraction(5); + EXPECT_EQ(f, Fraction(5, 1)); +} + +TEST_F(FractionTest, MakeFractionFromDouble) { + auto f = makeFraction(0.5, 1000); + EXPECT_EQ(f, Fraction(1, 2)); +} + +// Edge Cases and Error Tests +TEST_F(FractionTest, ArithmeticOverflow) { + Fraction f1(std::numeric_limits::max(), 1); + Fraction f2(1, 1); + EXPECT_THROW(f1 + f2, FractionException); +} + +TEST_F(FractionTest, DivisionByZero) { + Fraction f1(1, 2); + Fraction f2(0, 1); + EXPECT_THROW(f1 / f2, FractionException); +} \ No newline at end of file diff --git a/tests/atom/algorithm/huffman.cpp b/tests/atom/algorithm/huffman.cpp index f88e2a5a..ac43df44 100644 --- a/tests/atom/algorithm/huffman.cpp +++ b/tests/atom/algorithm/huffman.cpp @@ -1,30 +1,178 @@ #include "atom/algorithm/huffman.hpp" #include -// 创建Huffman树测试 -TEST(HuffmanTest, CreateHuffmanTreeTest) { - std::unordered_map frequencies = { - {'a', 5}, {'b', 9}, {'c', 12}, {'d', 13}, {'e', 16}, {'f', 45}}; +using namespace atom::algorithm; - auto root = atom::algorithm::createHuffmanTree(frequencies); - ASSERT_EQ(root->frequency, 100); - ASSERT_EQ(root->left->data, 'f'); +class HuffmanTest : public ::testing::Test { +protected: + // Helper function to create a sample frequency map + static auto createSampleFrequencies() { + return std::unordered_map{ + {'a', 5}, {'b', 9}, {'c', 12}, {'d', 13}, {'e', 16}, {'f', 45}}; + } + + // Helper function to create a simple test tree + static auto createTestTree() { + auto root = std::make_shared('\0', 10); + root->left = std::make_shared('a', 4); + root->right = std::make_shared('b', 6); + return root; + } +}; + +// HuffmanNode Tests +TEST_F(HuffmanTest, NodeConstruction) { + HuffmanNode node('a', 5); + EXPECT_EQ(node.data, 'a'); + EXPECT_EQ(node.frequency, 5); + EXPECT_EQ(node.left, nullptr); + EXPECT_EQ(node.right, nullptr); +} + +// Tree Creation Tests +TEST_F(HuffmanTest, CreateHuffmanTreeEmpty) { + std::unordered_map emptyFreq; + EXPECT_THROW(createHuffmanTree(emptyFreq), HuffmanException); +} + +TEST_F(HuffmanTest, CreateHuffmanTreeSingleChar) { + std::unordered_map freq{{'a', 1}}; + auto root = createHuffmanTree(freq); + EXPECT_EQ(root->data, 'a'); + EXPECT_EQ(root->frequency, 1); } -// 压缩和解压缩文本测试 -TEST(HuffmanTest, CompressAndDecompressTextTest) { - std::string text = "abbcccddddeeeeeffffff"; - std::unordered_map frequencies = {{'a', 1}, {'b', 2}, {'c', 3}, - {'d', 4}, {'e', 5}, {'f', 6}}; +TEST_F(HuffmanTest, CreateHuffmanTreeMultipleChars) { + auto freq = createSampleFrequencies(); + auto root = createHuffmanTree(freq); + EXPECT_NE(root, nullptr); + EXPECT_GT(root->frequency, 0); +} - auto root = atom::algorithm::createHuffmanTree(frequencies); - std::unordered_map huffmanCodes; - atom::algorithm::generateHuffmanCodes(root.get(), "", huffmanCodes); +// Code Generation Tests +TEST_F(HuffmanTest, GenerateHuffmanCodesEmpty) { + std::unordered_map codes; + generateHuffmanCodes(nullptr, "", codes); + EXPECT_TRUE(codes.empty()); +} + +TEST_F(HuffmanTest, GenerateHuffmanCodesSimple) { + auto root = createTestTree(); + std::unordered_map codes; + generateHuffmanCodes(root.get(), "", codes); + EXPECT_EQ(codes['a'], "0"); + EXPECT_EQ(codes['b'], "1"); +} - std::string compressedText = - atom::algorithm::compressText(text, huffmanCodes); - std::string decompressedText = - atom::algorithm::decompressText(compressedText, root.get()); +// Compression Tests +TEST_F(HuffmanTest, CompressDataEmpty) { + std::vector emptyData; + std::unordered_map codes; + auto compressed = compressData(emptyData, codes); + EXPECT_TRUE(compressed.empty()); +} + +TEST_F(HuffmanTest, CompressDataSimple) { + std::vector data{'a', 'b', 'a'}; + std::unordered_map codes{{'a', "0"}, + {'b', "1"}}; + auto compressed = compressData(data, codes); + EXPECT_EQ(compressed, "010"); +} + +TEST_F(HuffmanTest, CompressDataInvalidCode) { + std::vector data{'x'}; + std::unordered_map codes{{'a', "0"}, + {'b', "1"}}; + EXPECT_THROW(compressData(data, codes), HuffmanException); +} + +// Decompression Tests +TEST_F(HuffmanTest, DecompressDataEmpty) { + auto root = createTestTree(); + auto decompressed = decompressData("", root.get()); + EXPECT_TRUE(decompressed.empty()); +} + +TEST_F(HuffmanTest, DecompressDataSimple) { + auto root = createTestTree(); + auto decompressed = decompressData("01", root.get()); + EXPECT_EQ(decompressed.size(), 2); + EXPECT_EQ(decompressed[0], 'a'); + EXPECT_EQ(decompressed[1], 'b'); +} - ASSERT_EQ(decompressedText, text); +TEST_F(HuffmanTest, DecompressDataInvalid) { + EXPECT_THROW(decompressData("01", nullptr), HuffmanException); } + +// Serialization Tests +TEST_F(HuffmanTest, SerializeTreeEmpty) { + EXPECT_TRUE(serializeTree(nullptr).empty()); +} + +TEST_F(HuffmanTest, SerializeTreeSimple) { + auto root = createTestTree(); + auto serialized = serializeTree(root.get()); + EXPECT_FALSE(serialized.empty()); +} + +// Deserialization Tests +TEST_F(HuffmanTest, DeserializeTreeEmpty) { + size_t index = 0; + EXPECT_THROW(deserializeTree("", index), HuffmanException); +} + +TEST_F(HuffmanTest, DeserializeTreeSimple) { + auto root = createTestTree(); + auto serialized = serializeTree(root.get()); + size_t index = 0; + auto deserialized = deserializeTree(serialized, index); + EXPECT_NE(deserialized, nullptr); +} + +// Integration Tests +TEST_F(HuffmanTest, FullEncodingDecodingCycle) { + // Original data + std::vector original{'h', 'e', 'l', 'l', 'o'}; + + // Create frequency map + std::unordered_map frequencies; + for (auto c : original) { + frequencies[c]++; + } + + // Create tree and generate codes + auto root = createHuffmanTree(frequencies); + std::unordered_map codes; + generateHuffmanCodes(root.get(), "", codes); + + // Compress + auto compressed = compressData(original, codes); + + // Decompress + auto decompressed = decompressData(compressed, root.get()); + + // Verify + EXPECT_EQ(original, decompressed); +} + +// Visualization Test +TEST_F(HuffmanTest, VisualizeTree) { + auto root = createTestTree(); + testing::internal::CaptureStdout(); + visualizeHuffmanTree(root.get()); + std::string output = testing::internal::GetCapturedStdout(); + EXPECT_FALSE(output.empty()); +} + +// Error Handling Tests +TEST_F(HuffmanTest, ExceptionMessages) { + try { + std::unordered_map emptyFreq; + createHuffmanTree(emptyFreq); + FAIL() << "Expected HuffmanException"; + } catch (const HuffmanException& e) { + EXPECT_NE(std::string(e.what()), ""); + } +} \ No newline at end of file diff --git a/tests/components/meta/any.cpp b/tests/components/meta/any.cpp index a78542d7..fa754677 100644 --- a/tests/components/meta/any.cpp +++ b/tests/components/meta/any.cpp @@ -1,161 +1,223 @@ -#include "atom/function/any.hpp" +// test_vany.hpp +#ifndef TEST_ATOM_META_VANY_HPP +#define TEST_ATOM_META_VANY_HPP #include +#include "atom/function/vany.hpp" +#include +#include + +namespace atom::meta::test { + +class AnyTest : public ::testing::Test { +protected: + struct LargeObject { + std::array data; + std::string name; + + LargeObject(const std::string& n = "test") : name(n) {} + bool operator==(const LargeObject& other) const { + return name == other.name; + } + }; + + struct SmallObject { + int value; + SmallObject(int v = 0) : value(v) {} + bool operator==(const SmallObject& other) const { + return value == other.value; + } + }; +}; + +// Construction Tests +TEST_F(AnyTest, DefaultConstruction) { + Any any; + EXPECT_FALSE(any.hasValue()); +} + +TEST_F(AnyTest, SmallObjectConstruction) { + SmallObject obj(42); + Any any(obj); + EXPECT_TRUE(any.hasValue()); + EXPECT_TRUE(any.is()); + EXPECT_EQ(any.cast(), obj); +} + +TEST_F(AnyTest, LargeObjectConstruction) { + LargeObject obj("test"); + Any any(obj); + EXPECT_TRUE(any.hasValue()); + EXPECT_TRUE(any.is()); + EXPECT_EQ(any.cast(), obj); +} + +// Copy Tests +/* +TEST_F(AnyTest, CopyConstructionSmall) { + Any original(SmallObject(42)); + Any copy(original); + EXPECT_TRUE(copy.hasValue()); + EXPECT_TRUE(copy.is()); + EXPECT_EQ(copy.cast(), SmallObject(42)); +} -using namespace atom::meta; - -const int INITIAL_VALUE = 42; -const int UPDATED_VALUE = 100; -const int SECOND_VALUE = 200; +TEST_F(AnyTest, CopyConstructionLarge) { + Any original(LargeObject("test")); + Any copy(original); + EXPECT_TRUE(copy.hasValue()); + EXPECT_TRUE(copy.is()); + EXPECT_EQ(copy.cast(), LargeObject("test")); +} +*/ -class BoxedValueTest : public ::testing::Test {}; -TEST_F(BoxedValueTest, DefaultConstructor) { - BoxedValue boxedValue; - EXPECT_TRUE(boxedValue.isUndef()); - EXPECT_TRUE(boxedValue.isNull()); +// Move Tests +TEST_F(AnyTest, MoveConstructionSmall) { + Any original(SmallObject(42)); + Any moved(std::move(original)); + EXPECT_TRUE(moved.hasValue()); + EXPECT_FALSE(original.hasValue()); + EXPECT_EQ(moved.cast(), SmallObject(42)); } -TEST_F(BoxedValueTest, ConstructWithValue) { - BoxedValue boxedValue(INITIAL_VALUE); - EXPECT_FALSE(boxedValue.isUndef()); - EXPECT_TRUE(boxedValue.canCast()); - EXPECT_EQ(boxedValue.tryCast().value(), INITIAL_VALUE); +TEST_F(AnyTest, MoveConstructionLarge) { + Any original(LargeObject("test")); + Any moved(std::move(original)); + EXPECT_TRUE(moved.hasValue()); + EXPECT_FALSE(original.hasValue()); + EXPECT_EQ(moved.cast(), LargeObject("test")); } -TEST_F(BoxedValueTest, ConstructWithConstValue) { - const int VALUE = INITIAL_VALUE; - BoxedValue boxedValue = VALUE; - // TODO: FIX ME - Now we can't detect constant value - // EXPECT_TRUE(boxedValue.isConst()); - EXPECT_TRUE(boxedValue.isReadonly()); - EXPECT_EQ(boxedValue.tryCast().value(), INITIAL_VALUE); +// Assignment Tests +/* +TEST_F(AnyTest, CopyAssignment) { + Any original(SmallObject(42)); + Any copy; + copy = original; + EXPECT_TRUE(copy.hasValue()); + EXPECT_EQ(copy.cast(), SmallObject(42)); } +*/ -TEST_F(BoxedValueTest, CopyConstructor) { - BoxedValue boxedValue1(INITIAL_VALUE); - BoxedValue boxedValue2 = boxedValue1; - EXPECT_EQ(boxedValue2.tryCast().value(), INITIAL_VALUE); - boxedValue1 = UPDATED_VALUE; - EXPECT_EQ(boxedValue2.tryCast().value(), - INITIAL_VALUE); // Copy should not affect original -} -TEST_F(BoxedValueTest, MoveConstructor) { - BoxedValue boxedValue1(INITIAL_VALUE); // 构造默认对象 - BoxedValue boxedValue2 = std::move(boxedValue1); // 移动构造 - EXPECT_EQ(boxedValue2.tryCast().value(), - INITIAL_VALUE); // 验证移动对象的值 - EXPECT_TRUE(boxedValue1.isUndef()); // 原对象应被置于无效状态 +TEST_F(AnyTest, MoveAssignment) { + Any original(SmallObject(42)); + Any target; + target = std::move(original); + EXPECT_TRUE(target.hasValue()); + EXPECT_FALSE(original.hasValue()); } -TEST_F(BoxedValueTest, CopyAssignment) { - BoxedValue boxedValue1(INITIAL_VALUE); // 创建一个 BoxedValue - BoxedValue boxedValue2; // 默认构造 - boxedValue2 = boxedValue1; // 拷贝赋值 - EXPECT_EQ(boxedValue2.tryCast().value(), INITIAL_VALUE); - boxedValue1 = - makeBoxedValue(UPDATED_VALUE); // 使用 makeBoxedValue 来避免直接赋值 - EXPECT_EQ(boxedValue2.tryCast().value(), - INITIAL_VALUE); // boxedValue2 不应该受影响 +// Type Safety Tests +TEST_F(AnyTest, TypeChecking) { + Any any(42); + EXPECT_TRUE(any.is()); + EXPECT_FALSE(any.is()); + EXPECT_FALSE(any.is()); } -TEST_F(BoxedValueTest, MoveAssignment) { - BoxedValue boxedValue1(INITIAL_VALUE); - BoxedValue boxedValue2; - boxedValue2 = std::move(boxedValue1); - EXPECT_TRUE(boxedValue2.canCast()); - EXPECT_EQ(boxedValue2.tryCast().value(), INITIAL_VALUE); - EXPECT_TRUE( - boxedValue1 - .isUndef()); // Original should be in a valid but undefined state +TEST_F(AnyTest, BadCast) { + Any any(42); + EXPECT_THROW(any.cast(), std::bad_cast); } -TEST_F(BoxedValueTest, Swap) { - BoxedValue boxedValue1(INITIAL_VALUE); - BoxedValue boxedValue2(UPDATED_VALUE); - boxedValue1.swap(boxedValue2); - EXPECT_EQ(boxedValue1.tryCast().value(), UPDATED_VALUE); - EXPECT_EQ(boxedValue2.tryCast().value(), INITIAL_VALUE); +// String Conversion Tests +TEST_F(AnyTest, ToStringTest) { + Any empty; + EXPECT_EQ(empty.toString(), "Empty Any"); + + Any intAny(42); + EXPECT_EQ(intAny.toString(), "42"); + + Any strAny(std::string("test")); + EXPECT_EQ(strAny.toString(), "test"); } -TEST_F(BoxedValueTest, CheckAttributes) { - BoxedValue boxedValue(INITIAL_VALUE); - boxedValue.setAttr("key", BoxedValue(UPDATED_VALUE)); - EXPECT_TRUE(boxedValue.hasAttr("key")); - EXPECT_EQ(boxedValue.getAttr("key").tryCast().value(), UPDATED_VALUE); - boxedValue.removeAttr("key"); - EXPECT_FALSE(boxedValue.hasAttr("key")); +// Iterator Support Tests +TEST_F(AnyTest, ForeachVector) { + std::vector vec{1, 2, 3}; + Any any(vec); + std::vector result; + + any.foreach([&result](const Any& item) { + result.push_back(item.cast()); + }); + + EXPECT_EQ(result, vec); } -TEST_F(BoxedValueTest, ListAttributes) { - BoxedValue boxedValue(INITIAL_VALUE); - boxedValue.setAttr("key1", BoxedValue(UPDATED_VALUE)); - boxedValue.setAttr("key2", BoxedValue(SECOND_VALUE)); - auto attrs = boxedValue.listAttrs(); - EXPECT_EQ(attrs.size(), 2); - EXPECT_NE(std::find(attrs.begin(), attrs.end(), "key1"), attrs.end()); - EXPECT_NE(std::find(attrs.begin(), attrs.end(), "key2"), attrs.end()); +TEST_F(AnyTest, ForeachNonIterable) { + Any any(42); + EXPECT_THROW(any.foreach([](const Any&) {}), std::invalid_argument); } -TEST_F(BoxedValueTest, TryCastValid) { - BoxedValue boxedValue(INITIAL_VALUE); - auto result = boxedValue.tryCast(); - ASSERT_TRUE(result.has_value()); - EXPECT_EQ(result.value(), INITIAL_VALUE); +// Reset and Value Management Tests +TEST_F(AnyTest, ResetTest) { + Any any(42); + EXPECT_TRUE(any.hasValue()); + any.reset(); + EXPECT_FALSE(any.hasValue()); } -TEST_F(BoxedValueTest, TryCastInvalid) { - BoxedValue boxedValue(INITIAL_VALUE); - auto result = boxedValue.tryCast(); - EXPECT_FALSE(result.has_value()); +/* +TEST_F(AnyTest, SwapTest) { + Any a1(42); + Any a2(std::string("test")); + + a1.swap(a2); + + EXPECT_TRUE(a1.is()); + EXPECT_TRUE(a2.is()); + EXPECT_EQ(a1.cast(), "test"); + EXPECT_EQ(a2.cast(), 42); } +*/ -TEST_F(BoxedValueTest, CanCast) { - BoxedValue boxedValue(INITIAL_VALUE); - EXPECT_TRUE(boxedValue.canCast()); - EXPECT_FALSE(boxedValue.canCast()); + +// Memory Leak Tests +TEST_F(AnyTest, NoMemoryLeakOnException) { + struct ThrowOnCopy { + ThrowOnCopy() = default; + ThrowOnCopy(const ThrowOnCopy&) { throw std::runtime_error("copy error"); } + }; + + Any original(ThrowOnCopy{}); + EXPECT_THROW(Any copy(original), std::runtime_error); } -TEST_F(BoxedValueTest, DebugString) { - BoxedValue boxedValue(INITIAL_VALUE); - EXPECT_EQ(boxedValue.debugString(), "BoxedValue: 42"); +// Invoke Tests +TEST_F(AnyTest, InvokeTest) { + int value = 42; + Any any(value); + bool invoked = false; + + any.invoke([&invoked](const void* ptr) { + invoked = (*static_cast(ptr) == 42); + }); + + EXPECT_TRUE(invoked); } -TEST_F(BoxedValueTest, VoidTypeCheck) { - BoxedValue boxedValue; - EXPECT_TRUE(boxedValue.isUndef()); - EXPECT_FALSE(boxedValue.canCast()); - EXPECT_TRUE(boxedValue.isNull()); +TEST_F(AnyTest, InvokeEmpty) { + Any any; + EXPECT_THROW(any.invoke([](const void*) {}), std::invalid_argument); } -// TODO: FIX ME - Now we can't detect constant value -/* -TEST_F(BoxedValueTest, ConstDataPtrCheck) { - const int value = INITIAL_VALUE; - BoxedValue boxedValue = constVar(value); - EXPECT_TRUE(boxedValue.isConstDataPtr()); - EXPECT_EQ(*static_cast(boxedValue.getPtr()), INITIAL_VALUE); +// Type Info Tests +TEST_F(AnyTest, TypeInfoTest) { + Any any(42); + EXPECT_EQ(any.type(), typeid(int)); + + any = std::string("test"); + EXPECT_EQ(any.type(), typeid(std::string)); } -*/ -TEST_F(BoxedValueTest, ReadonlyCheck) { - int value = INITIAL_VALUE; - BoxedValue boxedValue = makeBoxedValue(value, false, true); - EXPECT_TRUE(boxedValue.isReadonly()); - boxedValue.resetReturnValue(); - EXPECT_TRUE(boxedValue.isReadonly()); +TEST_F(AnyTest, TypeInfoEmptyThrows) { + Any any; + EXPECT_THROW(any.type(), std::bad_typeid); } -/* +} // namespace atom::meta::test -*/ -TEST_F(BoxedValueTest, ReferenceHandling) { - int value = INITIAL_VALUE; - BoxedValue boxedValue = makeBoxedValue(std::ref(value)); - // TODO: FIX ME - Now we can't detect reference - // EXPECT_TRUE(boxedValue.isRef()); - EXPECT_EQ(boxedValue.tryCast().value(), INITIAL_VALUE); - value = UPDATED_VALUE; - EXPECT_EQ(boxedValue.tryCast().value(), UPDATED_VALUE); -} +#endif // TEST_ATOM_META_VANY_HPP \ No newline at end of file diff --git a/tests/components/meta/anymeta.cpp b/tests/components/meta/anymeta.cpp index 7bb59b5c..87171dba 100644 --- a/tests/components/meta/anymeta.cpp +++ b/tests/components/meta/anymeta.cpp @@ -1,246 +1,168 @@ -#include "gtest/gtest.h" +// test_anymeta.hpp +#include +#include "atom/function/anymeta.hpp" +#include -#include "atom/function/anymeta.hpp" // 包含我们之前定义的 `TypeMetadata` 和 `TypeRegistry` +namespace atom::meta::test { -using namespace atom::meta; - -// 测试类 +// Test helper class class TestClass { public: - int value = 0; - + int value{0}; + std::string name; + TestClass() = default; - - explicit TestClass(int v) : value(v) {} - + TestClass(int v) : value(v) {} + int getValue() const { return value; } - - void setValue(int v) { - // std::cout << "Setting value to " << v << std::endl; - value = v; - } - - void printValue() const { - // std::cout << "Value: " << value << std::endl; - } - - static void staticPrint() { - // std::cout << "Static print" << std::endl;// - } + void setValue(int v) { value = v; } + std::string getName() const { return name; } }; -// 注册类型信息 -class TestClassRegistrar { -public: - static void registerType() { - TypeMetadata metadata; - - // 注册构造函数 - metadata.addConstructor( - "TestClass", [](std::vector args) -> BoxedValue { - if (args.empty()) { - return BoxedValue(TestClass{}); // 默认构造函数 - } else if (args.size() == 1) { - if (auto value = args[0].tryCast(); - value.has_value()) { - return BoxedValue(TestClass{*value}); - } - } - THROW_INVALID_ARGUMENT("Invalid arguments for constructor"); - }); - - // 注册方法 - metadata.addMethod( - "getValue", [](std::vector args) -> BoxedValue { - auto& obj = args[0]; - auto value = obj.tryCast()->getValue(); - // std::cout << "Value: " << value << std::endl; - return BoxedValue(value); - }); - - metadata.addMethod( - "setValue", [](std::vector args) -> BoxedValue { - auto& obj = args[0]; - if (auto value = args[1].tryCast(); value.has_value()) { - obj.tryCast()->setValue(*value); - return BoxedValue{}; - } - THROW_INVALID_ARGUMENT("Invalid argument for setValue"); +class TypeMetadataTest : public ::testing::Test { +protected: + TypeMetadata metadata; + + void SetUp() override { + // Register a test method + metadata.addMethod("testMethod", + [](std::vector args) -> BoxedValue { + return BoxedValue(42); }); - - metadata.addMethod("printValue", - [](std::vector args) -> BoxedValue { - args[0].tryCast()->printValue(); - return BoxedValue{}; - }); - - // 注册属性 - metadata.addProperty( - "value", + + // Register a test property + metadata.addProperty("testProperty", [](const BoxedValue& obj) -> BoxedValue { - return BoxedValue(obj.tryCast()->getValue()); + return BoxedValue(123); }, [](BoxedValue& obj, const BoxedValue& value) { - // std::cout << "Setting value to " << - // value.getTypeInfo().name() - // << ": " << value.tryCast().value() << - // std::endl; - if (auto v = value.tryCast(); v.has_value()) { - obj.tryCast()->setValue(*v); - // std::cout << "Value set to " << *v << std::endl; - } else { - THROW_INVALID_ARGUMENT("Invalid type for value property"); - } + // Setter implementation + }); + + // Register a test constructor + metadata.addConstructor("TestClass", + [](std::vector args) -> BoxedValue { + return BoxedValue(TestClass{}); }); - - // 注册事件 - metadata.addEvent("onValueChanged"); - - TypeRegistry::instance().registerType("TestClass", std::move(metadata)); } }; -// 测试套件 -class TypeRegistryTest : public ::testing::Test { -protected: - void SetUp() override { TestClassRegistrar::registerType(); } -}; - -// 测试:类型注册和构造函数 -TEST_F(TypeRegistryTest, TypeRegistrationAndConstructor) { - auto metadata = TypeRegistry::instance().getMetadata("TestClass"); - ASSERT_TRUE(metadata.has_value()); - - // 测试默认构造函数 - BoxedValue obj = createInstance("TestClass", {}); - ASSERT_TRUE(obj.canCast()); - EXPECT_EQ(obj.tryCast()->getValue(), 0); - - // 测试带参数的构造函数 - BoxedValue objWithArg = createInstance("TestClass", {BoxedValue(42)}); - ASSERT_TRUE(objWithArg.canCast()); - EXPECT_EQ(objWithArg.tryCast()->getValue(), 42); - - // 边缘情况:无效参数的构造函数 - EXPECT_THROW(createInstance("TestClass", {BoxedValue("invalid")}), - std::exception); +TEST_F(TypeMetadataTest, AddAndGetMethod) { + auto methods = metadata.getMethods("testMethod"); + ASSERT_TRUE(methods.has_value()); + ASSERT_EQ((*methods)->size(), 1); + + auto result = (*methods)->front()({}); + EXPECT_EQ(result.tryCast(), 42); } -// TODO: FIX ME - 测试:方法调用 -/* -TEST_F(TypeRegistryTest, MethodCall) { - BoxedValue obj = createInstance("TestClass", {BoxedValue(10)}); - std::cout << "obj: " << obj.getTypeInfo().name() << std::endl; - - // 调用 getValue 方法 - BoxedValue result = callMethod(obj, "getValue", {}); - ASSERT_TRUE(result.canCast()); - EXPECT_EQ(result.tryCast(), 10); - - // 调用 setValue 方法 - callMethod(obj, "setValue", {BoxedValue(20)}); - result = callMethod(obj, "getValue", {}); - EXPECT_EQ(result.tryCast(), 20); - - // 边缘情况:调用未注册的方法 - EXPECT_THROW(callMethod(obj, "nonexistentMethod", {}), std::exception); +TEST_F(TypeMetadataTest, AddAndGetProperty) { + auto property = metadata.getProperty("testProperty"); + ASSERT_TRUE(property.has_value()); + + BoxedValue obj(TestClass{}); + auto value = property->getter(obj); + EXPECT_EQ(value.tryCast(), 123); } -*/ - -// TODO: FIX ME - 测试:属性访问 -/* -TEST_F(TypeRegistryTest, PropertyAccess) { - BoxedValue obj = createInstance("TestClass", {BoxedValue(5)}); - // 获取属性值 - BoxedValue value = getProperty(obj, "value"); - ASSERT_TRUE(value.canCast()); - EXPECT_EQ(value.tryCast(), 5); - - // 设置属性值 - setProperty(obj, "value", BoxedValue(15)); - std::cout << "obj: " << obj.getTypeInfo().name() << std::endl; - value = getProperty(obj, "value"); - EXPECT_EQ(value.tryCast(), 15); - - // 边缘情况:获取未注册的属性 - EXPECT_THROW(getProperty(obj, "nonexistentProperty"), std::exception); - - // 边缘情况:设置无效类型的属性 - EXPECT_THROW(setProperty(obj, "value", BoxedValue("invalid")), - std::exception); +TEST_F(TypeMetadataTest, EventSystem) { + bool eventFired = false; + metadata.addEvent("testEvent", "Test event description"); + metadata.addEventListener("testEvent", + [&eventFired](BoxedValue& obj, const std::vector& args) { + eventFired = true; + }); + + BoxedValue obj(TestClass{}); + metadata.fireEvent(obj, "testEvent", {}); + EXPECT_TRUE(eventFired); } -*/ -// TODO: FIX ME - 测试:事件处理 -/* -TEST_F(TypeRegistryTest, EventHandling) { - BoxedValue obj = createInstance("TestClass", {BoxedValue(5)}); +class TypeRegistryTest : public ::testing::Test { +protected: + void SetUp() override { + TypeRegistry::instance().registerType("TestClass", TypeMetadata{}); + } + + void TearDown() override { + // Clean up registered types if needed + } +}; +TEST_F(TypeRegistryTest, RegisterAndRetrieveType) { auto metadata = TypeRegistry::instance().getMetadata("TestClass"); ASSERT_TRUE(metadata.has_value()); - - // 添加事件监听器 - bool eventTriggered = false; - metadata->addEventListener( - "onValueChanged", [&](BoxedValue& obj, const std::vector&) { - eventTriggered = true; - }); - - // 触发事件 - fireEvent(obj, "onValueChanged", {}); - EXPECT_TRUE(eventTriggered); - - // 边缘情况:触发不存在的事件 - EXPECT_NO_THROW(fireEvent(obj, "nonexistentEvent", {})); } -*/ -// 测试:构造函数边缘情况 -TEST_F(TypeRegistryTest, ConstructorEdgeCases) { - // 空参数列表的构造函数应该生成默认对象 - BoxedValue defaultObj = createInstance("TestClass", {}); - ASSERT_TRUE(defaultObj.canCast()); - EXPECT_EQ(defaultObj.tryCast()->getValue(), 0); - - // 边缘情况:传递多个无效参数 - EXPECT_THROW(createInstance("TestClass", {BoxedValue(1), BoxedValue(2)}), - std::exception); +TEST(TypeRegistrarTest, RegisterType) { + TypeRegistrar::registerType("TestClass"); + + auto metadata = TypeRegistry::instance().getMetadata("TestClass"); + ASSERT_TRUE(metadata.has_value()); + + // Test registered constructor + auto constructor = metadata->getConstructor("TestClass"); + ASSERT_TRUE(constructor.has_value()); + + auto instance = (*constructor)({}); + ASSERT_TRUE(instance.isType()); } -// 测试:多线程访问 -TEST_F(TypeRegistryTest, MultithreadedAccess) { - BoxedValue obj = createInstance("TestClass", {BoxedValue(5)}); - - // 在多个线程中读取属性值 - std::vector threads; - threads.reserve(10); - for (int i = 0; i < 10; ++i) { - threads.emplace_back([&]() { - for (int j = 0; j < 100; ++j) { - BoxedValue value = getProperty(obj, "value"); - EXPECT_TRUE(value.canCast()); - } - }); - } +TEST(HelperFunctionsTest, CallMethod) { + TypeRegistrar::registerType("TestClass"); + BoxedValue obj(TestClass{}); + + // Test print method + EXPECT_NO_THROW(callMethod(obj, "print", {BoxedValue(42)})); +} - // 在多个线程中设置属性值 - for (int i = 0; i < 10; ++i) { - threads.emplace_back([&]() { - for (int j = 0; j < 100; ++j) { - setProperty(obj, "value", BoxedValue(10 + j)); - } +TEST(ThreadSafetyTest, ConcurrentTypeRegistration) { + std::vector threads; + for(int i = 0; i < 10; i++) { + threads.emplace_back([i]() { + std::string typeName = "Type" + std::to_string(i); + TypeRegistrar::registerType(typeName); }); } - - // 等待所有线程完成 - for (auto& thread : threads) { + + for(auto& thread : threads) { thread.join(); } + + // Verify all types were registered + for(int i = 0; i < 10; i++) { + std::string typeName = "Type" + std::to_string(i); + EXPECT_TRUE(TypeRegistry::instance().getMetadata(typeName).has_value()); + } +} - // 检查最终属性值 - BoxedValue finalValue = getProperty(obj, "value"); - ASSERT_TRUE(finalValue.canCast()); - EXPECT_GE(finalValue.tryCast(), - 5); // 最终值至少应该是设置过的最大值之一 +TEST(ErrorHandlingTest, MethodNotFound) { + TypeRegistrar::registerType("TestClass"); + BoxedValue obj(TestClass{}); + + EXPECT_THROW(callMethod(obj, "nonexistentMethod", {}), atom::error::NotFound); } + +TEST(EventPriorityTest, EventPriorityOrder) { + TypeMetadata metadata; + std::vector executionOrder; + + metadata.addEvent("testEvent"); + metadata.addEventListener("testEvent", + [&](BoxedValue&, const std::vector&) { + executionOrder.push_back(1); + }, 1); + metadata.addEventListener("testEvent", + [&](BoxedValue&, const std::vector&) { + executionOrder.push_back(2); + }, 2); + + BoxedValue obj(TestClass{}); + metadata.fireEvent(obj, "testEvent", {}); + + ASSERT_EQ(executionOrder.size(), 2); + EXPECT_EQ(executionOrder[0], 2); // Higher priority executed first + EXPECT_EQ(executionOrder[1], 1); +} + +} // namespace atom::meta::test \ No newline at end of file diff --git a/tests/components/meta/enum.cpp b/tests/components/meta/enum.cpp index de66a5e2..60a35121 100644 --- a/tests/components/meta/enum.cpp +++ b/tests/components/meta/enum.cpp @@ -1,151 +1,197 @@ -#include -#include +#ifndef TEST_ATOM_META_ENUM_HPP +#define TEST_ATOM_META_ENUM_HPP #include "atom/function/enum.hpp" -using namespace atom::meta; +#include +#include +using namespace std::literals::string_view_literals; + +// Test enum definitions enum class Color { Red, Green, Blue }; -enum class Permissions { Read = 1, Write = 2, Execute = 4 }; +enum class Flags { None = 0, Flag1 = 1, Flag2 = 2, Flag3 = 4 }; + +// Specializations for test enums template <> -struct EnumTraits { +struct atom::meta::EnumTraits { static constexpr std::array values = {Color::Red, Color::Green, Color::Blue}; - static constexpr std::array names = {"Red", "Green", - "Blue"}; + static constexpr std::array names = { + "Red"sv, "Green"sv, "Blue"sv}; + static constexpr std::array descriptions = { + "Red color"sv, "Green color"sv, "Blue color"sv}; }; template <> -struct EnumAliasTraits { - static constexpr std::array aliases = {"R", "G", "B"}; +struct atom::meta::EnumTraits { + static constexpr std::array values = {Flags::None, Flags::Flag1, + Flags::Flag2, Flags::Flag3}; + static constexpr std::array names = { + "None"sv, "Flag1"sv, "Flag2"sv, "Flag3"sv}; + static constexpr std::array descriptions = { + "No flags"sv, "First flag"sv, "Second flag"sv, "Third flag"sv}; }; template <> -struct EnumTraits { - static constexpr std::array values = { - Permissions::Read, Permissions::Write, Permissions::Execute}; - static constexpr std::array names = {"Read", "Write", - "Execute"}; +struct atom::meta::EnumAliasTraits { + static constexpr std::array aliases = {"R"sv, "G"sv, "B"sv}; }; -// 枚举到字符串测试 -TEST(EnumTest, EnumToString) { + +namespace atom::meta::test { + +class EnumTest : public ::testing::Test { +protected: + void SetUp() override {} + void TearDown() override {} +}; + +// Basic enum operations tests +TEST_F(EnumTest, EnumToString) { EXPECT_EQ(enum_name(Color::Red), "Red"); EXPECT_EQ(enum_name(Color::Green), "Green"); EXPECT_EQ(enum_name(Color::Blue), "Blue"); - - // 边界情况:未定义的枚举值(在当前代码中不会发生,因为只有定义的枚举值会被转换) - // EXPECT_EQ(enum_name(static_cast(-1)), ""); // Uncomment if needed - // for additional boundary checks } -// 字符串到枚举测试 -TEST(EnumTest, StringToEnum) { - EXPECT_EQ(enum_cast("Red"), Color::Red); - EXPECT_EQ(enum_cast("Green"), Color::Green); - EXPECT_EQ(enum_cast("Blue"), Color::Blue); +TEST_F(EnumTest, StringToEnum) { + auto red = enum_cast("Red"); + EXPECT_TRUE(red.has_value()); + EXPECT_EQ(red.value(), Color::Red); - // 边界情况:无效的字符串 - EXPECT_EQ(enum_cast("Purple"), std::nullopt); + auto invalid = enum_cast("Invalid"); + EXPECT_FALSE(invalid.has_value()); } -// 枚举值到整数测试 -TEST(EnumTest, EnumToInteger) { - EXPECT_EQ(enum_to_integer(Color::Red), 0); - EXPECT_EQ(enum_to_integer(Color::Green), 1); - EXPECT_EQ(enum_to_integer(Color::Blue), 2); +TEST_F(EnumTest, EnumToInteger) { + EXPECT_EQ(enum_to_integer(Flags::None), 0); + EXPECT_EQ(enum_to_integer(Flags::Flag1), 1); + EXPECT_EQ(enum_to_integer(Flags::Flag2), 2); } -// 整数到枚举值测试 -TEST(EnumTest, IntegerToEnum) { - EXPECT_EQ(integer_to_enum(0), Color::Red); - EXPECT_EQ(integer_to_enum(1), Color::Green); - EXPECT_EQ(integer_to_enum(2), Color::Blue); - - // 边界情况:无效的整数 - EXPECT_EQ(integer_to_enum(3), std::nullopt); - EXPECT_EQ(integer_to_enum(-1), std::nullopt); +TEST_F(EnumTest, IntegerToEnum) { + auto flag1 = integer_to_enum(1); + EXPECT_TRUE(flag1.has_value()); + EXPECT_EQ(flag1.value(), Flags::Flag1); } -// 检查枚举值是否有效 -TEST(EnumTest, EnumContains) { +// Enum validation tests +TEST_F(EnumTest, EnumContains) { EXPECT_TRUE(enum_contains(Color::Red)); EXPECT_TRUE(enum_contains(Color::Green)); EXPECT_TRUE(enum_contains(Color::Blue)); - - // 边界情况:无效的枚举值 - EXPECT_FALSE(enum_contains(static_cast(-1))); -} - -// 枚举别名测试 -TEST(EnumTest, EnumAlias) { - EXPECT_EQ(enum_cast_with_alias("R"), Color::Red); - EXPECT_EQ(enum_cast_with_alias("G"), Color::Green); - EXPECT_EQ(enum_cast_with_alias("B"), Color::Blue); - - // 边界情况:无效的别名 - EXPECT_EQ(enum_cast_with_alias("X"), std::nullopt); } -// 模糊匹配测试 -TEST(EnumTest, EnumCastFuzzy) { - EXPECT_EQ(enum_cast_fuzzy("Red"), Color::Red); - EXPECT_EQ(enum_cast_fuzzy("Gre"), Color::Green); - EXPECT_EQ(enum_cast_fuzzy("Blu"), Color::Blue); - - // 边界情况:无效的模糊匹配 - EXPECT_EQ(enum_cast_fuzzy("Purple"), std::nullopt); +TEST_F(EnumTest, EnumEntries) { + auto entries = enum_entries(); + EXPECT_EQ(entries.size(), 3); + EXPECT_EQ(entries[0].first, Color::Red); + EXPECT_EQ(entries[0].second, "Red"); } -// 位运算测试 -TEST(EnumTest, EnumBitwiseOperations) { - Permissions p = Permissions::Read | Permissions::Write; - EXPECT_EQ(enum_to_integer(p), 3); // 1 | 2 = 3 +// Bitwise operation tests +TEST_F(EnumTest, BitwiseOperations) { + Flags f1 = Flags::Flag1; + Flags f2 = Flags::Flag2; - p |= Permissions::Execute; - EXPECT_EQ(enum_to_integer(p), 7); // 3 | 4 = 7 + auto combined = f1 | f2; + EXPECT_EQ(enum_to_integer(combined), 3); - p &= Permissions::Write; - EXPECT_EQ(enum_to_integer(p), 2); // 7 & 2 = 2 + auto intersection = combined & f1; + EXPECT_EQ(intersection, f1); - p ^= Permissions::Read; - EXPECT_EQ(enum_to_integer(p), 3); // 2 ^ 1 = 3 + auto exclusive = f1 ^ f2; + EXPECT_EQ(enum_to_integer(exclusive), 3); - p = ~Permissions::Execute; - EXPECT_NE( - enum_to_integer(p), - enum_to_integer(Permissions::Execute)); // ~4 should not be equal to 4 + auto complement = ~f1; + EXPECT_NE(complement, f1); } -// 枚举值根据名称排序测试 -TEST(EnumTest, EnumSortedByName) { +// Sorting tests +TEST_F(EnumTest, SortByName) { auto sorted = enum_sorted_by_name(); EXPECT_EQ(sorted[0].second, "Blue"); EXPECT_EQ(sorted[1].second, "Green"); EXPECT_EQ(sorted[2].second, "Red"); } -// 枚举值根据整数值排序测试 -TEST(EnumTest, EnumSortedByValue) { - auto sorted = enum_sorted_by_value(); - EXPECT_EQ(sorted[0].second, "Read"); - EXPECT_EQ(sorted[1].second, "Write"); - EXPECT_EQ(sorted[2].second, "Execute"); +TEST_F(EnumTest, SortByValue) { + auto sorted = enum_sorted_by_value(); + EXPECT_EQ(sorted[0].first, Flags::None); + EXPECT_EQ(sorted[1].first, Flags::Flag1); + EXPECT_EQ(sorted[2].first, Flags::Flag2); +} + +// Fuzzy matching tests +TEST_F(EnumTest, FuzzyMatch) { + auto red = enum_cast_fuzzy("Re"); + EXPECT_TRUE(red.has_value()); + EXPECT_EQ(red.value(), Color::Red); } -// 检查整数值是否在枚举范围内 -TEST(EnumTest, IntegerInEnumRange) { - EXPECT_TRUE(integer_in_enum_range(1)); // Read - EXPECT_TRUE(integer_in_enum_range(2)); // Write - EXPECT_TRUE(integer_in_enum_range(4)); // Execute +// Range checking tests +TEST_F(EnumTest, RangeCheck) { + EXPECT_TRUE(integer_in_enum_range(1)); + EXPECT_FALSE(integer_in_enum_range(8)); - // 边界情况:无效的整数值 - EXPECT_FALSE(integer_in_enum_range(3)); - EXPECT_FALSE(integer_in_enum_range(0)); + EXPECT_TRUE(enum_in_range(Color::Green, Color::Red, Color::Blue)); + EXPECT_TRUE(enum_in_range(Color::Red, Color::Red, Color::Blue)); + EXPECT_TRUE(enum_in_range(Color::Blue, Color::Red, Color::Blue)); } -// 枚举的默认值测试 -TEST(EnumTest, EnumDefault) { +// Alias tests +TEST_F(EnumTest, EnumAliases) { + auto red = enum_cast_with_alias("R"); + EXPECT_TRUE(red.has_value()); + EXPECT_EQ(red.value(), Color::Red); +} + +// Description tests +TEST_F(EnumTest, EnumDescriptions) { + EXPECT_EQ(enum_description(Color::Red), "Red color"); + EXPECT_EQ(enum_description(Color::Green), "Green color"); + EXPECT_EQ(enum_description(Color::Blue), "Blue color"); +} + +// Serialization tests +TEST_F(EnumTest, Serialization) { + auto serialized = serialize_enum(Color::Red); + EXPECT_EQ(serialized, "Red"); + + auto deserialized = deserialize_enum(serialized); + EXPECT_TRUE(deserialized.has_value()); + EXPECT_EQ(deserialized.value(), Color::Red); +} + +// Bitmask tests +TEST_F(EnumTest, Bitmasks) { + auto mask = enum_bitmask(Flags::Flag1); + EXPECT_EQ(mask, 1); + + auto flag = bitmask_to_enum(1); + EXPECT_TRUE(flag.has_value()); + EXPECT_EQ(flag.value(), Flags::Flag1); +} + +// Default value tests +TEST_F(EnumTest, DefaultValue) { EXPECT_EQ(enum_default(), Color::Red); - EXPECT_EQ(enum_default(), Permissions::Read); + EXPECT_EQ(enum_default(), Flags::None); +} + +// Compound operations tests +TEST_F(EnumTest, CompoundOperations) { + Flags f = Flags::Flag1; + f |= Flags::Flag2; + EXPECT_EQ(enum_to_integer(f), 3); + + f &= Flags::Flag1; + EXPECT_EQ(f, Flags::Flag1); + + f ^= Flags::Flag2; + EXPECT_EQ(enum_to_integer(f), 3); } + +} // namespace atom::meta::test + +#endif // TEST_ATOM_META_ENUM_HPP \ No newline at end of file diff --git a/tests/components/meta/field_count.cpp b/tests/components/meta/field_count.cpp index a3ddf0e8..1e9ebf2a 100644 --- a/tests/components/meta/field_count.cpp +++ b/tests/components/meta/field_count.cpp @@ -1,74 +1,180 @@ #include + #include "atom/function/field_count.hpp" -using namespace atom::meta; +namespace atom::meta::test { + +// Test helper types +struct Empty {}; + +struct OneField { + int x; +}; + +struct TwoFields { + int x; + double y; +}; -// 测试结构体 -struct SimpleStruct { - int a; - double b; +struct ThreeFields { + int x; + double y; + char z; }; struct NestedStruct { - int a; - SimpleStruct b; - float c; + int x; + TwoFields nested; + double z; +}; + +struct WithArray { + int arr[3]; + double x; +}; + +struct WithNestedArray { + int x; + int arr[2][3]; + double y; }; -struct ArrayStruct { - int a[3]; - double b; +class NonAggregate { + int x; +public: + NonAggregate() : x(0) {} }; -struct ComplexStruct { - int a; - int b[2]; - NestedStruct c; +struct DerivedEmpty : Empty { + int x; }; -TEST(FieldCountTest, SimpleStructTest) { - constexpr auto COUNT = fieldCountOf(); - EXPECT_EQ(COUNT, 2); +struct ComplexNested { + TwoFields a; + ThreeFields b; + Empty c; +}; + +class FieldCountTest : public ::testing::Test { +protected: + void SetUp() override {} + void TearDown() override {} +}; + +// Basic field counting tests +TEST_F(FieldCountTest, EmptyStructHasZeroFields) { + constexpr auto count = fieldCountOf(); + EXPECT_EQ(count, 0); } -TEST(FieldCountTest, NestedStructTest) { - constexpr auto COUNT = fieldCountOf(); - EXPECT_EQ(COUNT, 3); +TEST_F(FieldCountTest, BasicStructFieldCounts) { + constexpr auto one = fieldCountOf(); + constexpr auto two = fieldCountOf(); + constexpr auto three = fieldCountOf(); + + EXPECT_EQ(one, 1); + EXPECT_EQ(two, 2); + EXPECT_EQ(three, 3); } -TEST(FieldCountTest, ArrayStructTest) { - constexpr auto COUNT = fieldCountOf(); - EXPECT_EQ(COUNT, 4); +// Nested struct tests +TEST_F(FieldCountTest, NestedStructFieldCount) { + constexpr auto count = fieldCountOf(); + EXPECT_EQ(count, 3); // x, nested, z } -TEST(FieldCountTest, ComplexStructTest) { - constexpr auto COUNT = fieldCountOf(); - EXPECT_EQ(COUNT, 4); +TEST_F(FieldCountTest, ComplexNestedStructFieldCount) { + constexpr auto count = fieldCountOf(); + EXPECT_EQ(count, 3); // a, b, c } -TEST(FieldCountTest, EmptyStructTest) { - struct EmptyStruct {}; +// Array member tests +TEST_F(FieldCountTest, StructWithArrayFieldCount) { + constexpr auto count = fieldCountOf(); + EXPECT_EQ(count, 2); // arr, x +} - constexpr auto COUNT = fieldCountOf(); - EXPECT_EQ(COUNT, 0); +TEST_F(FieldCountTest, StructWithNestedArrayFieldCount) { + constexpr auto count = fieldCountOf(); + EXPECT_EQ(count, 3); // x, arr, y } -TEST(FieldCountTest, SingleFieldStructTest) { - struct SingleFieldStruct { - int a; - }; +// Non-aggregate type tests +TEST_F(FieldCountTest, NonAggregateTypeHasZeroFields) { + constexpr auto count = fieldCountOf(); + EXPECT_EQ(count, 0); +} - constexpr auto COUNT = fieldCountOf(); - EXPECT_EQ(COUNT, 1); +// Inheritance tests +TEST_F(FieldCountTest, DerivedEmptyStructFieldCount) { + constexpr auto count = fieldCountOf(); + EXPECT_EQ(count, 1); // Only x, Empty base has no fields } -TEST(FieldCountTest, NonAggregateStructTest) { - struct NonAggregateStruct { - NonAggregateStruct(int x) : a(x) {} - int a; - }; +// Edge cases +struct BitFields { + int x : 1; + int y : 2; + int z : 3; +}; - // Non-aggregate types should not be counted - constexpr auto count = fieldCountOf(); - EXPECT_EQ(count, 0); +TEST_F(FieldCountTest, BitFieldsCount) { + constexpr auto count = fieldCountOf(); + EXPECT_EQ(count, 3); } + +// Custom type_info specialization test +struct CustomStruct { + int a, b, c; +}; + +TEST_F(FieldCountTest, CustomTypeInfoSpecialization) { + constexpr auto count = fieldCountOf(); + EXPECT_EQ(count, 3); +} + +// Compile-time evaluation test +TEST_F(FieldCountTest, CompileTimeEvaluation) { + static_assert(fieldCountOf() == 0); + static_assert(fieldCountOf() == 1); + static_assert(fieldCountOf() == 2); + static_assert(fieldCountOf() == 3); +} + +// Type trait tests +TEST_F(FieldCountTest, TypeTraitBehavior) { + static_assert(std::is_aggregate_v); + static_assert(std::is_aggregate_v); + static_assert(!std::is_aggregate_v); +} + +// Additional edge cases +struct EmptyArrayStruct { + int arr[0]; +}; + +struct ZeroLengthArrayStruct { + int x; + int arr[]; +}; + +TEST_F(FieldCountTest, SpecialArrayCases) { + constexpr auto empty_arr_count = fieldCountOf(); + EXPECT_EQ(empty_arr_count, 1); + + constexpr auto zero_length_count = fieldCountOf(); + EXPECT_EQ(zero_length_count, 2); +} + +// Stress test with many fields +struct ManyFields { + int f1, f2, f3, f4, f5, f6, f7, f8, f9, f10; + double f11, f12, f13, f14, f15, f16, f17, f18, f19, f20; +}; + +TEST_F(FieldCountTest, LargeStructFieldCount) { + constexpr auto count = fieldCountOf(); + EXPECT_EQ(count, 20); +} + +} // namespace atom::meta::test \ No newline at end of file diff --git a/tests/components/meta/proxy_params.cpp b/tests/components/meta/proxy_params.cpp index 2ff7f75b..caec4c26 100644 --- a/tests/components/meta/proxy_params.cpp +++ b/tests/components/meta/proxy_params.cpp @@ -47,35 +47,46 @@ TEST(FunctionParamsTest, SingleElementConstructor) { DEFAULT_INT_VALUE); } +// 修改测试用例,添加类型检查和安全转换 TEST(FunctionParamsTest, RangeConstructor) { - std::vector vec = {Arg("param1", 1), Arg("param2", "test"), - Arg("param3", DEFAULT_DOUBLE_VALUE)}; + std::vector vec = {Arg("param1", std::any(1)), + Arg("param2", std::any(std::string("test"))), + Arg("param3", std::any(DEFAULT_DOUBLE_VALUE))}; FunctionParams params(vec); ASSERT_EQ(params.size(), vec.size()); - EXPECT_EQ(params[0].getName(), "param1"); - EXPECT_EQ(std::any_cast(params[0].getDefaultValue().value()), 1); - EXPECT_EQ(params[1].getName(), "param2"); - EXPECT_EQ(std::any_cast(params[1].getDefaultValue().value()), - "test"); - EXPECT_EQ(params[2].getName(), "param3"); - EXPECT_EQ(std::any_cast(params[2].getDefaultValue().value()), - DEFAULT_DOUBLE_VALUE); + + auto param1Value = params[0].getDefaultValue(); + ASSERT_TRUE(param1Value.has_value()); + EXPECT_EQ(std::any_cast(param1Value.value()), 1); + + auto param2Value = params[1].getDefaultValue(); + ASSERT_TRUE(param2Value.has_value()); + EXPECT_EQ(std::any_cast(param2Value.value()), "test"); + + auto param3Value = params[2].getDefaultValue(); + ASSERT_TRUE(param3Value.has_value()); + EXPECT_EQ(std::any_cast(param3Value.value()), DEFAULT_DOUBLE_VALUE); } TEST(FunctionParamsTest, InitializerListConstructor) { - FunctionParams params = {Arg("param1", 1), Arg("param2", "test"), - Arg("param3", DEFAULT_DOUBLE_VALUE)}; + FunctionParams params = {Arg("param1", std::any(1)), + Arg("param2", std::any(std::string("test"))), + Arg("param3", std::any(DEFAULT_DOUBLE_VALUE))}; ASSERT_EQ(params.size(), 3); - EXPECT_EQ(params[0].getName(), "param1"); - EXPECT_EQ(std::any_cast(params[0].getDefaultValue().value()), 1); - EXPECT_EQ(params[1].getName(), "param2"); - EXPECT_EQ(std::any_cast(params[1].getDefaultValue().value()), - "test"); - EXPECT_EQ(params[2].getName(), "param3"); - EXPECT_EQ(std::any_cast(params[2].getDefaultValue().value()), - DEFAULT_DOUBLE_VALUE); + + auto param1Value = params[0].getDefaultValue(); + ASSERT_TRUE(param1Value.has_value()); + EXPECT_EQ(std::any_cast(param1Value.value()), 1); + + auto param2Value = params[1].getDefaultValue(); + ASSERT_TRUE(param2Value.has_value()); + EXPECT_EQ(std::any_cast(param2Value.value()), "test"); + + auto param3Value = params[2].getDefaultValue(); + ASSERT_TRUE(param3Value.has_value()); + EXPECT_EQ(std::any_cast(param3Value.value()), DEFAULT_DOUBLE_VALUE); } // 测试 FunctionParams 类的其他方法 @@ -148,14 +159,18 @@ TEST(FunctionParamsTest, ToVectorMethod) { } TEST(FunctionParamsTest, ToAnyVectorMethod) { - FunctionParams params = {Arg("param1", 1), Arg("param2", "test"), - Arg("param3", DEFAULT_DOUBLE_VALUE)}; + FunctionParams params = {Arg("param1", std::any(1)), + Arg("param2", std::any(std::string("test"))), + Arg("param3", std::any(DEFAULT_DOUBLE_VALUE))}; + auto anyVec = params.toAnyVector(); + ASSERT_EQ(anyVec.size(), 3); - EXPECT_EQ(anyVec.size(), 3); - EXPECT_EQ(std::any_cast(anyVec[0]), 1); - EXPECT_EQ(std::any_cast(anyVec[1]), "test"); - EXPECT_EQ(std::any_cast(anyVec[2]), DEFAULT_DOUBLE_VALUE); + EXPECT_NO_THROW({ + EXPECT_EQ(std::any_cast(anyVec[0]), 1); + EXPECT_EQ(std::any_cast(anyVec[1]), "test"); + EXPECT_EQ(std::any_cast(anyVec[2]), DEFAULT_DOUBLE_VALUE); + }); } TEST(FunctionParamsTest, GetByNameMethod) { diff --git a/tests/components/meta/type_caster.cpp b/tests/components/meta/type_caster.cpp index d67fbe05..646232cf 100644 --- a/tests/components/meta/type_caster.cpp +++ b/tests/components/meta/type_caster.cpp @@ -1,96 +1,184 @@ -#ifndef ATOM_META_TEST_TYPE_CASTER_HPP -#define ATOM_META_TEST_TYPE_CASTER_HPP - +// test_type_caster.hpp #include "atom/function/type_caster.hpp" #include +#include + +namespace atom::meta::test { -using namespace atom::meta; +// Test helper types +struct TestStruct { + int value; + explicit TestStruct(int v = 0) : value(v) {} +}; + +enum class TestEnum { Value1, Value2, Value3 }; class TypeCasterTest : public ::testing::Test { protected: - TypeCaster typeCaster; - - void SetUp() override { - // Register some custom types and conversions for testing - typeCaster.registerType("int"); - typeCaster.registerType("double"); - typeCaster.registerConversion([](const std::any& input) { - return std::any_cast(input) * 1.0; - }); - typeCaster.registerConversion([](const std::any& input) { - return static_cast(std::any_cast(input)); - }); + std::shared_ptr caster; + + void SetUp() override { caster = TypeCaster::createShared(); } + + // Helper to create simple conversion functions + template + static auto makeConvertFunc() -> TypeCaster::ConvertFunc { + return [](const std::any& value) -> std::any { + return std::any(static_cast(std::any_cast(value))); + }; } }; -TEST_F(TypeCasterTest, ConvertIntToDouble) { +// Constructor Tests +TEST_F(TypeCasterTest, CreateInstance) { + EXPECT_NE(caster, nullptr); + auto types = caster->getRegisteredTypes(); + EXPECT_FALSE(types.empty()); +} + +// Basic Type Registration Tests +TEST_F(TypeCasterTest, RegisterBasicType) { + caster->registerType("TestStruct"); + auto types = caster->getRegisteredTypes(); + EXPECT_TRUE(std::find(types.begin(), types.end(), "TestStruct") != + types.end()); +} + +// Type Conversion Tests +TEST_F(TypeCasterTest, BasicConversion) { + caster->registerType("int"); + caster->registerType("double"); + caster->registerConversion(makeConvertFunc()); + std::any input = 42; - std::any result = typeCaster.convert(input); + auto result = caster->convert(input); EXPECT_EQ(std::any_cast(result), 42.0); } -TEST_F(TypeCasterTest, ConvertDoubleToInt) { - std::any input = 42.0; - std::any result = typeCaster.convert(input); - EXPECT_EQ(std::any_cast(result), 42); +// Multi-stage Conversion Tests +TEST_F(TypeCasterTest, MultiStageConversion) { + caster->registerType("int"); + caster->registerType("double"); + caster->registerType("string"); + + caster->registerMultiStageConversion( + makeConvertFunc(), [](const std::any& value) -> std::any { + return std::to_string(std::any_cast(value)); + }); + + std::any input = 42; + auto result = caster->convert(input); + EXPECT_EQ(std::any_cast(result), "42"); } -TEST_F(TypeCasterTest, RegisterAndConvertCustomType) { - struct CustomType { - int value; - }; +// Type Alias Tests +TEST_F(TypeCasterTest, TypeAlias) { + caster->registerType("int"); + caster->registerAlias("Integer"); + auto types = caster->getRegisteredTypes(); + EXPECT_TRUE(std::find(types.begin(), types.end(), "Integer") != + types.end()); +} - typeCaster.registerType("CustomType"); - typeCaster.registerConversion([](const std::any& input) { - return std::any_cast(input).value; - }); +// Type Group Tests +TEST_F(TypeCasterTest, TypeGroup) { + std::vector numericTypes = {"int", "double", "float"}; + caster->registerTypeGroup("numeric", numericTypes); + // Verify group registration (implementation specific) +} - CustomType customValue{123}; - std::any input = customValue; - std::any result = typeCaster.convert(input); - EXPECT_EQ(std::any_cast(result), 123); +// Enum Tests +TEST_F(TypeCasterTest, EnumRegistration) { + caster->registerEnumValue("TestEnum", "Value1", TestEnum::Value1); + caster->registerEnumValue("TestEnum", "Value2", TestEnum::Value2); + + auto enumStr = caster->enumToString(TestEnum::Value1, "TestEnum"); + EXPECT_EQ(enumStr, "Value1"); + + auto enumVal = caster->stringToEnum("Value2", "TestEnum"); + EXPECT_EQ(enumVal, TestEnum::Value2); } -TEST_F(TypeCasterTest, RegisterMultiStageConversion) { - typeCaster.registerMultiStageConversion( - [](const std::any& input) { return std::any_cast(input) * 1.0; }, - [](const std::any& input) { - return std::to_string(std::any_cast(input)); - }); +// Error Handling Tests +TEST_F(TypeCasterTest, ConversionNotFound) { + caster->registerType("int"); + caster->registerType("string"); std::any input = 42; - std::any result = typeCaster.convert(input); - EXPECT_EQ(std::any_cast(result), "42.000000"); + EXPECT_THROW(caster->convert(input), std::runtime_error); +} + +TEST_F(TypeCasterTest, InvalidEnumValue) { + caster->registerEnumValue("TestEnum", "Value1", TestEnum::Value1); + EXPECT_THROW(caster->enumToString(TestEnum::Value2, "TestEnum"), + std::invalid_argument); + EXPECT_THROW(caster->stringToEnum("InvalidValue", "TestEnum"), + std::invalid_argument); } -TEST_F(TypeCasterTest, GetRegisteredTypes) { - auto types = typeCaster.getRegisteredTypes(); - EXPECT_NE(std::find(types.begin(), types.end(), "int"), types.end()); - EXPECT_NE(std::find(types.begin(), types.end(), "double"), types.end()); +// Thread Safety Tests +TEST_F(TypeCasterTest, ConcurrentTypeRegistration) { + std::vector threads; + for (int i = 0; i < 10; i++) { + threads.emplace_back([this, i]() { + std::string typeName = "Type" + std::to_string(i); + caster->registerType(typeName); + }); + } + + for (auto& thread : threads) { + thread.join(); + } + + auto types = caster->getRegisteredTypes(); + EXPECT_EQ(std::count_if(types.begin(), types.end(), + [](const std::string& name) { + return name.find("Type") != std::string::npos; + }), + 10); } -TEST_F(TypeCasterTest, EnumToString) { - enum class TestEnum { VALUE1, VALUE2 }; - typeCaster.registerEnumValue("TestEnum", "VALUE1", - TestEnum::VALUE1); - typeCaster.registerEnumValue("TestEnum", "VALUE2", - TestEnum::VALUE2); +// Cache Tests +TEST_F(TypeCasterTest, ConversionPathCache) { + caster->registerType("int"); + caster->registerType("double"); + caster->registerType("string"); + + caster->registerConversion(makeConvertFunc()); + caster->registerConversion( + [](const std::any& value) -> std::any { + return std::to_string(std::any_cast(value)); + }); + + // First conversion should build the path + std::any input = 42; + auto result1 = caster->convert(input); - EXPECT_EQ(typeCaster.enumToString(TestEnum::VALUE1, "TestEnum"), "VALUE1"); - EXPECT_EQ(typeCaster.enumToString(TestEnum::VALUE2, "TestEnum"), "VALUE2"); + // Second conversion should use cached path + auto result2 = caster->convert(input); + + EXPECT_EQ(std::any_cast(result1), + std::any_cast(result2)); } -TEST_F(TypeCasterTest, StringToEnum) { - enum class TestEnum { VALUE1, VALUE2 }; - typeCaster.registerEnumValue("TestEnum", "VALUE1", - TestEnum::VALUE1); - typeCaster.registerEnumValue("TestEnum", "VALUE2", - TestEnum::VALUE2); - - EXPECT_EQ(typeCaster.stringToEnum("VALUE1", "TestEnum"), - TestEnum::VALUE1); - EXPECT_EQ(typeCaster.stringToEnum("VALUE2", "TestEnum"), - TestEnum::VALUE2); +// Complex Conversion Path Tests +TEST_F(TypeCasterTest, ComplexConversionPath) { + // Register types + caster->registerType("int"); + caster->registerType("float"); + caster->registerType("double"); + caster->registerType("string"); + + // Register conversions + caster->registerConversion(makeConvertFunc()); + caster->registerConversion(makeConvertFunc()); + caster->registerConversion( + [](const std::any& value) -> std::any { + return std::to_string(std::any_cast(value)); + }); + + std::any input = 42; + auto result = caster->convert(input); + EXPECT_EQ(std::any_cast(result), "42"); } -#endif // ATOM_META_TEST_TYPE_CASTER_HPP +} // namespace atom::meta::test \ No newline at end of file