#![cfg(all(feature = "wal2json", feature = "pg-walstream", feature = "maxwell"))]
extern crate alloc;
use alloc::string::String;
use alloc::vec::Vec;
use bytes::Bytes;
use sqlite_diff_rs::maxwell::{Maxwell, MaxwellColumn};
use sqlite_diff_rs::pg_walstream::{ColumnValue, PgWalstream, PgWalstreamColumn};
use sqlite_diff_rs::wal2json::{Wal2Json, Wal2JsonColumn};
use sqlite_diff_rs::{
DecodeError, Int64OverflowToTextDecoder, IntDecoder, TypeMap, Value, WireAdapter,
};
#[test]
fn int_decoder_pg_walstream_text_positive_and_negative() {
let cv_pos = ColumnValue::text("42");
let cv_neg = ColumnValue::text("-17");
let got_pos: Value<String, Vec<u8>> = PgWalstreamColumn {
column_name: "n",
oid: 23,
type_modifier: -1,
data: &cv_pos,
}
.decoded_by(&IntDecoder)
.unwrap();
let got_neg: Value<String, Vec<u8>> = PgWalstreamColumn {
column_name: "n",
oid: 23,
type_modifier: -1,
data: &cv_neg,
}
.decoded_by(&IntDecoder)
.unwrap();
assert_eq!(got_pos, Value::Integer(42));
assert_eq!(got_neg, Value::Integer(-17));
}
#[test]
fn int_decoder_pg_walstream_text_i64_bounds() {
let cv_max = ColumnValue::text("9223372036854775807"); let cv_min = ColumnValue::text("-9223372036854775808"); let cv_over = ColumnValue::text("9223372036854775808");
let got_max: Value<String, Vec<u8>> = PgWalstreamColumn {
column_name: "n",
oid: 20,
type_modifier: -1,
data: &cv_max,
}
.decoded_by(&IntDecoder)
.unwrap();
let got_min: Value<String, Vec<u8>> = PgWalstreamColumn {
column_name: "n",
oid: 20,
type_modifier: -1,
data: &cv_min,
}
.decoded_by(&IntDecoder)
.unwrap();
assert_eq!(got_max, Value::Integer(i64::MAX));
assert_eq!(got_min, Value::Integer(i64::MIN));
let result: Result<Value<String, Vec<u8>>, _> = PgWalstreamColumn {
column_name: "n",
oid: 20,
type_modifier: -1,
data: &cv_over,
}
.decoded_by(&IntDecoder);
assert!(matches!(
result.unwrap_err(),
DecodeError::IntegerOverflow { .. }
));
}
#[test]
fn int_decoder_pg_walstream_binary_int2_int4_int8() {
let two = 12345_i16.to_be_bytes();
let cv_two = ColumnValue::binary_bytes(Bytes::copy_from_slice(&two));
let got: Value<String, Vec<u8>> = PgWalstreamColumn {
column_name: "n",
oid: 21,
type_modifier: -1,
data: &cv_two,
}
.decoded_by(&IntDecoder)
.unwrap();
assert_eq!(got, Value::Integer(12345));
let four = 1_234_567_i32.to_be_bytes();
let cv_four = ColumnValue::binary_bytes(Bytes::copy_from_slice(&four));
let got: Value<String, Vec<u8>> = PgWalstreamColumn {
column_name: "n",
oid: 23,
type_modifier: -1,
data: &cv_four,
}
.decoded_by(&IntDecoder)
.unwrap();
assert_eq!(got, Value::Integer(1_234_567));
let eight = 42_000_000_000_i64.to_be_bytes();
let cv_eight = ColumnValue::binary_bytes(Bytes::copy_from_slice(&eight));
let got: Value<String, Vec<u8>> = PgWalstreamColumn {
column_name: "n",
oid: 20,
type_modifier: -1,
data: &cv_eight,
}
.decoded_by(&IntDecoder)
.unwrap();
assert_eq!(got, Value::Integer(42_000_000_000));
}
#[test]
fn int_decoder_pg_walstream_null() {
let cv = ColumnValue::Null;
let got: Value<String, Vec<u8>> = PgWalstreamColumn {
column_name: "n",
oid: 23,
type_modifier: -1,
data: &cv,
}
.decoded_by(&IntDecoder)
.unwrap();
assert_eq!(got, Value::Null);
}
#[test]
fn int_decoder_pg_walstream_rejects_non_int_text() {
let cv = ColumnValue::text("hello");
let result: Result<Value<String, Vec<u8>>, _> = PgWalstreamColumn {
column_name: "n",
oid: 23,
type_modifier: -1,
data: &cv,
}
.decoded_by(&IntDecoder);
assert!(matches!(
result.unwrap_err(),
DecodeError::WrongPayloadKind { .. }
));
}
#[test]
fn int_decoder_wal2json_valid_i64() {
let n = serde_json::Value::Number(42.into());
let got: Value<String, Vec<u8>> = Wal2JsonColumn {
column_name: "n",
pg_type_name: "integer",
value: &n,
}
.decoded_by(&IntDecoder)
.unwrap();
assert_eq!(got, Value::Integer(42));
}
#[test]
fn int_decoder_wal2json_null() {
let n = serde_json::Value::Null;
let got: Value<String, Vec<u8>> = Wal2JsonColumn {
column_name: "n",
pg_type_name: "integer",
value: &n,
}
.decoded_by(&IntDecoder)
.unwrap();
assert_eq!(got, Value::Null);
}
#[test]
fn int_decoder_wal2json_rejects_non_number() {
let s = serde_json::Value::String("42".into());
let result: Result<Value<String, Vec<u8>>, _> = Wal2JsonColumn {
column_name: "n",
pg_type_name: "integer",
value: &s,
}
.decoded_by(&IntDecoder);
assert!(matches!(
result.unwrap_err(),
DecodeError::WrongPayloadKind { .. }
));
}
#[test]
fn int_decoder_maxwell_valid_i64() {
let n = serde_json::Value::Number((-9999_i64).into());
let got: Value<String, Vec<u8>> = MaxwellColumn {
column_name: "n",
mysql_type: Some("int"),
value: &n,
}
.decoded_by(&IntDecoder)
.unwrap();
assert_eq!(got, Value::Integer(-9999));
}
#[test]
fn overflow_decoder_fits_i64_maxwell() {
let at_max = serde_json::Value::Number(i64::MAX.into());
let got: Value<String, Vec<u8>> = MaxwellColumn {
column_name: "big",
mysql_type: Some("bigint unsigned"),
value: &at_max,
}
.decoded_by(&Int64OverflowToTextDecoder)
.unwrap();
assert_eq!(got, Value::Integer(i64::MAX));
}
#[test]
fn overflow_decoder_overflows_to_text_maxwell() {
let over_json = serde_json::from_str::<serde_json::Value>("9223372036854775808").unwrap();
let got: Value<String, Vec<u8>> = MaxwellColumn {
column_name: "big",
mysql_type: Some("bigint unsigned"),
value: &over_json,
}
.decoded_by(&Int64OverflowToTextDecoder)
.unwrap();
assert_eq!(got, Value::Text(String::from("9223372036854775808")));
let very_large = serde_json::from_str::<serde_json::Value>("18000000000000000000").unwrap();
let got: Value<String, Vec<u8>> = MaxwellColumn {
column_name: "big",
mysql_type: Some("bigint unsigned"),
value: &very_large,
}
.decoded_by(&Int64OverflowToTextDecoder)
.unwrap();
assert_eq!(got, Value::Text(String::from("18000000000000000000")));
}
#[test]
fn overflow_decoder_null() {
let n = serde_json::Value::Null;
let got: Value<String, Vec<u8>> = MaxwellColumn {
column_name: "big",
mysql_type: Some("bigint unsigned"),
value: &n,
}
.decoded_by(&Int64OverflowToTextDecoder)
.unwrap();
assert_eq!(got, Value::Null);
}
#[test]
fn type_map_defaults_route_int_types() {
let pg: TypeMap<PgWalstream, String, Vec<u8>> = TypeMap::defaults();
let w2j: TypeMap<Wal2Json, String, Vec<u8>> = TypeMap::defaults();
let mx: TypeMap<Maxwell, String, Vec<u8>> = TypeMap::defaults();
let cv = ColumnValue::text("12345");
let got = pg
.decode(PgWalstreamColumn {
column_name: "n",
oid: 23,
type_modifier: -1,
data: &cv,
})
.unwrap();
assert_eq!(got, Value::Integer(12345));
let json = serde_json::Value::Number(12345.into());
let got = w2j
.decode(Wal2JsonColumn {
column_name: "n",
pg_type_name: "integer",
value: &json,
})
.unwrap();
assert_eq!(got, Value::Integer(12345));
let got = mx
.decode(MaxwellColumn {
column_name: "n",
mysql_type: Some("int"),
value: &json,
})
.unwrap();
assert_eq!(got, Value::Integer(12345));
let over = serde_json::from_str::<serde_json::Value>("9223372036854775808").unwrap();
let got = mx
.decode(MaxwellColumn {
column_name: "big",
mysql_type: Some("bigint unsigned"),
value: &over,
})
.unwrap();
assert_eq!(got, Value::Text(String::from("9223372036854775808")));
}