From ea4b86ccab63f979e33c75eefe85f6684a392e9a Mon Sep 17 00:00:00 2001 From: SuperSerious Dev Date: Wed, 25 Jun 2025 09:12:14 -0700 Subject: [PATCH 01/11] Add `paste` dependency to parquet-variant --- parquet-variant/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/parquet-variant/Cargo.toml b/parquet-variant/Cargo.toml index 0065121726ac..1fab5caee55a 100644 --- a/parquet-variant/Cargo.toml +++ b/parquet-variant/Cargo.toml @@ -35,5 +35,6 @@ rust-version = "1.83" [dependencies] arrow-schema = { workspace = true } chrono = { workspace = true } +paste = { version = "1.0" } [lib] From d8144c5a93a372af023366bd3c03da701c5006f6 Mon Sep 17 00:00:00 2001 From: SuperSerious Dev Date: Wed, 25 Jun 2025 09:12:14 -0700 Subject: [PATCH 02/11] Implement decoder tests for integers --- parquet-variant/src/decoder.rs | 63 ++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/parquet-variant/src/decoder.rs b/parquet-variant/src/decoder.rs index cb8336b5b88d..d0a2c66cb59f 100644 --- a/parquet-variant/src/decoder.rs +++ b/parquet-variant/src/decoder.rs @@ -284,37 +284,40 @@ pub(crate) fn decode_short_string(metadata: u8, data: &[u8]) -> Result { + paste! { + #[test] + fn [<$test_name _exact_length>]() { + let result = $decode_fn(&$data).unwrap(); + assert_eq!(result, $expected); + } + + #[test] + fn [<$test_name _truncated_length>]() { + // Remove the last byte of data so that there is not enough to decode + let truncated_data = &$data[.. $data.len() - 1]; + let result = $decode_fn(&truncated_data); + assert!(matches!(result, Err(ArrowError::InvalidArgumentError(_)))); + } + } + }; + } - #[test] - fn test_i8() -> Result<(), ArrowError> { - let data = [0x2a]; - let result = decode_int8(&data)?; - assert_eq!(result, 42); - Ok(()) - } - - #[test] - fn test_i16() -> Result<(), ArrowError> { - let data = [0xd2, 0x04]; - let result = decode_int16(&data)?; - assert_eq!(result, 1234); - Ok(()) - } - - #[test] - fn test_i32() -> Result<(), ArrowError> { - let data = [0x40, 0xe2, 0x01, 0x00]; - let result = decode_int32(&data)?; - assert_eq!(result, 123456); - Ok(()) - } - - #[test] - fn test_i64() -> Result<(), ArrowError> { - let data = [0x15, 0x81, 0xe9, 0x7d, 0xf4, 0x10, 0x22, 0x11]; - let result = decode_int64(&data)?; - assert_eq!(result, 1234567890123456789); - Ok(()) + decoder_tests!(test_i8, [0x2a], decode_int8, 42); + decoder_tests!(test_i16, [0xd2, 0x04], decode_int16, 1234); + decoder_tests!(test_i32, [0x40, 0xe2, 0x01, 0x00], decode_int32, 123456); + decoder_tests!( + test_i64, + [0x15, 0x81, 0xe9, 0x7d, 0xf4, 0x10, 0x22, 0x11], + decode_int64, + 1234567890123456789 + ); } #[test] From 629348d55f7bf9186a6d92721ce416778b134861 Mon Sep 17 00:00:00 2001 From: SuperSerious Dev Date: Wed, 25 Jun 2025 09:12:14 -0700 Subject: [PATCH 03/11] Implement decoder tests for decimals --- parquet-variant/src/decoder.rs | 123 +++++++++++++++++++++++---------- 1 file changed, 87 insertions(+), 36 deletions(-) diff --git a/parquet-variant/src/decoder.rs b/parquet-variant/src/decoder.rs index d0a2c66cb59f..9c5e887d105d 100644 --- a/parquet-variant/src/decoder.rs +++ b/parquet-variant/src/decoder.rs @@ -25,6 +25,7 @@ use std::num::TryFromIntError; // Makes the code a bit more readable pub(crate) const VARIANT_VALUE_HEADER_BYTES: usize = 1; +pub(crate) const DECIMAL_MAX_SCALE: u8 = 38; #[derive(Debug, Clone, Copy, PartialEq)] pub enum VariantBasicType { @@ -205,22 +206,40 @@ pub(crate) fn decode_int64(data: &[u8]) -> Result { /// Decodes a Decimal4 from the value section of a variant. pub(crate) fn decode_decimal4(data: &[u8]) -> Result<(i32, u8), ArrowError> { let scale = u8::from_le_bytes(array_from_slice(data, 0)?); - let integer = i32::from_le_bytes(array_from_slice(data, 1)?); - Ok((integer, scale)) + if scale <= DECIMAL_MAX_SCALE { + let integer = i32::from_le_bytes(array_from_slice(data, 1)?); + Ok((integer, scale)) + } else { + Err(ArrowError::InvalidArgumentError(format!( + "Scale must be <= {DECIMAL_MAX_SCALE}" + ))) + } } /// Decodes a Decimal8 from the value section of a variant. pub(crate) fn decode_decimal8(data: &[u8]) -> Result<(i64, u8), ArrowError> { let scale = u8::from_le_bytes(array_from_slice(data, 0)?); - let integer = i64::from_le_bytes(array_from_slice(data, 1)?); - Ok((integer, scale)) + if scale <= DECIMAL_MAX_SCALE { + let integer = i64::from_le_bytes(array_from_slice(data, 1)?); + Ok((integer, scale)) + } else { + Err(ArrowError::InvalidArgumentError(format!( + "Scale must be <= {DECIMAL_MAX_SCALE}" + ))) + } } /// Decodes a Decimal16 from the value section of a variant. pub(crate) fn decode_decimal16(data: &[u8]) -> Result<(i128, u8), ArrowError> { let scale = u8::from_le_bytes(array_from_slice(data, 0)?); - let integer = i128::from_le_bytes(array_from_slice(data, 1)?); - Ok((integer, scale)) + if scale <= DECIMAL_MAX_SCALE { + let integer = i128::from_le_bytes(array_from_slice(data, 1)?); + Ok((integer, scale)) + } else { + Err(ArrowError::InvalidArgumentError(format!( + "Scale must be <= {DECIMAL_MAX_SCALE}" + ))) + } } /// Decodes a Float from the value section of a variant. @@ -320,38 +339,70 @@ mod tests { ); } - #[test] - fn test_decimal4() -> Result<(), ArrowError> { - let data = [ - 0x02, // Scale - 0xd2, 0x04, 0x00, 0x00, // Integer - ]; - let result = decode_decimal4(&data)?; - assert_eq!(result, (1234, 2)); - Ok(()) - } + mod decimal { + use super::*; - #[test] - fn test_decimal8() -> Result<(), ArrowError> { - let data = [ - 0x02, // Scale - 0xd2, 0x02, 0x96, 0x49, 0x00, 0x00, 0x00, 0x00, // Integer - ]; - let result = decode_decimal8(&data)?; - assert_eq!(result, (1234567890, 2)); - Ok(()) - } + macro_rules! decoder_tests { + ($test_name:ident, $data:expr, $decode_fn:ident, $expected:expr) => { + paste! { + #[test] + fn [<$test_name _success>]() { + let result = $decode_fn(&$data).unwrap(); + assert_eq!(result, $expected); + } - #[test] - fn test_decimal16() -> Result<(), ArrowError> { - let data = [ - 0x02, // Scale - 0xd2, 0xb6, 0x23, 0xc0, 0xf4, 0x10, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, // Integer - ]; - let result = decode_decimal16(&data)?; - assert_eq!(result, (1234567891234567890, 2)); - Ok(()) + #[test] + fn [<$test_name _truncated_integer>]() { + // Remove the last byte of data so that there is not enough to decode + let truncated_data = &$data[.. $data.len() - 1]; + let result = $decode_fn(&truncated_data); + assert!(matches!(result, Err(ArrowError::InvalidArgumentError(_)))); + } + + #[test] + fn [<$test_name _scale_too_large>]() { + let mut data = $data; + + // Modify the scale byte to that it exceeds the limit in the spec + data[0] = 0xFF; + + let result = $decode_fn(&data); + assert!(matches!(result, Err(ArrowError::InvalidArgumentError(_)))); + } + } + }; + } + + decoder_tests!( + test_decimal4, + [ + 0x02, // Scale + 0xd2, 0x04, 0x00, 0x00, // Unscaled Value + ], + decode_decimal4, + (1234, 2) + ); + + decoder_tests!( + test_decimal8, + [ + 0x02, // Scale + 0xd2, 0x02, 0x96, 0x49, 0x00, 0x00, 0x00, 0x00, // Unscaled Value + ], + decode_decimal8, + (1234567890, 2) + ); + + decoder_tests!( + test_decimal16, + [ + 0x02, // Scale + 0xd2, 0xb6, 0x23, 0xc0, 0xf4, 0x10, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, // Unscaled Value + ], + decode_decimal16, + (1234567891234567890, 2) + ); } #[test] From 97e9cd38874880f3327aa0fbd65f4beea3cff576 Mon Sep 17 00:00:00 2001 From: SuperSerious Dev Date: Wed, 25 Jun 2025 10:02:39 -0700 Subject: [PATCH 04/11] Implement decoder tests for floats and doubles --- parquet-variant/src/decoder.rs | 48 +++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/parquet-variant/src/decoder.rs b/parquet-variant/src/decoder.rs index 9c5e887d105d..1d58a09d051a 100644 --- a/parquet-variant/src/decoder.rs +++ b/parquet-variant/src/decoder.rs @@ -405,20 +405,42 @@ mod tests { ); } - #[test] - fn test_float() -> Result<(), ArrowError> { - let data = [0x06, 0x2c, 0x93, 0x4e]; - let result = decode_float(&data)?; - assert_eq!(result, 1234567890.1234); - Ok(()) - } + mod float { + use super::*; - #[test] - fn test_double() -> Result<(), ArrowError> { - let data = [0xc9, 0xe5, 0x87, 0xb4, 0x80, 0x65, 0xd2, 0x41]; - let result = decode_double(&data)?; - assert_eq!(result, 1234567890.1234); - Ok(()) + macro_rules! decoder_tests { + ($test_name:ident, $data:expr, $decode_fn:ident, $expected:expr) => { + paste! { + #[test] + fn [<$test_name _exact_length>]() { + let result = $decode_fn(&$data).unwrap(); + assert_eq!(result, $expected); + } + + #[test] + fn [<$test_name _truncated_length>]() { + // Remove the last byte of data so that there is not enough to decode + let truncated_data = &$data[.. $data.len() - 1]; + let result = $decode_fn(&truncated_data); + assert!(matches!(result, Err(ArrowError::InvalidArgumentError(_)))); + } + } + }; + } + + decoder_tests!( + test_float, + [0x06, 0x2c, 0x93, 0x4e], + decode_float, + 1234567890.1234 + ); + + decoder_tests!( + test_double, + [0xc9, 0xe5, 0x87, 0xb4, 0x80, 0x65, 0xd2, 0x41], + decode_double, + 1234567890.1234 + ); } #[test] From 64b232679b792c08e74b97c616bed82e72caa187 Mon Sep 17 00:00:00 2001 From: SuperSerious Dev Date: Wed, 25 Jun 2025 10:08:47 -0700 Subject: [PATCH 05/11] Implement decoder tests for dates and datetimes standardize naming --- parquet-variant/src/decoder.rs | 59 +++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/parquet-variant/src/decoder.rs b/parquet-variant/src/decoder.rs index 1d58a09d051a..2a7b9da19f29 100644 --- a/parquet-variant/src/decoder.rs +++ b/parquet-variant/src/decoder.rs @@ -443,41 +443,56 @@ mod tests { ); } - #[test] - fn test_date() -> Result<(), ArrowError> { - let data = [0xe2, 0x4e, 0x0, 0x0]; - let result = decode_date(&data)?; - assert_eq!(result, NaiveDate::from_ymd_opt(2025, 4, 16).unwrap()); - Ok(()) - } + mod datetime { + use super::*; - #[test] - fn test_timestamp_micros() -> Result<(), ArrowError> { - let data = [0xe0, 0x52, 0x97, 0xdd, 0xe7, 0x32, 0x06, 0x00]; - let result = decode_timestamp_micros(&data)?; - assert_eq!( - result, + macro_rules! decoder_tests { + ($test_name:ident, $data:expr, $decode_fn:ident, $expected:expr) => { + paste! { + #[test] + fn [<$test_name _exact_length>]() { + let result = $decode_fn(&$data).unwrap(); + assert_eq!(result, $expected); + } + + #[test] + fn [<$test_name _truncated_length>]() { + // Remove the last byte of data so that there is not enough to decode + let truncated_data = &$data[.. $data.len() - 1]; + let result = $decode_fn(&truncated_data); + assert!(matches!(result, Err(ArrowError::InvalidArgumentError(_)))); + } + } + }; + } + + decoder_tests!( + test_date, + [0xe2, 0x4e, 0x0, 0x0], + decode_date, + NaiveDate::from_ymd_opt(2025, 4, 16).unwrap() + ); + + decoder_tests!( + test_timestamp_micros, + [0xe0, 0x52, 0x97, 0xdd, 0xe7, 0x32, 0x06, 0x00], + decode_timestamp_micros, NaiveDate::from_ymd_opt(2025, 4, 16) .unwrap() .and_hms_milli_opt(16, 34, 56, 780) .unwrap() .and_utc() ); - Ok(()) - } - #[test] - fn test_timestampntz_micros() -> Result<(), ArrowError> { - let data = [0xe0, 0x52, 0x97, 0xdd, 0xe7, 0x32, 0x06, 0x00]; - let result = decode_timestampntz_micros(&data)?; - assert_eq!( - result, + decoder_tests!( + test_timestampntz_micros, + [0xe0, 0x52, 0x97, 0xdd, 0xe7, 0x32, 0x06, 0x00], + decode_timestampntz_micros, NaiveDate::from_ymd_opt(2025, 4, 16) .unwrap() .and_hms_milli_opt(16, 34, 56, 780) .unwrap() ); - Ok(()) } #[test] From 1a3ff0b99a050aad99f047db955e684c87ae7676 Mon Sep 17 00:00:00 2001 From: SuperSerious Dev Date: Wed, 25 Jun 2025 11:18:51 -0700 Subject: [PATCH 06/11] Implement decoder tests for binary --- parquet-variant/src/decoder.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/parquet-variant/src/decoder.rs b/parquet-variant/src/decoder.rs index 2a7b9da19f29..ff1914e6fa9b 100644 --- a/parquet-variant/src/decoder.rs +++ b/parquet-variant/src/decoder.rs @@ -496,17 +496,26 @@ mod tests { } #[test] - fn test_binary() -> Result<(), ArrowError> { + fn test_binary_exact_length() { let data = [ 0x09, 0, 0, 0, // Length of binary data, 4-byte little-endian 0x03, 0x13, 0x37, 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, ]; - let result = decode_binary(&data)?; + let result = decode_binary(&data).unwrap(); assert_eq!( result, [0x03, 0x13, 0x37, 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe] ); - Ok(()) + } + + #[test] + fn test_binary_truncated_length() { + let data = [ + 0x09, 0, 0, 0, // Length of binary data, 4-byte little-endian + 0x03, 0x13, 0x37, 0xde, 0xad, 0xbe, 0xef, 0xca, + ]; + let result = decode_binary(&data); + assert!(matches!(result, Err(ArrowError::InvalidArgumentError(_)))); } #[test] From ecd8e76075fd0039cf9c3b364e4468d0b579d687 Mon Sep 17 00:00:00 2001 From: SuperSerious Dev Date: Wed, 25 Jun 2025 11:27:35 -0700 Subject: [PATCH 07/11] Implement decoder tests for strings and short strings --- parquet-variant/src/decoder.rs | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/parquet-variant/src/decoder.rs b/parquet-variant/src/decoder.rs index ff1914e6fa9b..89372bf836ae 100644 --- a/parquet-variant/src/decoder.rs +++ b/parquet-variant/src/decoder.rs @@ -519,22 +519,37 @@ mod tests { } #[test] - fn test_short_string() -> Result<(), ArrowError> { + fn test_short_string_exact_length() { let data = [b'H', b'e', b'l', b'l', b'o', b'o']; - let result = decode_short_string(1 | 5 << 2, &data)?; + let result = decode_short_string(1 | 5 << 2, &data).unwrap(); assert_eq!(result.0, "Hello"); - Ok(()) } #[test] - fn test_string() -> Result<(), ArrowError> { + fn test_short_string_truncated_length() { + let data = [b'H', b'e', b'l']; + let result = decode_short_string(1 | 5 << 2, &data); + assert!(matches!(result, Err(ArrowError::InvalidArgumentError(_)))); + } + + #[test] + fn test_string_exact_length() { let data = [ 0x05, 0, 0, 0, // Length of string, 4-byte little-endian b'H', b'e', b'l', b'l', b'o', b'o', ]; - let result = decode_long_string(&data)?; + let result = decode_long_string(&data).unwrap(); assert_eq!(result, "Hello"); - Ok(()) + } + + #[test] + fn test_string_truncated_length() { + let data = [ + 0x05, 0, 0, 0, // Length of string, 4-byte little-endian + b'H', b'e', b'l', + ]; + let result = decode_long_string(&data); + assert!(matches!(result, Err(ArrowError::InvalidArgumentError(_)))); } #[test] From 9d9d113e944c409aad05df7501e82334a31876e6 Mon Sep 17 00:00:00 2001 From: SuperSerious Dev Date: Wed, 25 Jun 2025 12:09:19 -0700 Subject: [PATCH 08/11] Remove unnecessary ref on the slice --- parquet-variant/src/decoder.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/parquet-variant/src/decoder.rs b/parquet-variant/src/decoder.rs index 89372bf836ae..d31480a6ff95 100644 --- a/parquet-variant/src/decoder.rs +++ b/parquet-variant/src/decoder.rs @@ -321,7 +321,7 @@ mod tests { fn [<$test_name _truncated_length>]() { // Remove the last byte of data so that there is not enough to decode let truncated_data = &$data[.. $data.len() - 1]; - let result = $decode_fn(&truncated_data); + let result = $decode_fn(truncated_data); assert!(matches!(result, Err(ArrowError::InvalidArgumentError(_)))); } } @@ -355,7 +355,7 @@ mod tests { fn [<$test_name _truncated_integer>]() { // Remove the last byte of data so that there is not enough to decode let truncated_data = &$data[.. $data.len() - 1]; - let result = $decode_fn(&truncated_data); + let result = $decode_fn(truncated_data); assert!(matches!(result, Err(ArrowError::InvalidArgumentError(_)))); } @@ -421,7 +421,7 @@ mod tests { fn [<$test_name _truncated_length>]() { // Remove the last byte of data so that there is not enough to decode let truncated_data = &$data[.. $data.len() - 1]; - let result = $decode_fn(&truncated_data); + let result = $decode_fn(truncated_data); assert!(matches!(result, Err(ArrowError::InvalidArgumentError(_)))); } } @@ -459,7 +459,7 @@ mod tests { fn [<$test_name _truncated_length>]() { // Remove the last byte of data so that there is not enough to decode let truncated_data = &$data[.. $data.len() - 1]; - let result = $decode_fn(&truncated_data); + let result = $decode_fn(truncated_data); assert!(matches!(result, Err(ArrowError::InvalidArgumentError(_)))); } } From dccd2d3c850615ff06b57a3dc14e1971ece12019 Mon Sep 17 00:00:00 2001 From: Andrew Lamb Date: Fri, 27 Jun 2025 17:48:36 -0400 Subject: [PATCH 09/11] Mark paste as a dev dependency --- parquet-variant/Cargo.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/parquet-variant/Cargo.toml b/parquet-variant/Cargo.toml index ffcbffe32212..6bec373d0204 100644 --- a/parquet-variant/Cargo.toml +++ b/parquet-variant/Cargo.toml @@ -35,8 +35,11 @@ rust-version = "1.83" [dependencies] arrow-schema = { workspace = true } chrono = { workspace = true } -paste = { version = "1.0" } serde_json = "1.0" base64 = "0.22" +[dev-dependencies] +paste = { version = "1.0" } + + [lib] From 24d6a2d0b4d7354290c45a25d13d6826d159f943 Mon Sep 17 00:00:00 2001 From: SuperSerious Dev Date: Sat, 28 Jun 2025 18:30:10 -0700 Subject: [PATCH 10/11] Remove extra scale validation --- parquet-variant/src/decoder.rs | 42 +++++----------------------------- 1 file changed, 6 insertions(+), 36 deletions(-) diff --git a/parquet-variant/src/decoder.rs b/parquet-variant/src/decoder.rs index 5737a974793b..2a11307a7b6b 100644 --- a/parquet-variant/src/decoder.rs +++ b/parquet-variant/src/decoder.rs @@ -25,7 +25,6 @@ use std::num::TryFromIntError; // Makes the code a bit more readable pub(crate) const VARIANT_VALUE_HEADER_BYTES: usize = 1; -pub(crate) const DECIMAL_MAX_SCALE: u8 = 38; #[derive(Debug, Clone, Copy, PartialEq)] pub enum VariantBasicType { @@ -205,40 +204,22 @@ pub(crate) fn decode_int64(data: &[u8]) -> Result { /// Decodes a Decimal4 from the value section of a variant. pub(crate) fn decode_decimal4(data: &[u8]) -> Result<(i32, u8), ArrowError> { let scale = u8::from_le_bytes(array_from_slice(data, 0)?); - if scale <= DECIMAL_MAX_SCALE { - let integer = i32::from_le_bytes(array_from_slice(data, 1)?); - Ok((integer, scale)) - } else { - Err(ArrowError::InvalidArgumentError(format!( - "Scale must be <= {DECIMAL_MAX_SCALE}" - ))) - } + let integer = i32::from_le_bytes(array_from_slice(data, 1)?); + Ok((integer, scale)) } /// Decodes a Decimal8 from the value section of a variant. pub(crate) fn decode_decimal8(data: &[u8]) -> Result<(i64, u8), ArrowError> { let scale = u8::from_le_bytes(array_from_slice(data, 0)?); - if scale <= DECIMAL_MAX_SCALE { - let integer = i64::from_le_bytes(array_from_slice(data, 1)?); - Ok((integer, scale)) - } else { - Err(ArrowError::InvalidArgumentError(format!( - "Scale must be <= {DECIMAL_MAX_SCALE}" - ))) - } + let integer = i64::from_le_bytes(array_from_slice(data, 1)?); + Ok((integer, scale)) } /// Decodes a Decimal16 from the value section of a variant. pub(crate) fn decode_decimal16(data: &[u8]) -> Result<(i128, u8), ArrowError> { let scale = u8::from_le_bytes(array_from_slice(data, 0)?); - if scale <= DECIMAL_MAX_SCALE { - let integer = i128::from_le_bytes(array_from_slice(data, 1)?); - Ok((integer, scale)) - } else { - Err(ArrowError::InvalidArgumentError(format!( - "Scale must be <= {DECIMAL_MAX_SCALE}" - ))) - } + let integer = i128::from_le_bytes(array_from_slice(data, 1)?); + Ok((integer, scale)) } /// Decodes a Float from the value section of a variant. @@ -357,17 +338,6 @@ mod tests { let result = $decode_fn(truncated_data); assert!(matches!(result, Err(ArrowError::InvalidArgumentError(_)))); } - - #[test] - fn [<$test_name _scale_too_large>]() { - let mut data = $data; - - // Modify the scale byte to that it exceeds the limit in the spec - data[0] = 0xFF; - - let result = $decode_fn(&data); - assert!(matches!(result, Err(ArrowError::InvalidArgumentError(_)))); - } } }; } From 47e1298e3472b2ffba108bbcce749e6d3376391c Mon Sep 17 00:00:00 2001 From: SuperSerious Dev Date: Sat, 28 Jun 2025 18:37:03 -0700 Subject: [PATCH 11/11] rename tests and remove duplicate macros --- parquet-variant/src/decoder.rs | 124 +++++++++------------------------ 1 file changed, 32 insertions(+), 92 deletions(-) diff --git a/parquet-variant/src/decoder.rs b/parquet-variant/src/decoder.rs index 2a11307a7b6b..6b5c1310787c 100644 --- a/parquet-variant/src/decoder.rs +++ b/parquet-variant/src/decoder.rs @@ -285,33 +285,33 @@ mod tests { use super::*; use paste::paste; - mod integer { - use super::*; + macro_rules! test_decoder_bounds { + ($test_name:ident, $data:expr, $decode_fn:ident, $expected:expr) => { + paste! { + #[test] + fn [<$test_name _exact_length>]() { + let result = $decode_fn(&$data).unwrap(); + assert_eq!(result, $expected); + } - macro_rules! decoder_tests { - ($test_name:ident, $data:expr, $decode_fn:ident, $expected:expr) => { - paste! { - #[test] - fn [<$test_name _exact_length>]() { - let result = $decode_fn(&$data).unwrap(); - assert_eq!(result, $expected); - } - - #[test] - fn [<$test_name _truncated_length>]() { - // Remove the last byte of data so that there is not enough to decode - let truncated_data = &$data[.. $data.len() - 1]; - let result = $decode_fn(truncated_data); - assert!(matches!(result, Err(ArrowError::InvalidArgumentError(_)))); - } + #[test] + fn [<$test_name _truncated_length>]() { + // Remove the last byte of data so that there is not enough to decode + let truncated_data = &$data[.. $data.len() - 1]; + let result = $decode_fn(truncated_data); + assert!(matches!(result, Err(ArrowError::InvalidArgumentError(_)))); } - }; - } + } + }; + } + + mod integer { + use super::*; - decoder_tests!(test_i8, [0x2a], decode_int8, 42); - decoder_tests!(test_i16, [0xd2, 0x04], decode_int16, 1234); - decoder_tests!(test_i32, [0x40, 0xe2, 0x01, 0x00], decode_int32, 123456); - decoder_tests!( + test_decoder_bounds!(test_i8, [0x2a], decode_int8, 42); + test_decoder_bounds!(test_i16, [0xd2, 0x04], decode_int16, 1234); + test_decoder_bounds!(test_i32, [0x40, 0xe2, 0x01, 0x00], decode_int32, 123456); + test_decoder_bounds!( test_i64, [0x15, 0x81, 0xe9, 0x7d, 0xf4, 0x10, 0x22, 0x11], decode_int64, @@ -322,27 +322,7 @@ mod tests { mod decimal { use super::*; - macro_rules! decoder_tests { - ($test_name:ident, $data:expr, $decode_fn:ident, $expected:expr) => { - paste! { - #[test] - fn [<$test_name _success>]() { - let result = $decode_fn(&$data).unwrap(); - assert_eq!(result, $expected); - } - - #[test] - fn [<$test_name _truncated_integer>]() { - // Remove the last byte of data so that there is not enough to decode - let truncated_data = &$data[.. $data.len() - 1]; - let result = $decode_fn(truncated_data); - assert!(matches!(result, Err(ArrowError::InvalidArgumentError(_)))); - } - } - }; - } - - decoder_tests!( + test_decoder_bounds!( test_decimal4, [ 0x02, // Scale @@ -352,7 +332,7 @@ mod tests { (1234, 2) ); - decoder_tests!( + test_decoder_bounds!( test_decimal8, [ 0x02, // Scale @@ -362,7 +342,7 @@ mod tests { (1234567890, 2) ); - decoder_tests!( + test_decoder_bounds!( test_decimal16, [ 0x02, // Scale @@ -377,34 +357,14 @@ mod tests { mod float { use super::*; - macro_rules! decoder_tests { - ($test_name:ident, $data:expr, $decode_fn:ident, $expected:expr) => { - paste! { - #[test] - fn [<$test_name _exact_length>]() { - let result = $decode_fn(&$data).unwrap(); - assert_eq!(result, $expected); - } - - #[test] - fn [<$test_name _truncated_length>]() { - // Remove the last byte of data so that there is not enough to decode - let truncated_data = &$data[.. $data.len() - 1]; - let result = $decode_fn(truncated_data); - assert!(matches!(result, Err(ArrowError::InvalidArgumentError(_)))); - } - } - }; - } - - decoder_tests!( + test_decoder_bounds!( test_float, [0x06, 0x2c, 0x93, 0x4e], decode_float, 1234567890.1234 ); - decoder_tests!( + test_decoder_bounds!( test_double, [0xc9, 0xe5, 0x87, 0xb4, 0x80, 0x65, 0xd2, 0x41], decode_double, @@ -415,34 +375,14 @@ mod tests { mod datetime { use super::*; - macro_rules! decoder_tests { - ($test_name:ident, $data:expr, $decode_fn:ident, $expected:expr) => { - paste! { - #[test] - fn [<$test_name _exact_length>]() { - let result = $decode_fn(&$data).unwrap(); - assert_eq!(result, $expected); - } - - #[test] - fn [<$test_name _truncated_length>]() { - // Remove the last byte of data so that there is not enough to decode - let truncated_data = &$data[.. $data.len() - 1]; - let result = $decode_fn(truncated_data); - assert!(matches!(result, Err(ArrowError::InvalidArgumentError(_)))); - } - } - }; - } - - decoder_tests!( + test_decoder_bounds!( test_date, [0xe2, 0x4e, 0x0, 0x0], decode_date, NaiveDate::from_ymd_opt(2025, 4, 16).unwrap() ); - decoder_tests!( + test_decoder_bounds!( test_timestamp_micros, [0xe0, 0x52, 0x97, 0xdd, 0xe7, 0x32, 0x06, 0x00], decode_timestamp_micros, @@ -453,7 +393,7 @@ mod tests { .and_utc() ); - decoder_tests!( + test_decoder_bounds!( test_timestampntz_micros, [0xe0, 0x52, 0x97, 0xdd, 0xe7, 0x32, 0x06, 0x00], decode_timestampntz_micros,