diff --git a/src/connector/codec/tests/integration_tests/avro.rs b/src/connector/codec/tests/integration_tests/avro.rs index ce46beacdb363..e3892635e6188 100644 --- a/src/connector/codec/tests/integration_tests/avro.rs +++ b/src/connector/codec/tests/integration_tests/avro.rs @@ -71,6 +71,7 @@ struct Config { /// ## Why test schema mapping and data mapping together? /// /// Because the expected data type for data mapping comes from the schema mapping. +#[track_caller] fn check( avro_schema: &str, avro_data: &[&str], @@ -108,16 +109,18 @@ fn check( .expect("failed to parse Avro data"); let access = AvroAccess::new(&avro_data, parser); + let mut row = vec![]; for col in &rw_schema { let rw_data = access .access(&[&col.name], &col.data_type) .expect("failed to access"); - data_str.push(format!("{:?}", rw_data)); + row.push(format!("{:#?}", DatumCowTestDisplay(&rw_data))); } + data_str.push(format!("{}", row.iter().format("\n"))); } } } - expected_risingwave_data.assert_eq(&format!("{}", data_str.iter().format("\n"))); + expected_risingwave_data.assert_eq(&format!("{}", data_str.iter().format("\n----\n"))); } #[test] @@ -215,17 +218,17 @@ fn test_simple() { bytes(#11): Bytea, ]"#]], expect![[r#" - Owned(Some(Int32(32))) - Owned(Some(Int64(64))) - Borrowed(Some(Utf8("str_value"))) - Owned(Some(Float32(OrderedFloat(32.0)))) - Owned(Some(Float64(OrderedFloat(64.0)))) - Owned(Some(Bool(true))) - Owned(Some(Date(Date(1970-01-01)))) - Owned(Some(Timestamptz(Timestamptz(0)))) - Owned(Some(Timestamptz(Timestamptz(0)))) - Owned(Some(Interval(Interval { months: 1, days: 1, usecs: 1000000 }))) - Borrowed(Some(Bytea([1, 2, 3, 4, 5])))"#]], + Owned(Int32(32)) + Owned(Int64(64)) + Borrowed(Utf8("str_value")) + Owned(Float32(OrderedFloat(32.0))) + Owned(Float64(OrderedFloat(64.0))) + Owned(Bool(true)) + Owned(Date(Date(1970-01-01))) + Owned(Timestamptz(Timestamptz(0))) + Owned(Timestamptz(Timestamptz(0))) + Owned(Interval(Interval { months: 1, days: 1, usecs: 1000000 })) + Borrowed(Bytea([1, 2, 3, 4, 5]))"#]], ) } @@ -389,25 +392,25 @@ fn test_1() { UNIT_INFO(#8): Varchar, UPD_TIME(#9): Varchar, DEC_VAL(#10): Decimal, - REFERRED(#11): Struct(StructType { field_names: ["a"], field_types: [Varchar] }), - REF(#12): Struct(StructType { field_names: ["a"], field_types: [Varchar] }), + REFERRED(#11): Struct { a: Varchar }, + REF(#12): Struct { a: Varchar }, uuid(#13): Varchar, rate(#14): Float64, ]"#]], expect![[r#" - Borrowed(Some(Utf8("update"))) - Borrowed(Some(Utf8("id1"))) - Borrowed(Some(Utf8("1"))) - Borrowed(Some(Utf8("6768"))) - Borrowed(Some(Utf8("6970"))) - Borrowed(Some(Utf8("value9"))) - Borrowed(Some(Utf8("7172"))) - Borrowed(Some(Utf8("info9"))) - Borrowed(Some(Utf8("2021-05-18T07:59:58.714Z"))) - Owned(Some(Decimal(Normalized(99999999.99)))) - Owned(None) - Owned(None) - Owned(None) - Owned(Some(Float64(OrderedFloat(NaN))))"#]], + Borrowed(Utf8("update")) + Borrowed(Utf8("id1")) + Borrowed(Utf8("1")) + Borrowed(Utf8("6768")) + Borrowed(Utf8("6970")) + Borrowed(Utf8("value9")) + Borrowed(Utf8("7172")) + Borrowed(Utf8("info9")) + Borrowed(Utf8("2021-05-18T07:59:58.714Z")) + Owned(Decimal(Normalized(99999999.99))) + Owned(null) + Owned(null) + Owned(null) + Owned(Float64(OrderedFloat(NaN)))"#]], ); } diff --git a/src/connector/codec/tests/integration_tests/utils.rs b/src/connector/codec/tests/integration_tests/utils.rs index 966bebbfd61ce..a33f17277a875 100644 --- a/src/connector/codec/tests/integration_tests/utils.rs +++ b/src/connector/codec/tests/integration_tests/utils.rs @@ -15,8 +15,127 @@ pub use expect_test::{expect, Expect}; pub use itertools::Itertools; pub use risingwave_common::catalog::ColumnDesc; +use risingwave_common::types::{ + DataType, Datum, DatumCow, DatumRef, ScalarImpl, ScalarRefImpl, ToDatumRef, +}; use risingwave_pb::plan_common::AdditionalColumn; +/// More concise display for `DataType`, to use in tests. +pub struct DataTypeTestDisplay<'a>(pub &'a DataType); + +impl<'a> std::fmt::Debug for DataTypeTestDisplay<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.0 { + DataType::Struct(s) => { + // since this is for tests, we don't care about perf here :) + if !f.alternate() || s.len() == 1 { + let (name, ty) = s.iter().next().unwrap(); + return write!(f, "Struct {{ {}: {:?} }}", name, &DataTypeTestDisplay(ty)); + } + + let mut f = f.debug_struct("Struct"); + for (name, ty) in s.iter() { + f.field(name, &DataTypeTestDisplay(ty)); + } + f.finish()?; + Ok(()) + } + DataType::List(t) => f + .debug_tuple("List") + .field(&DataTypeTestDisplay(t)) + .finish(), + _ => { + // do not use alternative display for simple types + write!(f, "{:?}", self.0) + } + } + } +} + +/// More concise display for `ScalarRefImpl`, to use in tests. +pub struct ScalarRefImplTestDisplay<'a>(pub ScalarRefImpl<'a>); + +impl<'a> std::fmt::Debug for ScalarRefImplTestDisplay<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.0 { + ScalarRefImpl::Struct(s) => { + // since this is for tests, we don't care about perf here :) + if !f.alternate() || s.iter_fields_ref().len() == 1 { + let field = s.iter_fields_ref().next().unwrap(); + return write!(f, "StructValue({:#?})", &DatumRefTestDisplay(field)); + } + + let mut f = f.debug_tuple("StructValue"); + for field in s.iter_fields_ref() { + f.field(&DatumRefTestDisplay(field)); + } + f.finish()?; + Ok(()) + } + ScalarRefImpl::List(l) => f + .debug_list() + .entries(l.iter().map(DatumRefTestDisplay)) + .finish(), + _ => { + // do not use alternative display for simple types + write!(f, "{:?}", self.0) + } + } + } +} + +/// More concise display for `ScalarImpl`, to use in tests. +pub struct ScalarImplTestDisplay<'a>(pub &'a ScalarImpl); + +impl<'a> std::fmt::Debug for ScalarImplTestDisplay<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + ScalarRefImplTestDisplay(self.0.as_scalar_ref_impl()).fmt(f) + } +} + +/// More concise display for `DatumRef`, to use in tests. +pub struct DatumRefTestDisplay<'a>(pub DatumRef<'a>); + +impl<'a> std::fmt::Debug for DatumRefTestDisplay<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.0 { + Some(scalar) => ScalarRefImplTestDisplay(scalar).fmt(f), + None => write!(f, "null"), + } + } +} + +/// More concise display for `Datum`, to use in tests. +pub struct DatumTestDisplay<'a>(pub &'a Datum); + +impl<'a> std::fmt::Debug for DatumTestDisplay<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + DatumRefTestDisplay(self.0.to_datum_ref()).fmt(f) + } +} + +/// More concise display for `DatumCow`, to use in tests. +pub struct DatumCowTestDisplay<'a>(pub &'a DatumCow<'a>); + +impl<'a> std::fmt::Debug for DatumCowTestDisplay<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.0 { + DatumCow::Borrowed(datum_ref) => { + // don't use debug_tuple to avoid extra newline + write!(f, "Borrowed(")?; + DatumRefTestDisplay(*datum_ref).fmt(f)?; + write!(f, ")")?; + } + DatumCow::Owned(datum) => { + write!(f, "Owned(")?; + DatumTestDisplay(datum).fmt(f)?; + write!(f, ")")?; + } + } + Ok(()) + } +} + /// More concise display for `ColumnDesc`, to use in tests. pub struct ColumnDescTestDisplay<'a>(pub &'a ColumnDesc); @@ -34,9 +153,13 @@ impl<'a> std::fmt::Debug for ColumnDescTestDisplay<'a> { version: _, } = &self.0; - write!(f, "{name}(#{column_id}): {data_type:?}")?; + write!( + f, + "{name}(#{column_id}): {:#?}", + DataTypeTestDisplay(data_type) + )?; if !type_name.is_empty() { - write!(f, ", type_name: {:?}", type_name)?; + write!(f, ", type_name: {}", type_name)?; } if !field_descs.is_empty() { write!(f, ", field_descs: {:?}", field_descs)?;