@@ -383,61 +383,6 @@ TEST(LiteralTest, DoubleZeroComparison) {
383383 EXPECT_EQ (neg_zero <=> pos_zero, std::partial_ordering::less);
384384}
385385
386- void CheckBinaryRoundTrip (const std::vector<uint8_t >& input_bytes,
387- const Literal& expected_literal,
388- std::shared_ptr<PrimitiveType> type) {
389- // Deserialize from bytes
390- auto literal_result = Literal::Deserialize (input_bytes, type);
391- ASSERT_TRUE (literal_result.has_value ());
392-
393- // Check type and value are correct
394- EXPECT_EQ (literal_result->type ()->type_id (), expected_literal.type ()->type_id ());
395- EXPECT_EQ (literal_result->ToString (), expected_literal.ToString ());
396-
397- // Serialize back to bytes
398- auto bytes_result = literal_result->Serialize ();
399- ASSERT_TRUE (bytes_result.has_value ());
400- EXPECT_EQ (*bytes_result, input_bytes);
401-
402- // Deserialize again to verify
403- auto final_literal = Literal::Deserialize (*bytes_result, type);
404- ASSERT_TRUE (final_literal.has_value ());
405- EXPECT_EQ (final_literal->type ()->type_id (), expected_literal.type ()->type_id ());
406- EXPECT_EQ (final_literal->ToString (), expected_literal.ToString ());
407- }
408-
409- // binary serialization tests
410- TEST (LiteralSerializationTest, BinaryBoolean) {
411- CheckBinaryRoundTrip ({1 }, Literal::Boolean (true ), boolean ());
412- CheckBinaryRoundTrip ({0 }, Literal::Boolean (false ), boolean ());
413- }
414-
415- TEST (LiteralSerializationTest, BinaryInt) {
416- CheckBinaryRoundTrip ({32 , 0 , 0 , 0 }, Literal::Int (32 ), int32 ());
417- }
418-
419- TEST (LiteralSerializationTest, BinaryLong) {
420- CheckBinaryRoundTrip ({32 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, Literal::Long (32 ), int64 ());
421- }
422-
423- TEST (LiteralSerializationTest, BinaryFloat) {
424- CheckBinaryRoundTrip ({0 , 0 , 128 , 63 }, Literal::Float (1 .0f ), float32 ());
425- }
426-
427- TEST (LiteralSerializationTest, BinaryDouble) {
428- CheckBinaryRoundTrip ({0 , 0 , 0 , 0 , 0 , 0 , 240 , 63 }, Literal::Double (1.0 ), float64 ());
429- }
430-
431- TEST (LiteralSerializationTest, BinaryString) {
432- CheckBinaryRoundTrip ({105 , 99 , 101 , 98 , 101 , 114 , 103 }, Literal::String (" iceberg" ),
433- string ());
434- }
435-
436- TEST (LiteralSerializationTest, BinaryData) {
437- std::vector<uint8_t > data = {0x01 , 0x02 , 0x03 , 0xFF };
438- CheckBinaryRoundTrip (data, Literal::Binary (data), binary ());
439- }
440-
441386// Type promotion tests
442387TEST (LiteralSerializationTest, TypePromotion) {
443388 // 4-byte int data can be deserialized as long
@@ -463,61 +408,93 @@ TEST(LiteralSerializationTest, TypePromotion) {
463408 EXPECT_EQ (double_bytes->size (), 8 );
464409}
465410
466- // Edge case serialization tests
467- TEST (LiteralSerializationTest, EdgeCases) {
468- // Negative integers
469- CheckBinaryRoundTrip ({224 , 255 , 255 , 255 }, Literal::Int (-32 ), int32 ());
470- CheckBinaryRoundTrip ({224 , 255 , 255 , 255 , 255 , 255 , 255 , 255 }, Literal::Long (-32 ),
471- int64 ());
411+ struct LiteralRoundTripParam {
412+ std::string test_name;
413+ std::vector<uint8_t > input_bytes;
414+ Literal expected_literal;
415+ std::shared_ptr<PrimitiveType> type;
416+ };
417+
418+ class LiteralSerializationParamTest
419+ : public ::testing::TestWithParam<LiteralRoundTripParam> {};
420+
421+ TEST_P (LiteralSerializationParamTest, RoundTrip) {
422+ const auto & param = GetParam ();
423+
424+ // Deserialize from bytes
425+ Result<Literal> literal_result = Literal::Deserialize (param.input_bytes , param.type );
426+ ASSERT_TRUE (literal_result.has_value ())
427+ << " Deserialization failed: " << literal_result.error ().message ;
428+
429+ // Check type and value
430+ EXPECT_EQ (literal_result->type ()->type_id (), param.expected_literal .type ()->type_id ());
431+ EXPECT_EQ (literal_result->ToString (), param.expected_literal .ToString ());
472432
473- // Empty string special handling: empty string -> empty bytes -> null conversion
433+ // Serialize back to bytes
434+ Result<std::vector<uint8_t >> bytes_result = literal_result->Serialize ();
435+ ASSERT_TRUE (bytes_result.has_value ())
436+ << " Serialization failed: " << bytes_result.error ().message ;
437+ EXPECT_EQ (*bytes_result, param.input_bytes );
438+
439+ // Deserialize again to verify idempotency
440+ Result<Literal> final_literal = Literal::Deserialize (*bytes_result, param.type );
441+ ASSERT_TRUE (final_literal.has_value ())
442+ << " Final deserialization failed: " << final_literal.error ().message ;
443+ EXPECT_EQ (final_literal->type ()->type_id (), param.expected_literal .type ()->type_id ());
444+ EXPECT_EQ (final_literal->ToString (), param.expected_literal .ToString ());
445+ }
446+
447+ INSTANTIATE_TEST_SUITE_P (
448+ BinarySerializationTests, LiteralSerializationParamTest,
449+ ::testing::Values (
450+ // Basic types
451+ LiteralRoundTripParam{" BooleanTrue" , {1 }, Literal::Boolean (true ), boolean ()},
452+ LiteralRoundTripParam{" BooleanFalse" , {0 }, Literal::Boolean (false ), boolean ()},
453+ LiteralRoundTripParam{" Int" , {32 , 0 , 0 , 0 }, Literal::Int (32 ), int32 ()},
454+ LiteralRoundTripParam{
455+ " Long" , {32 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, Literal::Long (32 ), int64 ()},
456+ LiteralRoundTripParam{" Float" , {0 , 0 , 128 , 63 }, Literal::Float (1 .0f ), float32 ()},
457+ LiteralRoundTripParam{
458+ " Double" , {0 , 0 , 0 , 0 , 0 , 0 , 240 , 63 }, Literal::Double (1.0 ), float64 ()},
459+ LiteralRoundTripParam{" String" ,
460+ {105 , 99 , 101 , 98 , 101 , 114 , 103 },
461+ Literal::String (" iceberg" ),
462+ string ()},
463+ LiteralRoundTripParam{" BinaryData" ,
464+ {0x01 , 0x02 , 0x03 , 0xFF },
465+ Literal::Binary ({0x01 , 0x02 , 0x03 , 0xFF }),
466+ binary ()},
467+ // Edge cases that fit the round-trip pattern
468+ LiteralRoundTripParam{
469+ " NegativeInt" , {224 , 255 , 255 , 255 }, Literal::Int (-32 ), int32 ()},
470+ LiteralRoundTripParam{" NegativeLong" ,
471+ {224 , 255 , 255 , 255 , 255 , 255 , 255 , 255 },
472+ Literal::Long (-32 ),
473+ int64 ()},
474+ // IEEE 754 representation for NaN and Infinity (in little-endian)
475+ LiteralRoundTripParam{" FloatInfinity" ,
476+ {0 , 0 , 128 , 127 },
477+ Literal::Float (std::numeric_limits<float >::infinity ()),
478+ float32 ()},
479+ LiteralRoundTripParam{" FloatNaN" ,
480+ {0 , 0 , 192 , 127 },
481+ Literal::Float (std::numeric_limits<float >::quiet_NaN ()),
482+ float32 ()}
483+ // TODO(Li Feiyang): Add tests for Date, Time, Timestamp, TimestampTz
484+ ),
485+
486+ [](const testing::TestParamInfo<LiteralSerializationParamTest::ParamType>& info) {
487+ return info.param .test_name ;
488+ });
489+
490+ TEST (LiteralSerializationEdgeCaseTest, EmptyStringSerialization) {
474491 auto empty_string = Literal::String (" " );
475492 auto empty_bytes = empty_string.Serialize ();
476493 ASSERT_TRUE (empty_bytes.has_value ());
477494 EXPECT_TRUE (empty_bytes->empty ());
478495
479- // Empty bytes cause an InvalidArgument error
480- auto null_result = Literal::Deserialize (*empty_bytes, string ());
481- EXPECT_THAT (null_result, IsError (ErrorKind::kInvalidArgument ));
482-
483- // Special floating point value serialization
484- auto nan_float = Literal::Float (std::numeric_limits<float >::quiet_NaN ());
485- auto nan_bytes = nan_float.Serialize ();
486- ASSERT_TRUE (nan_bytes.has_value ());
487- EXPECT_EQ (nan_bytes->size (), 4 );
488-
489- auto inf_float = Literal::Float (std::numeric_limits<float >::infinity ());
490- auto inf_bytes = inf_float.Serialize ();
491- ASSERT_TRUE (inf_bytes.has_value ());
492- EXPECT_EQ (inf_bytes->size (), 4 );
493- }
494-
495- // Error case serialization tests
496- TEST (LiteralSerializationTest, ErrorCases) {
497- // AboveMax/BelowMin values cannot be serialized
498- auto long_literal =
499- Literal::Long (static_cast <int64_t >(std::numeric_limits<int32_t >::max ()) + 1 );
500- auto above_max_result = long_literal.CastTo (int32 ());
501- ASSERT_TRUE (above_max_result.has_value ());
502- EXPECT_TRUE (above_max_result->IsAboveMax ());
503-
504- auto serialize_result = above_max_result->Serialize ();
505- EXPECT_FALSE (serialize_result.has_value ());
506-
507- // Insufficient data size for deserialization should fail
508- std::vector<uint8_t > insufficient_int_data = {0x01 }; // Need 4 bytes but only have 1
509- auto insufficient_data = Literal::Deserialize (insufficient_int_data, int32 ());
510- EXPECT_FALSE (insufficient_data.has_value ());
511-
512- std::vector<uint8_t > insufficient_long_data = {
513- 0x01 , 0x02 }; // Need 4 or 8 bytes but only have 2
514- auto insufficient_long = Literal::Deserialize (insufficient_long_data, int64 ());
515- EXPECT_FALSE (insufficient_long.has_value ());
516-
517- // Oversized decimal data should fail
518- std::vector<uint8_t > oversized_decimal (20 , 0xFF ); // Exceeds 16-byte limit
519- auto oversized_result = Literal::Deserialize (oversized_decimal, decimal (10 , 2 ));
520- EXPECT_FALSE (oversized_result.has_value ());
496+ auto deserialize_result = Literal::Deserialize (*empty_bytes, string ());
497+ EXPECT_THAT (deserialize_result, IsError (ErrorKind::kInvalidArgument ));
521498}
522499
523500} // namespace iceberg
0 commit comments