Skip to content

Commit 9fd36eb

Browse files
committed
test: add integration tests for reader-based BAM header parsing
Verify that parse_bam_from_reader correctly handles roundtrip encoding and truncated streams (partial uploads with trailing garbage).
1 parent bc9ec44 commit 9fd36eb

1 file changed

Lines changed: 70 additions & 0 deletions

File tree

tests/header_extraction_tests.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
//! Integration tests for header-only parsing from binary uploads.
2+
//!
3+
//! Verifies that the server can parse headers from BAM/CRAM bytes
4+
//! sent as multipart uploads, including truncated streams.
5+
6+
use std::io::Cursor;
7+
use std::num::NonZeroUsize;
8+
9+
use noodles::bam;
10+
use noodles::sam;
11+
use noodles::sam::header::record::value::map::ReferenceSequence;
12+
use noodles::sam::header::record::value::Map;
13+
14+
/// Create a minimal BAM file in memory with the given contigs.
15+
fn create_test_bam(contigs: &[(&str, usize)]) -> Vec<u8> {
16+
let mut header = sam::Header::builder();
17+
for &(name, length) in contigs {
18+
header = header.add_reference_sequence(
19+
name,
20+
Map::<ReferenceSequence>::new(NonZeroUsize::new(length).unwrap()),
21+
);
22+
}
23+
let header = header.build();
24+
25+
let mut buf = Vec::new();
26+
{
27+
let mut writer = bam::io::Writer::new(&mut buf);
28+
writer.write_header(&header).unwrap();
29+
}
30+
buf
31+
}
32+
33+
#[test]
34+
fn test_parse_bam_from_reader_roundtrip() {
35+
use ref_solver::parsing::sam::parse_bam_from_reader;
36+
37+
let contigs = [
38+
("chr1", 248_956_422),
39+
("chr2", 242_193_529),
40+
("chr3", 198_295_559),
41+
("chrX", 156_040_895),
42+
("chrY", 57_227_415),
43+
("chrM", 16_569),
44+
];
45+
46+
let bam_bytes = create_test_bam(&contigs);
47+
let cursor = Cursor::new(&bam_bytes);
48+
let query = parse_bam_from_reader(cursor).unwrap();
49+
50+
assert_eq!(query.contigs.len(), contigs.len());
51+
for (i, &(name, length)) in contigs.iter().enumerate() {
52+
assert_eq!(query.contigs[i].name, name);
53+
assert_eq!(query.contigs[i].length, length as u64);
54+
}
55+
}
56+
57+
#[test]
58+
fn test_parse_bam_from_reader_with_trailing_garbage() {
59+
use ref_solver::parsing::sam::parse_bam_from_reader;
60+
61+
let mut bam_bytes = create_test_bam(&[("chr1", 248_956_422)]);
62+
// Simulate a truncated upload — header is complete but record data is garbage.
63+
// parse_bam_from_reader only reads the header, so this must still succeed.
64+
bam_bytes.extend_from_slice([0xDE, 0xAD, 0xBE, 0xEF].repeat(25).as_slice());
65+
let cursor = Cursor::new(&bam_bytes);
66+
let query = parse_bam_from_reader(cursor).unwrap();
67+
68+
assert_eq!(query.contigs.len(), 1);
69+
assert_eq!(query.contigs[0].name, "chr1");
70+
}

0 commit comments

Comments
 (0)