Skip to content

Commit a2096e7

Browse files
committed
tests: added testing on cbq reader
1 parent 1cdb1bc commit a2096e7

1 file changed

Lines changed: 308 additions & 0 deletions

File tree

src/cbq/read.rs

Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,3 +311,311 @@ impl ParallelReader for MmapReader {
311311
Ok(())
312312
}
313313
}
314+
#[cfg(test)]
315+
mod tests {
316+
use super::*;
317+
use crate::BinseqRecord;
318+
319+
const TEST_CBQ_FILE: &str = "./data/subset.cbq";
320+
321+
// ==================== MmapReader Basic Tests ====================
322+
323+
#[test]
324+
fn test_mmap_reader_new() {
325+
let reader = MmapReader::new(TEST_CBQ_FILE);
326+
assert!(reader.is_ok(), "Failed to create CBQ reader");
327+
}
328+
329+
#[test]
330+
fn test_mmap_reader_num_records() {
331+
let reader = MmapReader::new(TEST_CBQ_FILE).unwrap();
332+
let num_records = reader.num_records();
333+
assert!(num_records > 0, "Expected non-zero records");
334+
}
335+
336+
#[test]
337+
fn test_mmap_reader_is_paired() {
338+
let reader = MmapReader::new(TEST_CBQ_FILE).unwrap();
339+
let is_paired = reader.is_paired();
340+
// Test that the method returns a boolean
341+
assert!(is_paired || !is_paired);
342+
}
343+
344+
#[test]
345+
fn test_mmap_reader_header_access() {
346+
let reader = MmapReader::new(TEST_CBQ_FILE).unwrap();
347+
let header = reader.header();
348+
assert!(header.block_size > 0, "Expected non-zero block size");
349+
}
350+
351+
#[test]
352+
fn test_mmap_reader_index_access() {
353+
let reader = MmapReader::new(TEST_CBQ_FILE).unwrap();
354+
let index = reader.index();
355+
assert!(index.num_records() > 0, "Index should have records");
356+
}
357+
358+
#[test]
359+
fn test_mmap_reader_num_blocks() {
360+
let reader = MmapReader::new(TEST_CBQ_FILE).unwrap();
361+
let num_blocks = reader.num_blocks();
362+
assert!(num_blocks > 0, "Should have at least one block");
363+
}
364+
365+
// ==================== Default Quality Score Tests ====================
366+
367+
#[test]
368+
fn test_set_default_quality_score() {
369+
let mut reader = MmapReader::new(TEST_CBQ_FILE).unwrap();
370+
let custom_score = 42u8;
371+
372+
reader.set_default_quality_score(custom_score);
373+
// Just verify it doesn't panic
374+
}
375+
376+
// ==================== Parallel Processing Tests ====================
377+
378+
#[derive(Clone)]
379+
struct CbqCountingProcessor {
380+
count: Arc<std::sync::Mutex<usize>>,
381+
}
382+
383+
impl ParallelProcessor for CbqCountingProcessor {
384+
fn process_record<R: BinseqRecord>(&mut self, _record: R) -> Result<()> {
385+
let mut count = self.count.lock().unwrap();
386+
*count += 1;
387+
Ok(())
388+
}
389+
}
390+
391+
#[test]
392+
fn test_parallel_processing() {
393+
let reader = MmapReader::new(TEST_CBQ_FILE).unwrap();
394+
let num_records = reader.num_records();
395+
396+
let count = Arc::new(std::sync::Mutex::new(0));
397+
let processor = CbqCountingProcessor {
398+
count: count.clone(),
399+
};
400+
401+
reader.process_parallel(processor, 2).unwrap();
402+
403+
let final_count = *count.lock().unwrap();
404+
assert_eq!(final_count, num_records, "All records should be processed");
405+
}
406+
407+
#[test]
408+
fn test_parallel_processing_range() {
409+
let reader = MmapReader::new(TEST_CBQ_FILE).unwrap();
410+
let num_records = reader.num_records();
411+
412+
if num_records >= 100 {
413+
let start = 10;
414+
let end = 50;
415+
let expected_count = end - start;
416+
417+
let count = Arc::new(std::sync::Mutex::new(0));
418+
let processor = CbqCountingProcessor {
419+
count: count.clone(),
420+
};
421+
422+
reader
423+
.process_parallel_range(processor, 2, start..end)
424+
.unwrap();
425+
426+
let final_count = *count.lock().unwrap();
427+
assert_eq!(
428+
final_count, expected_count,
429+
"Should process exactly {} records",
430+
expected_count
431+
);
432+
}
433+
}
434+
435+
#[test]
436+
fn test_parallel_processing_with_record_data() {
437+
#[derive(Clone)]
438+
struct RecordValidator {
439+
valid_count: Arc<std::sync::Mutex<usize>>,
440+
}
441+
442+
impl ParallelProcessor for RecordValidator {
443+
fn process_record<R: BinseqRecord>(&mut self, record: R) -> Result<()> {
444+
// Validate record has non-zero length
445+
assert!(record.slen() > 0, "Record should have non-zero length");
446+
447+
let mut count = self.valid_count.lock().unwrap();
448+
*count += 1;
449+
Ok(())
450+
}
451+
}
452+
453+
let reader = MmapReader::new(TEST_CBQ_FILE).unwrap();
454+
let num_records = reader.num_records();
455+
456+
let count = Arc::new(std::sync::Mutex::new(0));
457+
let processor = RecordValidator {
458+
valid_count: count.clone(),
459+
};
460+
461+
reader.process_parallel(processor, 2).unwrap();
462+
463+
let final_count = *count.lock().unwrap();
464+
assert_eq!(final_count, num_records);
465+
}
466+
467+
// ==================== Index Tests ====================
468+
469+
#[test]
470+
fn test_index_num_records() {
471+
let reader = MmapReader::new(TEST_CBQ_FILE).unwrap();
472+
473+
let index_records = reader.index().num_records();
474+
let reader_records = reader.num_records();
475+
476+
assert_eq!(
477+
index_records, reader_records,
478+
"Index and reader should report same number of records"
479+
);
480+
}
481+
482+
#[test]
483+
fn test_index_num_blocks() {
484+
let reader = MmapReader::new(TEST_CBQ_FILE).unwrap();
485+
486+
let num_blocks = reader.index().num_blocks();
487+
assert!(num_blocks > 0, "Should have at least one block");
488+
}
489+
490+
#[test]
491+
fn test_index_iter_blocks() {
492+
let reader = MmapReader::new(TEST_CBQ_FILE).unwrap();
493+
494+
let blocks: Vec<_> = reader.index().iter_blocks().collect();
495+
assert!(!blocks.is_empty(), "Should have at least one block");
496+
497+
let num_blocks = reader.num_blocks();
498+
assert_eq!(blocks.len(), num_blocks, "Block count should match");
499+
}
500+
501+
// ==================== Error Handling Tests ====================
502+
503+
#[test]
504+
fn test_nonexistent_file() {
505+
let result = MmapReader::new("./data/nonexistent.cbq");
506+
assert!(result.is_err(), "Should fail on nonexistent file");
507+
}
508+
509+
#[test]
510+
fn test_invalid_file_format() {
511+
// Try to open a non-CBQ file as CBQ
512+
let result = MmapReader::new("./Cargo.toml");
513+
// This should fail during header validation
514+
assert!(result.is_err(), "Should fail on invalid file format");
515+
}
516+
517+
// ==================== Block Header Iterator Tests ====================
518+
519+
#[test]
520+
fn test_iter_block_headers() {
521+
let reader = MmapReader::new(TEST_CBQ_FILE).unwrap();
522+
523+
let headers: Vec<_> = reader
524+
.iter_block_headers()
525+
.take(5)
526+
.collect::<Result<Vec<_>>>()
527+
.unwrap();
528+
529+
assert!(!headers.is_empty(), "Should have at least one block header");
530+
531+
for header in headers {
532+
assert!(header.num_records > 0, "Block should have records");
533+
}
534+
}
535+
536+
#[test]
537+
fn test_iter_block_headers_count() {
538+
let reader = MmapReader::new(TEST_CBQ_FILE).unwrap();
539+
540+
let header_count = reader
541+
.iter_block_headers()
542+
.collect::<Result<Vec<_>>>()
543+
.unwrap()
544+
.len();
545+
546+
let num_blocks = reader.num_blocks();
547+
assert_eq!(header_count, num_blocks, "Should iterate all block headers");
548+
}
549+
550+
// ==================== Empty Range Tests ====================
551+
552+
#[test]
553+
fn test_parallel_processing_empty_range() {
554+
let reader = MmapReader::new(TEST_CBQ_FILE).unwrap();
555+
556+
let count = Arc::new(std::sync::Mutex::new(0));
557+
let processor = CbqCountingProcessor {
558+
count: count.clone(),
559+
};
560+
561+
// Process empty range
562+
reader.process_parallel_range(processor, 2, 0..0).unwrap();
563+
564+
let final_count = *count.lock().unwrap();
565+
assert_eq!(final_count, 0, "Empty range should process no records");
566+
}
567+
568+
#[test]
569+
fn test_parallel_processing_invalid_range() {
570+
let reader = MmapReader::new(TEST_CBQ_FILE).unwrap();
571+
let num_records = reader.num_records();
572+
573+
let count = Arc::new(std::sync::Mutex::new(0));
574+
let processor = CbqCountingProcessor {
575+
count: count.clone(),
576+
};
577+
578+
// Process out of bounds range (should handle gracefully)
579+
let result =
580+
reader.process_parallel_range(processor, 2, num_records + 100..num_records + 200);
581+
582+
assert!(
583+
result.is_ok(),
584+
"Should handle out of bounds range gracefully"
585+
);
586+
}
587+
588+
// ==================== Thread Count Tests ====================
589+
590+
#[test]
591+
fn test_parallel_processing_single_thread() {
592+
let reader = MmapReader::new(TEST_CBQ_FILE).unwrap();
593+
let num_records = reader.num_records();
594+
595+
let count = Arc::new(std::sync::Mutex::new(0));
596+
let processor = CbqCountingProcessor {
597+
count: count.clone(),
598+
};
599+
600+
reader.process_parallel(processor, 1).unwrap();
601+
602+
let final_count = *count.lock().unwrap();
603+
assert_eq!(final_count, num_records);
604+
}
605+
606+
#[test]
607+
fn test_parallel_processing_many_threads() {
608+
let reader = MmapReader::new(TEST_CBQ_FILE).unwrap();
609+
let num_records = reader.num_records();
610+
611+
let count = Arc::new(std::sync::Mutex::new(0));
612+
let processor = CbqCountingProcessor {
613+
count: count.clone(),
614+
};
615+
616+
reader.process_parallel(processor, 8).unwrap();
617+
618+
let final_count = *count.lock().unwrap();
619+
assert_eq!(final_count, num_records);
620+
}
621+
}

0 commit comments

Comments
 (0)