#![allow(clippy::cast_possible_truncation)]
use std::collections::HashMap;
use ferray_core::Dimension;
use ferray_core::dimension::{Ix1, IxDyn};
use ferray_strings::{self, StringArray, StringArray1, StringArray2};
#[test]
fn array_ctor_and_aliases_link() {
let a: StringArray1 = ferray_strings::array(&["hello", "world"]).unwrap();
assert_eq!(a.len(), 2);
let _b: StringArray<Ix1> = ferray_strings::array(&["x"]).unwrap();
let _c: StringArray2 = StringArray2::from_rows(&[&["a", "b"]]).unwrap();
}
#[test]
fn basic_accessors_match_construction() {
let dim = Ix1::new([3]);
let mut a: StringArray<Ix1> =
StringArray::from_vec(dim, vec!["a".into(), "b".into(), "c".into()]).unwrap();
assert_eq!(a.shape(), &[3]);
assert_eq!(a.ndim(), 1);
assert_eq!(a.len(), 3);
assert!(!a.is_empty());
assert_eq!(a.dim().as_slice(), &[3]);
assert_eq!(a.as_slice()[0], "a");
a.as_slice_mut()[0] = "A".to_string();
let collected: Vec<&str> = a.iter().map(String::as_str).collect();
assert_eq!(collected, vec!["A", "b", "c"]);
let empty: StringArray<Ix1> = StringArray::empty(Ix1::new([0])).unwrap();
assert!(empty.is_empty());
let v: Vec<String> = empty.into_vec();
assert!(v.is_empty());
}
#[test]
fn shape_aware_helpers() {
let a: StringArray1 = StringArray1::from_slice(&["x", "y", "z"]).unwrap();
assert_eq!(a.at(1), Some(&"y".to_string()));
assert_eq!(a.get(&[2]), Some(&"z".to_string()));
let m: StringArray2 = StringArray2::from_rows(&[&["a", "b"], &["c", "d"]]).unwrap();
let row = m.get_row(1).unwrap();
assert_eq!(row.as_slice(), &["c", "d"]);
let t = m.transpose().unwrap();
assert_eq!(t.as_slice(), &["a", "c", "b", "d"]);
let sl = m.slice_axis(0, 1..2).unwrap();
assert_eq!(sl.as_slice(), &["c", "d"]);
let d: StringArray<IxDyn> =
StringArray::<IxDyn>::from_vec_dyn(&[2, 1], vec!["p".into(), "q".into()]).unwrap();
assert_eq!(d.shape(), &[2, 1]);
}
#[test]
fn map_reshape_flatten_into_dyn() {
let a = ferray_strings::array(&["ab", "cd"]).unwrap();
let upper = a.map(|s| s.to_uppercase()).unwrap();
assert_eq!(upper.as_slice(), &["AB", "CD"]);
let lens: Vec<usize> = a.map_to_vec(str::len);
assert_eq!(lens, vec![2, 2]);
let m = StringArray2::from_rows(&[&["a", "b"], &["c", "d"]]).unwrap();
let r = m.clone().reshape(Ix1::new([4])).unwrap();
assert_eq!(r.as_slice(), &["a", "b", "c", "d"]);
let f: StringArray1 = StringArray2::from_rows(&[&["a", "b"], &["c", "d"]])
.unwrap()
.flatten();
assert_eq!(f.as_slice(), &["a", "b", "c", "d"]);
let dyn_arr: StringArray<IxDyn> = ferray_strings::array(&["x"]).unwrap().into_dyn();
assert_eq!(dyn_arr.shape(), &[1]);
}
#[test]
fn encode_decode_round_trip() {
let a = ferray_strings::array(&["hello", "café"]).unwrap();
let bytes = ferray_strings::encode(&a, "utf-8").unwrap();
assert_eq!(bytes[0], b"hello");
let back = ferray_strings::decode(&bytes, a.dim().clone(), "utf-8").unwrap();
assert_eq!(back.as_slice(), a.as_slice());
}
#[test]
fn expandtabs_expands_to_column_boundary() {
let a = ferray_strings::array(&["a\tb", "ab\tc"]).unwrap();
let out = ferray_strings::expandtabs(&a, 4).unwrap();
assert_eq!(out.as_slice(), &["a b", "ab c"]);
}
#[test]
fn mod_substitutes_printf_specs() {
let a = ferray_strings::array(&["x=%s, n=%d"]).unwrap();
let out = ferray_strings::mod_(&a, &["foo", "42"]).unwrap();
assert_eq!(out.as_slice(), &["x=foo, n=42"]);
}
#[test]
fn partition_splits_on_first_sep() {
let a = ferray_strings::array(&["a:b:c", "noSep"]).unwrap();
let out = ferray_strings::partition(&a, ":").unwrap();
assert_eq!(out[0], ("a".into(), ":".into(), "b:c".into()));
assert_eq!(out[1], ("noSep".into(), String::new(), String::new()));
}
#[test]
fn rpartition_splits_on_last_sep() {
let a = ferray_strings::array(&["a:b:c", "noSep"]).unwrap();
let out = ferray_strings::rpartition(&a, ":").unwrap();
assert_eq!(out[0], ("a:b".into(), ":".into(), "c".into()));
assert_eq!(out[1], (String::new(), String::new(), "noSep".into()));
}
#[test]
fn slice_supports_python_negative_indices() {
let a = ferray_strings::array(&["hello", "abc"]).unwrap();
let out = ferray_strings::slice(&a, Some(1), Some(-1)).unwrap();
assert_eq!(out.as_slice(), &["ell", "b"]);
}
#[test]
fn translate_replaces_and_drops_chars() {
let mut table: HashMap<char, Option<char>> = HashMap::new();
table.insert('a', Some('A'));
table.insert('b', None);
let a = ferray_strings::array(&["abcab", "bbb"]).unwrap();
let out = ferray_strings::translate(&a, &table).unwrap();
assert_eq!(out.as_slice(), &["AcA", ""]);
}
#[cfg(feature = "compact-storage")]
mod compact_tests {
use super::*;
use ferray_strings::compact::{
CompactStringArray, CompactStringIter, estimated_string_array_bytes,
};
#[test]
fn compact_round_trip_through_strs() {
let xs = ["hello", "", "world"];
let c: CompactStringArray = CompactStringArray::from_strs(&xs);
assert_eq!(c.len(), 3);
assert!(!c.is_empty());
assert_eq!(c.as_str(0), Some("hello"));
assert_eq!(c.as_str(1), Some(""));
assert_eq!(c.total_bytes(), 10);
assert_eq!(c.data(), b"helloworld");
assert_eq!(c.offsets(), &[0, 5, 5, 10]);
let c2: CompactStringArray = CompactStringArray::from_iter_str(xs.iter().copied());
assert_eq!(c2.len(), 3);
}
#[test]
fn compact_interop_with_string_array() {
let arr = ferray_strings::array(&["alpha", "beta"]).unwrap();
let c = CompactStringArray::from_string_array(&arr);
let back = c.to_string_array().unwrap();
assert_eq!(back.as_slice(), arr.as_slice());
let iter: CompactStringIter = c.iter();
let collected: Vec<&str> = iter.collect();
assert_eq!(collected, vec!["alpha", "beta"]);
let raw = CompactStringArray::from_raw_parts(b"abc".to_vec(), vec![0, 1, 3]).unwrap();
assert_eq!(raw.as_str(0), Some("a"));
assert_eq!(raw.as_str(1), Some("bc"));
let _bytes_owned = c.estimated_bytes();
let strs: Vec<String> = vec!["x".into(), "yz".into()];
let _est = estimated_string_array_bytes(&strs);
}
}