2222#include " fory/serialization/skip.h"
2323#include " fory/thirdparty/MurmurHash3.h"
2424#include " gtest/gtest.h"
25+ #include < any>
2526#include < array>
2627#include < atomic>
2728#include < chrono>
3132#include < map>
3233#include < string>
3334#include < thread>
35+ #include < typeinfo>
36+ #include < unordered_map>
3437#include < variant>
3538#include < vector>
3639
@@ -193,6 +196,24 @@ void test_roundtrip(const T &original, bool should_equal = true) {
193196 }
194197}
195198
199+ template <typename T> void expect_any_roundtrip (Fory &fory, const T &value) {
200+ std::any original = value;
201+ auto serialize_result = fory.serialize (original);
202+ ASSERT_TRUE (serialize_result.ok ())
203+ << " Serialization failed: " << serialize_result.error ().to_string ();
204+
205+ auto deserialize_result =
206+ fory.deserialize <std::any>(serialize_result.value ());
207+ ASSERT_TRUE (deserialize_result.ok ())
208+ << " Deserialization failed: " << deserialize_result.error ().to_string ();
209+
210+ std::any decoded = std::move (deserialize_result).value ();
211+ EXPECT_EQ (decoded.type (), typeid (T));
212+ const auto *decoded_value = std::any_cast<T>(&decoded);
213+ ASSERT_NE (decoded_value, nullptr );
214+ EXPECT_EQ (*decoded_value, value);
215+ }
216+
196217// ============================================================================
197218// Primitive Type Tests
198219// ============================================================================
@@ -370,10 +391,11 @@ TEST(SerializationTest, DurationRoundtrip) {
370391 auto fory =
371392 Fory::builder ().xlang (true ).compatible (false ).track_ref (false ).build ();
372393 std::vector<Duration> values = {
373- Duration (0 ),
374- std::chrono::seconds (12 ) + Duration (345678901 ),
375- -std::chrono::seconds (7 ) - std::chrono::milliseconds (45 ) - Duration (67 ),
376- Duration (-1 ),
394+ Duration (std::chrono::nanoseconds (0 )),
395+ Duration (std::chrono::seconds (12 ) + std::chrono::nanoseconds (345678901 )),
396+ Duration (-std::chrono::seconds (7 ) - std::chrono::milliseconds (45 ) -
397+ std::chrono::nanoseconds (67 )),
398+ Duration (std::chrono::nanoseconds (-1 )),
377399 };
378400
379401 for (const Duration &original : values) {
@@ -550,9 +572,9 @@ TEST(SerializationTest, DurationUsesSecondsAndNanosecondsPayload) {
550572 auto fory =
551573 Fory::builder ().xlang (true ).compatible (false ).track_ref (false ).build ();
552574 std::vector<TestCase> cases = {
553- {Duration (1234567890 ), 1 , 234567890 },
554- {Duration (-1234567890 ), -1 , -234567890 },
555- {Duration (- 1 ), 0 , -1 },
575+ {Duration (std::chrono::nanoseconds ( 1234567890 ) ), 1 , 234567890 },
576+ {Duration (std::chrono::nanoseconds ( -1234567890 ) ), -1 , -234567890 },
577+ {Duration (std::chrono::nanoseconds (- 1 ) ), 0 , -1 },
556578 };
557579
558580 for (const TestCase &test_case : cases) {
@@ -579,7 +601,8 @@ TEST(SerializationTest, DurationSkipConsumesSecondsAndNanosecondsPayload) {
579601 auto fory =
580602 Fory::builder ().xlang (true ).compatible (false ).track_ref (false ).build ();
581603 WriteContext write_ctx (fory.config (), fory.type_resolver ().clone ());
582- Serializer<Duration>::write_data (Duration (-1 ), write_ctx);
604+ Serializer<Duration>::write_data (Duration (std::chrono::nanoseconds (-1 )),
605+ write_ctx);
583606 ASSERT_FALSE (write_ctx.has_error ()) << write_ctx.error ().to_string ();
584607
585608 ReadContext read_ctx (fory.config (), fory.type_resolver ().clone ());
@@ -805,6 +828,13 @@ TEST(SerializationTest, MapStringIntRoundtrip) {
805828 std::map<std::string, int32_t >{{" one" , 1 }, {" two" , 2 }, {" three" , 3 }});
806829}
807830
831+ TEST (SerializationTest, UnorderedMapStringIntRoundtrip) {
832+ test_roundtrip (std::unordered_map<std::string, int32_t >{});
833+ test_roundtrip (std::unordered_map<std::string, int32_t >{{" one" , 1 }});
834+ test_roundtrip (std::unordered_map<std::string, int32_t >{
835+ {" one" , 1 }, {" two" , 2 }, {" three" , 3 }});
836+ }
837+
808838TEST (SerializationTest, NestedVectorRoundtrip) {
809839 test_roundtrip (std::vector<std::vector<int32_t >>{});
810840 test_roundtrip (std::vector<std::vector<int32_t >>{{1 , 2 }, {3 , 4 }, {5 }});
@@ -1489,6 +1519,113 @@ TEST(SerializationTest, ThreadSafeForyRejectsRegistrationAfterFirstSerialize) {
14891519 std::string::npos);
14901520}
14911521
1522+ TEST (SerializationTest, TemporalCarriersAreHashable) {
1523+ std::unordered_map<Date, std::string> date_map;
1524+ date_map[Date (0 )] = " epoch" ;
1525+ date_map[Date (18954 )] = " future" ;
1526+ date_map[Date (-1 )] = " past" ;
1527+ EXPECT_EQ (date_map.size (), 3u );
1528+ EXPECT_EQ (date_map[Date (0 )], " epoch" );
1529+
1530+ std::unordered_map<Duration, std::string> dur_map;
1531+ dur_map[Duration (std::chrono::nanoseconds (0 ))] = " zero" ;
1532+ dur_map[Duration (std::chrono::seconds (1 ))] = " one_sec" ;
1533+ dur_map[Duration (std::chrono::nanoseconds (-1 ))] = " neg" ;
1534+ EXPECT_EQ (dur_map.size (), 3u );
1535+ EXPECT_EQ (dur_map[Duration (std::chrono::nanoseconds (0 ))], " zero" );
1536+
1537+ std::unordered_map<Timestamp, std::string> ts_map;
1538+ ts_map[Timestamp ()] = " epoch" ;
1539+ ts_map[Timestamp (std::chrono::nanoseconds (1000000000LL ))] = " one_sec" ;
1540+ EXPECT_EQ (ts_map.size (), 2u );
1541+ EXPECT_EQ (ts_map[Timestamp ()], " epoch" );
1542+ }
1543+
1544+ TEST (SerializationTest, DurationChronoConversion) {
1545+ auto ns = std::chrono::seconds (5 ) + std::chrono::nanoseconds (123 );
1546+ Duration d (ns);
1547+ EXPECT_EQ (d.to_chrono (), ns);
1548+ EXPECT_EQ (d.count (), ns.count ());
1549+
1550+ Duration zero;
1551+ EXPECT_EQ (zero.count (), 0 );
1552+ EXPECT_EQ (zero.to_chrono (), std::chrono::nanoseconds (0 ));
1553+ }
1554+
1555+ TEST (SerializationTest, TimestampChronoConversion) {
1556+ auto ns = std::chrono::nanoseconds (1700000000000000000LL );
1557+ Timestamp ts (ns);
1558+ EXPECT_EQ (ts.time_since_epoch (), ns);
1559+ EXPECT_EQ (ts.to_chrono ().time_since_epoch (), ns);
1560+
1561+ Timestamp epoch;
1562+ EXPECT_EQ (epoch.time_since_epoch ().count (), 0 );
1563+ }
1564+
1565+ TEST (SerializationTest, TemporalAnyUsesCanonicalCarriers) {
1566+ auto fory =
1567+ Fory::builder ().xlang (true ).compatible (false ).track_ref (false ).build ();
1568+ ASSERT_TRUE (register_any_type<Duration>(fory.type_resolver ()).ok ());
1569+ ASSERT_TRUE (register_any_type<Timestamp>(fory.type_resolver ()).ok ());
1570+
1571+ expect_any_roundtrip (
1572+ fory, Duration (std::chrono::seconds (12 ) + std::chrono::nanoseconds (34 )));
1573+ expect_any_roundtrip (fory,
1574+ Timestamp (std::chrono::nanoseconds (1234567890123LL )));
1575+ }
1576+
1577+ TEST (SerializationTest, ChronoTemporalAnyRegistrationIsRejected) {
1578+ using ChronoTimestamp = std::chrono::time_point<std::chrono::system_clock,
1579+ std::chrono::nanoseconds>;
1580+ auto fory =
1581+ Fory::builder ().xlang (true ).compatible (false ).track_ref (false ).build ();
1582+
1583+ auto chrono_duration_registration =
1584+ register_any_type<std::chrono::nanoseconds>(fory.type_resolver ());
1585+ ASSERT_FALSE (chrono_duration_registration.ok ());
1586+ EXPECT_NE (chrono_duration_registration.error ().to_string ().find (
1587+ " explicit static targets" ),
1588+ std::string::npos);
1589+
1590+ ASSERT_TRUE (register_any_type<Duration>(fory.type_resolver ()).ok ());
1591+ ASSERT_TRUE (register_any_type<Timestamp>(fory.type_resolver ()).ok ());
1592+
1593+ auto chrono_timestamp_registration =
1594+ register_any_type<ChronoTimestamp>(fory.type_resolver ());
1595+ ASSERT_FALSE (chrono_timestamp_registration.ok ());
1596+ EXPECT_NE (chrono_timestamp_registration.error ().to_string ().find (
1597+ " explicit static targets" ),
1598+ std::string::npos);
1599+
1600+ expect_any_roundtrip (fory, Duration (std::chrono::nanoseconds (-1 )));
1601+ expect_any_roundtrip (fory, Timestamp (std::chrono::nanoseconds (1000000000LL )));
1602+ }
1603+
1604+ TEST (SerializationTest, ForyOwnedAndChronoShareWireEncoding) {
1605+ auto fory =
1606+ Fory::builder ().xlang (true ).compatible (false ).track_ref (false ).build ();
1607+
1608+ auto ns = std::chrono::seconds (7 ) + std::chrono::nanoseconds (654321 );
1609+ Duration fory_dur (ns);
1610+ std::chrono::nanoseconds chrono_dur = ns;
1611+
1612+ auto fory_bytes = fory.serialize (fory_dur);
1613+ auto chrono_bytes = fory.serialize (chrono_dur);
1614+ ASSERT_TRUE (fory_bytes.ok ());
1615+ ASSERT_TRUE (chrono_bytes.ok ());
1616+ EXPECT_EQ (fory_bytes.value (), chrono_bytes.value ());
1617+
1618+ auto decoded_from_fory = fory.deserialize <std::chrono::nanoseconds>(
1619+ fory_bytes.value ().data (), fory_bytes.value ().size ());
1620+ ASSERT_TRUE (decoded_from_fory.ok ());
1621+ EXPECT_EQ (decoded_from_fory.value (), ns);
1622+
1623+ auto decoded_from_chrono = fory.deserialize <Duration>(
1624+ chrono_bytes.value ().data (), chrono_bytes.value ().size ());
1625+ ASSERT_TRUE (decoded_from_chrono.ok ());
1626+ EXPECT_EQ (decoded_from_chrono.value (), fory_dur);
1627+ }
1628+
14921629} // namespace test
14931630} // namespace serialization
14941631} // namespace fory
0 commit comments