From 45846f09bfe6353e53e45f48d04f9448290d97f0 Mon Sep 17 00:00:00 2001 From: Remzi Yang <59198230+HaoYang670@users.noreply.github.com> Date: Fri, 17 Jun 2022 18:46:42 +0800 Subject: [PATCH] Clean up the test code of `substring` kernel. (#1853) * clean up Signed-off-by: remzi <13716567376yh@gmail.com> * clean up fixed binary Signed-off-by: remzi <13716567376yh@gmail.com> * trigger GitHub actions * directly panic Signed-off-by: remzi <13716567376yh@gmail.com> * add docs for helper macros Signed-off-by: remzi <13716567376yh@gmail.com> --- arrow/src/compute/kernels/substring.rs | 988 ++++++++----------------- 1 file changed, 306 insertions(+), 682 deletions(-) diff --git a/arrow/src/compute/kernels/substring.rs b/arrow/src/compute/kernels/substring.rs index 625a37514d1..024f5633fef 100644 --- a/arrow/src/compute/kernels/substring.rs +++ b/arrow/src/compute/kernels/substring.rs @@ -445,218 +445,138 @@ mod tests { use super::*; use crate::datatypes::*; - #[allow(clippy::type_complexity)] - fn with_nulls_generic_binary() -> Result<()> { - let cases: Vec<(Vec>, i64, Option, Vec>)> = vec![ - // all-nulls array is always identical - (vec![None, None, None], -1, Some(1), vec![None, None, None]), + /// A helper macro to generate test cases. + /// # Arguments + /// * `input` - A vector which array can be built from. + /// * `start` - The start index of the substring. + /// * `len` - The length of the substring. + /// * `result` - The expected result of substring, which is a vector that array can be built from. + /// # Return + /// A vector of `(input, start, len, result)`. + /// + /// Users can provide any number of `(start, len, result)` to generate test cases for one `input`. + macro_rules! gen_test_cases { + ($input:expr, $(($start:expr, $len:expr, $result:expr)), *) => { + [ + $( + ($input.clone(), $start, $len, $result), + )* + ] + }; + } + + /// A helper macro to test the substring functions. + /// # Arguments + /// * `cases` - The test cases which is a vector of `(input, start, len, result)`. + /// Please look at [`gen_test_cases`] to find how to generate it. + /// * `array_ty` - The array type. + /// * `substring_fn` - Either [`substring`] or [`substring_by_char`]. + macro_rules! do_test { + ($cases:expr, $array_ty:ty, $substring_fn:ident) => { + $cases + .into_iter() + .for_each(|(array, start, length, expected)| { + let array = <$array_ty>::from(array); + let result = $substring_fn(&array, start, length).unwrap(); + let result = result.as_any().downcast_ref::<$array_ty>().unwrap(); + let expected = <$array_ty>::from(expected); + assert_eq!(&expected, result); + }) + }; + } + + fn with_nulls_generic_binary() { + let input = vec![ + Some("hello".as_bytes()), + None, + Some(&[0xf8, 0xf9, 0xff, 0xfa]), + ]; + // all-nulls array is always identical + let base_case = gen_test_cases!( + vec![None, None, None], + (-1, Some(1), vec![None, None, None]) + ); + let cases = gen_test_cases!( + input, // identity - ( - vec![Some(b"hello"), None, Some(&[0xf8, 0xf9, 0xff, 0xfa])], - 0, - None, - vec![Some(b"hello"), None, Some(&[0xf8, 0xf9, 0xff, 0xfa])], - ), + (0, None, input.clone()), // 0 length -> Nothing - ( - vec![Some(b"hello"), None, Some(&[0xf8, 0xf9, 0xff, 0xfa])], - 0, - Some(0), - vec![Some(&[]), None, Some(&[])], - ), + (0, Some(0), vec![Some(&[]), None, Some(&[])]), // high start -> Nothing - ( - vec![Some(b"hello"), None, Some(&[0xf8, 0xf9, 0xff, 0xfa])], - 1000, - Some(0), - vec![Some(&[]), None, Some(&[])], - ), + (1000, Some(0), vec![Some(&[]), None, Some(&[])]), // high negative start -> identity - ( - vec![Some(b"hello"), None, Some(&[0xf8, 0xf9, 0xff, 0xfa])], - -1000, - None, - vec![Some(b"hello"), None, Some(&[0xf8, 0xf9, 0xff, 0xfa])], - ), + (-1000, None, input.clone()), // high length -> identity - ( - vec![Some(b"hello"), None, Some(&[0xf8, 0xf9, 0xff, 0xfa])], - 0, - Some(1000), - vec![Some(b"hello"), None, Some(&[0xf8, 0xf9, 0xff, 0xfa])], - ), - ]; - - cases.into_iter().try_for_each::<_, Result<()>>( - |(array, start, length, expected)| { - let array = GenericBinaryArray::::from(array); - let result: ArrayRef = substring(&array, start, length)?; - assert_eq!(array.len(), result.len()); - - let result = result - .as_any() - .downcast_ref::>() - .unwrap(); - let expected = GenericBinaryArray::::from(expected); - assert_eq!(&expected, result); - Ok(()) - }, - )?; - - Ok(()) + (0, Some(1000), input.clone()) + ); + + do_test!( + [&base_case[..], &cases[..]].concat(), + GenericBinaryArray, + substring + ); } #[test] - fn with_nulls_binary() -> Result<()> { + fn with_nulls_binary() { with_nulls_generic_binary::() } #[test] - fn with_nulls_large_binary() -> Result<()> { + fn with_nulls_large_binary() { with_nulls_generic_binary::() } - #[allow(clippy::type_complexity)] - fn without_nulls_generic_binary() -> Result<()> { - let cases: Vec<(Vec<&[u8]>, i64, Option, Vec<&[u8]>)> = vec![ - // empty array is always identical - (vec![b"", b"", b""], 2, Some(1), vec![b"", b"", b""]), + fn without_nulls_generic_binary() { + let input = vec!["hello".as_bytes(), b"", &[0xf8, 0xf9, 0xff, 0xfa]]; + // empty array is always identical + let base_case = gen_test_cases!( + vec!["".as_bytes(), b"", b""], + (2, Some(1), vec!["".as_bytes(), b"", b""]) + ); + let cases = gen_test_cases!( + input, + // identity + (0, None, input.clone()), // increase start - ( - vec![b"hello", b"", &[0xf8, 0xf9, 0xff, 0xfa]], - 0, - None, - vec![b"hello", b"", &[0xf8, 0xf9, 0xff, 0xfa]], - ), - ( - vec![b"hello", b"", &[0xf8, 0xf9, 0xff, 0xfa]], - 1, - None, - vec![b"ello", b"", &[0xf9, 0xff, 0xfa]], - ), - ( - vec![b"hello", b"", &[0xf8, 0xf9, 0xff, 0xfa]], - 2, - None, - vec![b"llo", b"", &[0xff, 0xfa]], - ), - ( - vec![b"hello", b"", &[0xf8, 0xf9, 0xff, 0xfa]], - 3, - None, - vec![b"lo", b"", &[0xfa]], - ), - ( - vec![b"hello", b"", &[0xf8, 0xf9, 0xff, 0xfa]], - 10, - None, - vec![b"", b"", b""], - ), + (1, None, vec![b"ello", b"", &[0xf9, 0xff, 0xfa]]), + (2, None, vec![b"llo", b"", &[0xff, 0xfa]]), + (3, None, vec![b"lo", b"", &[0xfa]]), + (10, None, vec![b"", b"", b""]), // increase start negatively - ( - vec![b"hello", b"", &[0xf8, 0xf9, 0xff, 0xfa]], - -1, - None, - vec![b"o", b"", &[0xfa]], - ), - ( - vec![b"hello", b"", &[0xf8, 0xf9, 0xff, 0xfa]], - -2, - None, - vec![b"lo", b"", &[0xff, 0xfa]], - ), - ( - vec![b"hello", b"", &[0xf8, 0xf9, 0xff, 0xfa]], - -3, - None, - vec![b"llo", b"", &[0xf9, 0xff, 0xfa]], - ), - ( - vec![b"hello", b"", &[0xf8, 0xf9, 0xff, 0xfa]], - -10, - None, - vec![b"hello", b"", &[0xf8, 0xf9, 0xff, 0xfa]], - ), + (-1, None, vec![b"o", b"", &[0xfa]]), + (-2, None, vec![b"lo", b"", &[0xff, 0xfa]]), + (-3, None, vec![b"llo", b"", &[0xf9, 0xff, 0xfa]]), + (-10, None, input.clone()), // increase length - ( - vec![b"hello", b"", &[0xf8, 0xf9, 0xff, 0xfa]], - 1, - Some(1), - vec![b"e", b"", &[0xf9]], - ), - ( - vec![b"hello", b"", &[0xf8, 0xf9, 0xff, 0xfa]], - 1, - Some(2), - vec![b"el", b"", &[0xf9, 0xff]], - ), - ( - vec![b"hello", b"", &[0xf8, 0xf9, 0xff, 0xfa]], - 1, - Some(3), - vec![b"ell", b"", &[0xf9, 0xff, 0xfa]], - ), - ( - vec![b"hello", b"", &[0xf8, 0xf9, 0xff, 0xfa]], - 1, - Some(4), - vec![b"ello", b"", &[0xf9, 0xff, 0xfa]], - ), - ( - vec![b"hello", b"", &[0xf8, 0xf9, 0xff, 0xfa]], - -3, - Some(1), - vec![b"l", b"", &[0xf9]], - ), - ( - vec![b"hello", b"", &[0xf8, 0xf9, 0xff, 0xfa]], - -3, - Some(2), - vec![b"ll", b"", &[0xf9, 0xff]], - ), - ( - vec![b"hello", b"", &[0xf8, 0xf9, 0xff, 0xfa]], - -3, - Some(3), - vec![b"llo", b"", &[0xf9, 0xff, 0xfa]], - ), - ( - vec![b"hello", b"", &[0xf8, 0xf9, 0xff, 0xfa]], - -3, - Some(4), - vec![b"llo", b"", &[0xf9, 0xff, 0xfa]], - ), - ]; - - cases.into_iter().try_for_each::<_, Result<()>>( - |(array, start, length, expected)| { - let array = GenericBinaryArray::::from(array); - let result = substring(&array, start, length)?; - assert_eq!(array.len(), result.len()); - let result = result - .as_any() - .downcast_ref::>() - .unwrap(); - let expected = GenericBinaryArray::::from(expected); - assert_eq!(&expected, result,); - Ok(()) - }, - )?; - - Ok(()) + (1, Some(1), vec![b"e", b"", &[0xf9]]), + (1, Some(2), vec![b"el", b"", &[0xf9, 0xff]]), + (1, Some(3), vec![b"ell", b"", &[0xf9, 0xff, 0xfa]]), + (1, Some(4), vec![b"ello", b"", &[0xf9, 0xff, 0xfa]]), + (-3, Some(1), vec![b"l", b"", &[0xf9]]), + (-3, Some(2), vec![b"ll", b"", &[0xf9, 0xff]]), + (-3, Some(3), vec![b"llo", b"", &[0xf9, 0xff, 0xfa]]), + (-3, Some(4), vec![b"llo", b"", &[0xf9, 0xff, 0xfa]]) + ); + + do_test!( + [&base_case[..], &cases[..]].concat(), + GenericBinaryArray, + substring + ); } #[test] - fn without_nulls_binary() -> Result<()> { + fn without_nulls_binary() { without_nulls_generic_binary::() } #[test] - fn without_nulls_large_binary() -> Result<()> { + fn without_nulls_large_binary() { without_nulls_generic_binary::() } - fn generic_binary_with_non_zero_offset() -> Result<()> { + fn generic_binary_with_non_zero_offset() { let values = 0_u8..15; let offsets = &[ O::zero(), @@ -673,11 +593,12 @@ mod tests { .add_buffer(Buffer::from_iter(values)) .null_bit_buffer(Some(Buffer::from(bitmap))) .offset(1) - .build()?; + .build() + .unwrap(); // array is `[null, [10, 11, 12, 13, 14]]` let array = GenericBinaryArray::::from(data); // result is `[null, [11, 12, 13, 14]]` - let result = substring(&array, 1, None)?; + let result = substring(&array, 1, None).unwrap(); let result = result .as_any() .downcast_ref::>() @@ -685,277 +606,96 @@ mod tests { let expected = GenericBinaryArray::::from_opt_vec(vec![None, Some(&[11_u8, 12, 13, 14])]); assert_eq!(result, &expected); - - Ok(()) } #[test] - fn binary_with_non_zero_offset() -> Result<()> { + fn binary_with_non_zero_offset() { generic_binary_with_non_zero_offset::() } #[test] - fn large_binary_with_non_zero_offset() -> Result<()> { + fn large_binary_with_non_zero_offset() { generic_binary_with_non_zero_offset::() } #[test] - #[allow(clippy::type_complexity)] - fn with_nulls_fixed_size_binary() -> Result<()> { - let cases: Vec<(Vec>, i64, Option, Vec>)> = vec![ - // all-nulls array is always identical - (vec![None, None, None], 3, Some(2), vec![None, None, None]), + fn with_nulls_fixed_size_binary() { + let input = vec![Some("cat".as_bytes()), None, Some(&[0xf8, 0xf9, 0xff])]; + // all-nulls array is always identical + let base_case = + gen_test_cases!(vec![None, None, None], (3, Some(2), vec![None, None, None])); + let cases = gen_test_cases!( + input, + // identity + (0, None, input.clone()), // increase start - ( - vec![Some(b"cat"), None, Some(&[0xf8, 0xf9, 0xff])], - 0, - None, - vec![Some(b"cat"), None, Some(&[0xf8, 0xf9, 0xff])], - ), - ( - vec![Some(b"cat"), None, Some(&[0xf8, 0xf9, 0xff])], - 1, - None, - vec![Some(b"at"), None, Some(&[0xf9, 0xff])], - ), - ( - vec![Some(b"cat"), None, Some(&[0xf8, 0xf9, 0xff])], - 2, - None, - vec![Some(b"t"), None, Some(&[0xff])], - ), - ( - vec![Some(b"cat"), None, Some(&[0xf8, 0xf9, 0xff])], - 3, - None, - vec![Some(b""), None, Some(&[])], - ), - ( - vec![Some(b"cat"), None, Some(&[0xf8, 0xf9, 0xff])], - 10, - None, - vec![Some(b""), None, Some(b"")], - ), + (1, None, vec![Some(b"at"), None, Some(&[0xf9, 0xff])]), + (2, None, vec![Some(b"t"), None, Some(&[0xff])]), + (3, None, vec![Some(b""), None, Some(b"")]), + (10, None, vec![Some(b""), None, Some(b"")]), // increase start negatively - ( - vec![Some(b"cat"), None, Some(&[0xf8, 0xf9, 0xff])], - -1, - None, - vec![Some(b"t"), None, Some(&[0xff])], - ), - ( - vec![Some(b"cat"), None, Some(&[0xf8, 0xf9, 0xff])], - -2, - None, - vec![Some(b"at"), None, Some(&[0xf9, 0xff])], - ), - ( - vec![Some(b"cat"), None, Some(&[0xf8, 0xf9, 0xff])], - -3, - None, - vec![Some(b"cat"), None, Some(&[0xf8, 0xf9, 0xff])], - ), - ( - vec![Some(b"cat"), None, Some(&[0xf8, 0xf9, 0xff])], - -10, - None, - vec![Some(b"cat"), None, Some(&[0xf8, 0xf9, 0xff])], - ), + (-1, None, vec![Some(b"t"), None, Some(&[0xff])]), + (-2, None, vec![Some(b"at"), None, Some(&[0xf9, 0xff])]), + (-3, None, input.clone()), + (-10, None, input.clone()), // increase length - ( - vec![Some(b"cat"), None, Some(&[0xf8, 0xf9, 0xff])], - 1, - Some(1), - vec![Some(b"a"), None, Some(&[0xf9])], - ), - ( - vec![Some(b"cat"), None, Some(&[0xf8, 0xf9, 0xff])], - 1, - Some(2), - vec![Some(b"at"), None, Some(&[0xf9, 0xff])], - ), - ( - vec![Some(b"cat"), None, Some(&[0xf8, 0xf9, 0xff])], - 1, - Some(3), - vec![Some(b"at"), None, Some(&[0xf9, 0xff])], - ), - ( - vec![Some(b"cat"), None, Some(&[0xf8, 0xf9, 0xff])], - -3, - Some(1), - vec![Some(b"c"), None, Some(&[0xf8])], - ), - ( - vec![Some(b"cat"), None, Some(&[0xf8, 0xf9, 0xff])], - -3, - Some(2), - vec![Some(b"ca"), None, Some(&[0xf8, 0xf9])], - ), - ( - vec![Some(b"cat"), None, Some(&[0xf8, 0xf9, 0xff])], - -3, - Some(3), - vec![Some(b"cat"), None, Some(&[0xf8, 0xf9, 0xff])], - ), - ( - vec![Some(b"cat"), None, Some(&[0xf8, 0xf9, 0xff])], - -3, - Some(4), - vec![Some(b"cat"), None, Some(&[0xf8, 0xf9, 0xff])], - ), - ]; - - cases.into_iter().try_for_each::<_, Result<()>>( - |(array, start, length, expected)| { - let array = FixedSizeBinaryArray::try_from_sparse_iter(array.into_iter()) - .unwrap(); - let result = substring(&array, start, length)?; - assert_eq!(array.len(), result.len()); - let result = result - .as_any() - .downcast_ref::() - .unwrap(); - let expected = - FixedSizeBinaryArray::try_from_sparse_iter(expected.into_iter()) - .unwrap(); - assert_eq!(&expected, result,); - Ok(()) - }, - )?; - - Ok(()) + (1, Some(1), vec![Some(b"a"), None, Some(&[0xf9])]), + (1, Some(2), vec![Some(b"at"), None, Some(&[0xf9, 0xff])]), + (1, Some(3), vec![Some(b"at"), None, Some(&[0xf9, 0xff])]), + (-3, Some(1), vec![Some(b"c"), None, Some(&[0xf8])]), + (-3, Some(2), vec![Some(b"ca"), None, Some(&[0xf8, 0xf9])]), + (-3, Some(3), input.clone()), + (-3, Some(4), input.clone()) + ); + + do_test!( + [&base_case[..], &cases[..]].concat(), + FixedSizeBinaryArray, + substring + ); } #[test] - #[allow(clippy::type_complexity)] - fn without_nulls_fixed_size_binary() -> Result<()> { - let cases: Vec<(Vec<&[u8]>, i64, Option, Vec<&[u8]>)> = vec![ - // empty array is always identical - (vec![b"", b"", &[]], 3, Some(2), vec![b"", b"", &[]]), + fn without_nulls_fixed_size_binary() { + let input = vec!["cat".as_bytes(), b"dog", &[0xf8, 0xf9, 0xff]]; + // empty array is always identical + let base_case = gen_test_cases!( + vec!["".as_bytes(), &[], &[]], + (1, Some(2), vec!["".as_bytes(), &[], &[]]) + ); + let cases = gen_test_cases!( + input, + // identity + (0, None, input.clone()), // increase start - ( - vec![b"cat", b"dog", &[0xf8, 0xf9, 0xff]], - 0, - None, - vec![b"cat", b"dog", &[0xf8, 0xf9, 0xff]], - ), - ( - vec![b"cat", b"dog", &[0xf8, 0xf9, 0xff]], - 1, - None, - vec![b"at", b"og", &[0xf9, 0xff]], - ), - ( - vec![b"cat", b"dog", &[0xf8, 0xf9, 0xff]], - 2, - None, - vec![b"t", b"g", &[0xff]], - ), - ( - vec![b"cat", b"dog", &[0xf8, 0xf9, 0xff]], - 3, - None, - vec![b"", b"", &[]], - ), - ( - vec![b"cat", b"dog", &[0xf8, 0xf9, 0xff]], - 10, - None, - vec![b"", b"", b""], - ), + (1, None, vec![b"at", b"og", &[0xf9, 0xff]]), + (2, None, vec![b"t", b"g", &[0xff]]), + (3, None, vec![&[], &[], &[]]), + (10, None, vec![&[], &[], &[]]), // increase start negatively - ( - vec![b"cat", b"dog", &[0xf8, 0xf9, 0xff]], - -1, - None, - vec![b"t", b"g", &[0xff]], - ), - ( - vec![b"cat", b"dog", &[0xf8, 0xf9, 0xff]], - -2, - None, - vec![b"at", b"og", &[0xf9, 0xff]], - ), - ( - vec![b"cat", b"dog", &[0xf8, 0xf9, 0xff]], - -3, - None, - vec![b"cat", b"dog", &[0xf8, 0xf9, 0xff]], - ), - ( - vec![b"cat", b"dog", &[0xf8, 0xf9, 0xff]], - -10, - None, - vec![b"cat", b"dog", &[0xf8, 0xf9, 0xff]], - ), + (-1, None, vec![b"t", b"g", &[0xff]]), + (-2, None, vec![b"at", b"og", &[0xf9, 0xff]]), + (-3, None, input.clone()), + (-10, None, input.clone()), // increase length - ( - vec![b"cat", b"dog", &[0xf8, 0xf9, 0xff]], - 1, - Some(1), - vec![b"a", b"o", &[0xf9]], - ), - ( - vec![b"cat", b"dog", &[0xf8, 0xf9, 0xff]], - 1, - Some(2), - vec![b"at", b"og", &[0xf9, 0xff]], - ), - ( - vec![b"cat", b"dog", &[0xf8, 0xf9, 0xff]], - 1, - Some(3), - vec![b"at", b"og", &[0xf9, 0xff]], - ), - ( - vec![b"cat", b"dog", &[0xf8, 0xf9, 0xff]], - -3, - Some(1), - vec![b"c", b"d", &[0xf8]], - ), - ( - vec![b"cat", b"dog", &[0xf8, 0xf9, 0xff]], - -3, - Some(2), - vec![b"ca", b"do", &[0xf8, 0xf9]], - ), - ( - vec![b"cat", b"dog", &[0xf8, 0xf9, 0xff]], - -3, - Some(3), - vec![b"cat", b"dog", &[0xf8, 0xf9, 0xff]], - ), - ( - vec![b"cat", b"dog", &[0xf8, 0xf9, 0xff]], - -3, - Some(4), - vec![b"cat", b"dog", &[0xf8, 0xf9, 0xff]], - ), - ]; - - cases.into_iter().try_for_each::<_, Result<()>>( - |(array, start, length, expected)| { - let array = - FixedSizeBinaryArray::try_from_iter(array.into_iter()).unwrap(); - let result = substring(&array, start, length)?; - assert_eq!(array.len(), result.len()); - let result = result - .as_any() - .downcast_ref::() - .unwrap(); - let expected = - FixedSizeBinaryArray::try_from_iter(expected.into_iter()).unwrap(); - assert_eq!(&expected, result,); - Ok(()) - }, - )?; - - Ok(()) + (1, Some(1), vec![b"a", b"o", &[0xf9]]), + (1, Some(2), vec![b"at", b"og", &[0xf9, 0xff]]), + (1, Some(3), vec![b"at", b"og", &[0xf9, 0xff]]), + (-3, Some(1), vec![b"c", b"d", &[0xf8]]), + (-3, Some(2), vec![b"ca", b"do", &[0xf8, 0xf9]]), + (-3, Some(3), input.clone()), + (-3, Some(4), input.clone()) + ); + + do_test!( + [&base_case[..], &cases[..]].concat(), + FixedSizeBinaryArray, + substring + ); } #[test] - fn fixed_size_binary_with_non_zero_offset() -> Result<()> { + fn fixed_size_binary_with_non_zero_offset() { let values: [u8; 15] = *b"hellotherearrow"; // set the first and third element to be valid let bits_v = [0b101_u8]; @@ -970,7 +710,7 @@ mod tests { // array is `[null, "arrow"]` let array = FixedSizeBinaryArray::from(data); // result is `[null, "rrow"]` - let result = substring(&array, 1, None)?; + let result = substring(&array, 1, None).unwrap(); let result = result .as_any() .downcast_ref::() @@ -980,165 +720,90 @@ mod tests { ) .unwrap(); assert_eq!(result, &expected); - - Ok(()) } - fn with_nulls_generic_string() -> Result<()> { - let cases = vec![ - // all-nulls array is always identical - (vec![None, None, None], 0, None, vec![None, None, None]), + fn with_nulls_generic_string() { + let input = vec![Some("hello"), None, Some("word")]; + // all-nulls array is always identical + let base_case = + gen_test_cases!(vec![None, None, None], (0, None, vec![None, None, None])); + let cases = gen_test_cases!( + input, // identity - ( - vec![Some("hello"), None, Some("word")], - 0, - None, - vec![Some("hello"), None, Some("word")], - ), + (0, None, input.clone()), // 0 length -> Nothing - ( - vec![Some("hello"), None, Some("word")], - 0, - Some(0), - vec![Some(""), None, Some("")], - ), + (0, Some(0), vec![Some(""), None, Some("")]), // high start -> Nothing - ( - vec![Some("hello"), None, Some("word")], - 1000, - Some(0), - vec![Some(""), None, Some("")], - ), + (1000, Some(0), vec![Some(""), None, Some("")]), // high negative start -> identity - ( - vec![Some("hello"), None, Some("word")], - -1000, - None, - vec![Some("hello"), None, Some("word")], - ), + (-1000, None, input.clone()), // high length -> identity - ( - vec![Some("hello"), None, Some("word")], - 0, - Some(1000), - vec![Some("hello"), None, Some("word")], - ), - ]; - - cases.into_iter().try_for_each::<_, Result<()>>( - |(array, start, length, expected)| { - let array = GenericStringArray::::from(array); - let result: ArrayRef = substring(&array, start, length)?; - assert_eq!(array.len(), result.len()); - - let result = result - .as_any() - .downcast_ref::>() - .unwrap(); - let expected = GenericStringArray::::from(expected); - assert_eq!(&expected, result); - Ok(()) - }, - )?; - - Ok(()) + (0, Some(1000), input.clone()) + ); + + do_test!( + [&base_case[..], &cases[..]].concat(), + GenericStringArray, + substring + ); } #[test] - fn with_nulls_string() -> Result<()> { + fn with_nulls_string() { with_nulls_generic_string::() } #[test] - fn with_nulls_large_string() -> Result<()> { + fn with_nulls_large_string() { with_nulls_generic_string::() } - fn without_nulls_generic_string() -> Result<()> { - let cases = vec![ - // empty array is always identical - (vec!["", "", ""], 0, None, vec!["", "", ""]), - // increase start - ( - vec!["hello", "", "word"], - 0, - None, - vec!["hello", "", "word"], - ), - (vec!["hello", "", "word"], 1, None, vec!["ello", "", "ord"]), - (vec!["hello", "", "word"], 2, None, vec!["llo", "", "rd"]), - (vec!["hello", "", "word"], 3, None, vec!["lo", "", "d"]), - (vec!["hello", "", "word"], 10, None, vec!["", "", ""]), + fn without_nulls_generic_string() { + let input = vec!["hello", "", "word"]; + // empty array is always identical + let base_case = gen_test_cases!(vec!["", "", ""], (0, None, vec!["", "", ""])); + let cases = gen_test_cases!( + input, + // identity + (0, None, input.clone()), + (1, None, vec!["ello", "", "ord"]), + (2, None, vec!["llo", "", "rd"]), + (3, None, vec!["lo", "", "d"]), + (10, None, vec!["", "", ""]), // increase start negatively - (vec!["hello", "", "word"], -1, None, vec!["o", "", "d"]), - (vec!["hello", "", "word"], -2, None, vec!["lo", "", "rd"]), - (vec!["hello", "", "word"], -3, None, vec!["llo", "", "ord"]), - ( - vec!["hello", "", "word"], - -10, - None, - vec!["hello", "", "word"], - ), + (-1, None, vec!["o", "", "d"]), + (-2, None, vec!["lo", "", "rd"]), + (-3, None, vec!["llo", "", "ord"]), + (-10, None, input.clone()), // increase length - (vec!["hello", "", "word"], 1, Some(1), vec!["e", "", "o"]), - (vec!["hello", "", "word"], 1, Some(2), vec!["el", "", "or"]), - ( - vec!["hello", "", "word"], - 1, - Some(3), - vec!["ell", "", "ord"], - ), - ( - vec!["hello", "", "word"], - 1, - Some(4), - vec!["ello", "", "ord"], - ), - (vec!["hello", "", "word"], -3, Some(1), vec!["l", "", "o"]), - (vec!["hello", "", "word"], -3, Some(2), vec!["ll", "", "or"]), - ( - vec!["hello", "", "word"], - -3, - Some(3), - vec!["llo", "", "ord"], - ), - ( - vec!["hello", "", "word"], - -3, - Some(4), - vec!["llo", "", "ord"], - ), - ]; - - cases.into_iter().try_for_each::<_, Result<()>>( - |(array, start, length, expected)| { - let array = GenericStringArray::::from(array); - let result = substring(&array, start, length)?; - assert_eq!(array.len(), result.len()); - let result = result - .as_any() - .downcast_ref::>() - .unwrap(); - let expected = GenericStringArray::::from(expected); - assert_eq!(&expected, result,); - Ok(()) - }, - )?; - - Ok(()) + (1, Some(1), vec!["e", "", "o"]), + (1, Some(2), vec!["el", "", "or"]), + (1, Some(3), vec!["ell", "", "ord"]), + (1, Some(4), vec!["ello", "", "ord"]), + (-3, Some(1), vec!["l", "", "o"]), + (-3, Some(2), vec!["ll", "", "or"]), + (-3, Some(3), vec!["llo", "", "ord"]), + (-3, Some(4), vec!["llo", "", "ord"]) + ); + + do_test!( + [&base_case[..], &cases[..]].concat(), + GenericStringArray, + substring + ); } #[test] - fn without_nulls_string() -> Result<()> { + fn without_nulls_string() { without_nulls_generic_string::() } #[test] - fn without_nulls_large_string() -> Result<()> { + fn without_nulls_large_string() { without_nulls_generic_string::() } - fn generic_string_with_non_zero_offset() -> Result<()> { + fn generic_string_with_non_zero_offset() { let values = "hellotherearrow"; let offsets = &[ O::zero(), @@ -1155,150 +820,113 @@ mod tests { .add_buffer(Buffer::from(values)) .null_bit_buffer(Some(Buffer::from(bitmap))) .offset(1) - .build()?; + .build() + .unwrap(); // array is `[null, "arrow"]` let array = GenericStringArray::::from(data); // result is `[null, "rrow"]` - let result = substring(&array, 1, None)?; + let result = substring(&array, 1, None).unwrap(); let result = result .as_any() .downcast_ref::>() .unwrap(); let expected = GenericStringArray::::from(vec![None, Some("rrow")]); assert_eq!(result, &expected); - - Ok(()) } #[test] - fn string_with_non_zero_offset() -> Result<()> { + fn string_with_non_zero_offset() { generic_string_with_non_zero_offset::() } #[test] - fn large_string_with_non_zero_offset() -> Result<()> { + fn large_string_with_non_zero_offset() { generic_string_with_non_zero_offset::() } - fn with_nulls_generic_string_by_char() -> Result<()> { - let input_vals = vec![Some("hello"), None, Some("Γ ⊢x:T")]; - let cases = vec![ - // all-nulls array is always identical - (vec![None, None, None], 0, None, vec![None, None, None]), + fn with_nulls_generic_string_by_char() { + let input = vec![Some("hello"), None, Some("Γ ⊢x:T")]; + // all-nulls array is always identical + let base_case = + gen_test_cases!(vec![None, None, None], (0, None, vec![None, None, None])); + let cases = gen_test_cases!( + input, // identity - ( - input_vals.clone(), - 0, - None, - vec![Some("hello"), None, Some("Γ ⊢x:T")], - ), + (0, None, input.clone()), // 0 length -> Nothing - ( - input_vals.clone(), - 0, - Some(0), - vec![Some(""), None, Some("")], - ), + (0, Some(0), vec![Some(""), None, Some("")]), // high start -> Nothing - ( - input_vals.clone(), - 1000, - Some(0), - vec![Some(""), None, Some("")], - ), + (1000, Some(0), vec![Some(""), None, Some("")]), // high negative start -> identity - ( - input_vals.clone(), - -1000, - None, - vec![Some("hello"), None, Some("Γ ⊢x:T")], - ), + (-1000, None, input.clone()), // high length -> identity - ( - input_vals.clone(), - 0, - Some(1000), - vec![Some("hello"), None, Some("Γ ⊢x:T")], - ), - ]; - - cases.into_iter().try_for_each::<_, Result<()>>( - |(array, start, length, expected)| { - let array = GenericStringArray::::from(array); - let result = substring_by_char(&array, start, length)?; - assert_eq!(array.len(), result.len()); - - let expected = GenericStringArray::::from(expected); - assert_eq!(expected, result); - Ok(()) - }, - )?; - - Ok(()) + (0, Some(1000), input.clone()) + ); + + do_test!( + [&base_case[..], &cases[..]].concat(), + GenericStringArray, + substring_by_char + ); } #[test] - fn with_nulls_string_by_char() -> Result<()> { + fn with_nulls_string_by_char() { with_nulls_generic_string_by_char::() } #[test] - fn with_nulls_large_string_by_char() -> Result<()> { + fn with_nulls_large_string_by_char() { with_nulls_generic_string_by_char::() } - fn without_nulls_generic_string_by_char() -> Result<()> { - let input_vals = vec!["hello", "", "Γ ⊢x:T"]; - let cases = vec![ - // empty array is always identical - (vec!["", "", ""], 0, None, vec!["", "", ""]), + fn without_nulls_generic_string_by_char() { + let input = vec!["hello", "", "Γ ⊢x:T"]; + // empty array is always identical + let base_case = gen_test_cases!(vec!["", "", ""], (0, None, vec!["", "", ""])); + let cases = gen_test_cases!( + input, + //identity + (0, None, input.clone()), // increase start - (input_vals.clone(), 0, None, vec!["hello", "", "Γ ⊢x:T"]), - (input_vals.clone(), 1, None, vec!["ello", "", " ⊢x:T"]), - (input_vals.clone(), 2, None, vec!["llo", "", "⊢x:T"]), - (input_vals.clone(), 3, None, vec!["lo", "", "x:T"]), - (input_vals.clone(), 10, None, vec!["", "", ""]), + (1, None, vec!["ello", "", " ⊢x:T"]), + (2, None, vec!["llo", "", "⊢x:T"]), + (3, None, vec!["lo", "", "x:T"]), + (10, None, vec!["", "", ""]), // increase start negatively - (input_vals.clone(), -1, None, vec!["o", "", "T"]), - (input_vals.clone(), -2, None, vec!["lo", "", ":T"]), - (input_vals.clone(), -4, None, vec!["ello", "", "⊢x:T"]), - (input_vals.clone(), -10, None, vec!["hello", "", "Γ ⊢x:T"]), + (-1, None, vec!["o", "", "T"]), + (-2, None, vec!["lo", "", ":T"]), + (-4, None, vec!["ello", "", "⊢x:T"]), + (-10, None, input.clone()), // increase length - (input_vals.clone(), 1, Some(1), vec!["e", "", " "]), - (input_vals.clone(), 1, Some(2), vec!["el", "", " ⊢"]), - (input_vals.clone(), 1, Some(3), vec!["ell", "", " ⊢x"]), - (input_vals.clone(), 1, Some(6), vec!["ello", "", " ⊢x:T"]), - (input_vals.clone(), -4, Some(1), vec!["e", "", "⊢"]), - (input_vals.clone(), -4, Some(2), vec!["el", "", "⊢x"]), - (input_vals.clone(), -4, Some(3), vec!["ell", "", "⊢x:"]), - (input_vals.clone(), -4, Some(4), vec!["ello", "", "⊢x:T"]), - ]; - - cases.into_iter().try_for_each::<_, Result<()>>( - |(array, start, length, expected)| { - let array = GenericStringArray::::from(array); - let result = substring_by_char(&array, start, length)?; - assert_eq!(array.len(), result.len()); - let expected = GenericStringArray::::from(expected); - assert_eq!(expected, result); - Ok(()) - }, - )?; - - Ok(()) + (1, Some(1), vec!["e", "", " "]), + (1, Some(2), vec!["el", "", " ⊢"]), + (1, Some(3), vec!["ell", "", " ⊢x"]), + (1, Some(6), vec!["ello", "", " ⊢x:T"]), + (-4, Some(1), vec!["e", "", "⊢"]), + (-4, Some(2), vec!["el", "", "⊢x"]), + (-4, Some(3), vec!["ell", "", "⊢x:"]), + (-4, Some(4), vec!["ello", "", "⊢x:T"]) + ); + + do_test!( + [&base_case[..], &cases[..]].concat(), + GenericStringArray, + substring_by_char + ); } #[test] - fn without_nulls_string_by_char() -> Result<()> { + fn without_nulls_string_by_char() { without_nulls_generic_string_by_char::() } #[test] - fn without_nulls_large_string_by_char() -> Result<()> { + fn without_nulls_large_string_by_char() { without_nulls_generic_string_by_char::() } - fn generic_string_by_char_with_non_zero_offset() -> Result<()> { + fn generic_string_by_char_with_non_zero_offset() { let values = "S→T = Πx:S.T"; let offsets = &[ O::zero(), @@ -1317,41 +945,39 @@ mod tests { .add_buffer(Buffer::from(values)) .null_bit_buffer(Some(Buffer::from(bitmap))) .offset(1) - .build()?; + .build() + .unwrap(); // array is `[null, "Πx:S.T"]` let array = GenericStringArray::::from(data); // result is `[null, "x:S.T"]` - let result = substring_by_char(&array, 1, None)?; + let result = substring_by_char(&array, 1, None).unwrap(); let expected = GenericStringArray::::from(vec![None, Some("x:S.T")]); assert_eq!(result, expected); - - Ok(()) } #[test] - fn string_with_non_zero_offset_by_char() -> Result<()> { + fn string_with_non_zero_offset_by_char() { generic_string_by_char_with_non_zero_offset::() } #[test] - fn large_string_with_non_zero_offset_by_char() -> Result<()> { + fn large_string_with_non_zero_offset_by_char() { generic_string_by_char_with_non_zero_offset::() } #[test] - fn dictionary() -> Result<()> { - _dictionary::()?; - _dictionary::()?; - _dictionary::()?; - _dictionary::()?; - _dictionary::()?; - _dictionary::()?; - _dictionary::()?; - _dictionary::()?; - Ok(()) + fn dictionary() { + _dictionary::(); + _dictionary::(); + _dictionary::(); + _dictionary::(); + _dictionary::(); + _dictionary::(); + _dictionary::(); + _dictionary::(); } - fn _dictionary() -> Result<()> { + fn _dictionary() { const TOTAL: i32 = 100; let v = ["aaa", "bbb", "ccc", "ddd", "eee"]; @@ -1371,7 +997,7 @@ mod tests { let expected: Vec> = data.iter().map(|opt| opt.map(|s| &s[1..3])).collect(); - let res = substring(&dict_array, 1, Some(2))?; + let res = substring(&dict_array, 1, Some(2)).unwrap(); let actual = res.as_any().downcast_ref::>().unwrap(); let actual: Vec> = actual .values() @@ -1384,8 +1010,6 @@ mod tests { for i in 0..TOTAL as usize { assert_eq!(expected[i], actual[i],); } - - Ok(()) } #[test]