use super::*;
use crate::matrix::test_support::{scratch, write_gz_members};
fn mtx_text(nrow: usize, ncol: usize, triplets: &[(u64, u64, f32)]) -> String {
let mut s = String::from("%%MatrixMarket matrix coordinate real general\n");
s.push_str(&format!("{}\t{}\t{}\n", nrow, ncol, triplets.len()));
for &(r, c, v) in triplets {
s.push_str(&format!("{}\t{}\t{}\n", r + 1, c + 1, v));
}
s
}
fn sample() -> Vec<(u64, u64, f32)> {
vec![
(0, 0, 1.0),
(3, 0, 2.0),
(1, 1, 3.0),
(4, 2, 4.0),
(2, 3, 5.0),
(0, 3, 6.0),
]
}
#[test]
fn triplets_come_back_in_file_order_with_the_shape() {
let dir = tempfile::tempdir().unwrap();
let f = scratch(&dir, "m.mtx", &mtx_text(5, 4, &sample()));
let (got, shape) = read_mtx_triplets(&f).unwrap();
assert_eq!(shape, (5, 4, 6));
assert_eq!(got, sample());
}
#[test]
fn every_gzip_framing_keeps_every_triplet() {
for (members, bgzf_extra) in [(1, false), (3, false), (3, true)] {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("m.mtx.gz");
write_gz_members(&path, &mtx_text(5, 4, &sample()), members, bgzf_extra);
let (got, shape) = read_mtx_triplets(path.to_str().unwrap()).unwrap();
assert_eq!(shape, (5, 4, 6));
assert_eq!(got, sample(), "members={members} bgzf_extra={bgzf_extra}");
}
}
#[test]
fn a_body_shorter_than_the_declared_nnz_is_an_error() {
let dir = tempfile::tempdir().unwrap();
let mut text = mtx_text(5, 4, &sample());
let cut = text.find("2\t2\t3").expect("third entry");
text.truncate(cut);
let f = scratch(&dir, "short.mtx", &text);
let err = read_mtx_triplets(&f).expect_err("a short body must not parse");
let msg = err.to_string();
assert!(
msg.contains('6'),
"error should name the declared count: {msg}"
);
}
#[test]
fn a_body_longer_than_the_declared_nnz_is_an_error() {
let dir = tempfile::tempdir().unwrap();
let text = mtx_text(5, 4, &sample()) + "5\t4\t7.0\n";
let f = scratch(&dir, "long.mtx", &text);
read_mtx_triplets(&f).expect_err("a long body must not parse");
}
#[test]
fn a_malformed_triplet_line_is_an_error() {
let dir = tempfile::tempdir().unwrap();
let text = mtx_text(5, 4, &sample()).replace("2\t2\t3", "2\tx\t3");
let f = scratch(&dir, "bad.mtx", &text);
read_mtx_triplets(&f).expect_err("a malformed line must not parse");
}
#[test]
fn an_entry_outside_the_declared_shape_is_an_error() {
let dir = tempfile::tempdir().unwrap();
for bad in ["0\t1\t1", "6\t1\t1", "1\t5\t1"] {
let text = mtx_text(5, 4, &sample()).replace("1\t1\t1", bad);
let f = scratch(&dir, "oob.mtx", &text);
read_mtx_triplets(&f).expect_err(bad);
}
}
#[test]
fn comments_and_blank_lines_in_the_body_are_skipped() {
let dir = tempfile::tempdir().unwrap();
let text = mtx_text(5, 4, &sample()).replace("2\t2\t3", "% a note\n\n2\t2\t3");
let f = scratch(&dir, "cmt.mtx", &text);
let (got, _) = read_mtx_triplets(&f).unwrap();
assert_eq!(got, sample());
}