use super::*;
#[test]
fn test_boundary_config_default() {
let config = BoundaryConfig::default();
assert!((config.min_silence_duration - 0.05).abs() < f32::EPSILON);
assert!(config.use_audio_energy);
}
#[test]
fn test_boundary_config_precise() {
let config = BoundaryConfig::precise();
assert!((config.min_silence_duration - 0.03).abs() < f32::EPSILON);
assert!((config.min_word_duration - 0.03).abs() < f32::EPSILON);
}
#[test]
fn test_boundary_config_fast() {
let config = BoundaryConfig::fast();
assert!(!config.use_audio_energy);
assert!((config.min_silence_duration - 0.1).abs() < f32::EPSILON);
}
#[test]
fn test_boundary_config_with_min_silence() {
let config = BoundaryConfig::default().with_min_silence(0.1);
assert!((config.min_silence_duration - 0.1).abs() < f32::EPSILON);
}
#[test]
fn test_boundary_config_with_min_word_duration() {
let config = BoundaryConfig::default().with_min_word_duration(0.2);
assert!((config.min_word_duration - 0.2).abs() < f32::EPSILON);
}
#[test]
fn test_word_boundary_new() {
let boundary = WordBoundary::new(1.0, 2.0);
assert!((boundary.start - 1.0).abs() < f32::EPSILON);
assert!((boundary.end - 2.0).abs() < f32::EPSILON);
assert!((boundary.start_confidence - 0.5).abs() < f32::EPSILON);
assert!(!boundary.audio_refined);
}
#[test]
fn test_word_boundary_duration() {
let boundary = WordBoundary::new(1.0, 2.5);
assert!((boundary.duration() - 1.5).abs() < f32::EPSILON);
}
#[test]
fn test_word_boundary_confidence() {
let boundary = WordBoundary::new(1.0, 2.0).with_confidence(0.8, 0.6);
assert!((boundary.confidence() - 0.7).abs() < f32::EPSILON);
}
#[test]
fn test_word_boundary_is_high_confidence() {
let high = WordBoundary::new(1.0, 2.0).with_confidence(0.9, 0.9);
let low = WordBoundary::new(1.0, 2.0).with_confidence(0.3, 0.3);
assert!(high.is_high_confidence());
assert!(!low.is_high_confidence());
}
#[test]
fn test_word_boundary_with_tokens() {
let boundary = WordBoundary::new(1.0, 2.0).with_tokens(vec![0, 1, 2]);
assert_eq!(boundary.token_indices, vec![0, 1, 2]);
}
#[test]
fn test_word_boundary_with_audio_refined() {
let boundary = WordBoundary::new(1.0, 2.0).with_audio_refined(true);
assert!(boundary.audio_refined);
}
#[test]
fn test_boundary_detector_new() {
let detector = BoundaryDetector::new(BoundaryConfig::default());
assert!(detector.config.use_audio_energy);
}
#[test]
fn test_boundary_detector_default() {
let detector = BoundaryDetector::default();
assert!((detector.config.min_silence_duration - 0.05).abs() < f32::EPSILON);
}
#[test]
fn test_detect_boundaries_empty() {
let detector = BoundaryDetector::default();
let result = detector
.detect_boundaries(&[], &[])
.expect("should succeed");
assert!(result.is_empty());
}
#[test]
fn test_detect_boundaries_single_word() {
let detector = BoundaryDetector::default();
let mut alignments = vec![
TokenAlignment::new(0, 100, 50, 0.9),
TokenAlignment::new(1, 101, 60, 0.8),
];
alignments[0].set_end_time(60);
alignments[1].set_end_time(80);
let word_starts = vec![0];
let result = detector
.detect_boundaries(&alignments, &word_starts)
.expect("should succeed");
assert_eq!(result.len(), 1);
assert!((result[0].start - 1.0).abs() < f32::EPSILON); }
#[test]
fn test_detect_boundaries_multiple_words() {
let detector = BoundaryDetector::default();
let mut alignments = vec![
TokenAlignment::new(0, 100, 0, 0.9),
TokenAlignment::new(1, 101, 25, 0.8),
TokenAlignment::new(2, 102, 50, 0.85),
TokenAlignment::new(3, 103, 75, 0.9),
];
for (i, a) in alignments.iter_mut().enumerate() {
a.set_end_time((i + 1) * 25);
}
let word_starts = vec![0, 2];
let result = detector
.detect_boundaries(&alignments, &word_starts)
.expect("should succeed");
assert_eq!(result.len(), 2);
}
#[test]
fn test_validate_boundary_min_duration() {
let detector = BoundaryDetector::new(BoundaryConfig::default().with_min_word_duration(0.1));
let boundary = WordBoundary::new(1.0, 1.01); let validated = detector.validate_boundary(boundary);
assert!(validated.duration() >= 0.1);
}
#[test]
fn test_validate_boundary_max_duration() {
let mut config = BoundaryConfig::default();
config.max_word_duration = 2.0;
let detector = BoundaryDetector::new(config);
let boundary = WordBoundary::new(0.0, 10.0); let validated = detector.validate_boundary(boundary);
assert!((validated.duration() - 2.0).abs() < f32::EPSILON);
}
#[test]
fn test_compute_boundary_confidence_empty() {
let detector = BoundaryDetector::default();
let confidence = detector.compute_boundary_confidence(&[]);
assert!((confidence - 0.0).abs() < f32::EPSILON);
}
#[test]
fn test_compute_boundary_confidence_monotonic() {
let detector = BoundaryDetector::default();
let alignments = vec![
TokenAlignment::new(0, 100, 10, 0.8),
TokenAlignment::new(1, 101, 20, 0.8),
TokenAlignment::new(2, 102, 30, 0.8),
];
let confidence = detector.compute_boundary_confidence(&alignments);
assert!((confidence - 0.8).abs() < f32::EPSILON); }
#[test]
fn test_compute_boundary_confidence_non_monotonic() {
let detector = BoundaryDetector::default();
let alignments = vec![
TokenAlignment::new(0, 100, 30, 0.8),
TokenAlignment::new(1, 101, 20, 0.8), TokenAlignment::new(2, 102, 40, 0.8),
];
let confidence = detector.compute_boundary_confidence(&alignments);
assert!(confidence < 0.8); }
#[test]
fn test_detect_silence_gaps() {
let detector = BoundaryDetector::default();
let boundaries = vec![
WordBoundary::new(0.0, 1.0),
WordBoundary::new(1.5, 2.5), WordBoundary::new(2.6, 3.5), ];
let gaps = detector.detect_silence_gaps(&boundaries);
assert_eq!(gaps.len(), 2);
assert!((gaps[0].0 - 1.0).abs() < f32::EPSILON);
assert!((gaps[0].1 - 1.5).abs() < f32::EPSILON);
}
#[test]
fn test_detect_silence_gaps_no_gaps() {
let mut config = BoundaryConfig::default();
config.min_silence_duration = 1.0; let detector = BoundaryDetector::new(config);
let boundaries = vec![
WordBoundary::new(0.0, 1.0),
WordBoundary::new(1.1, 2.0), ];
let gaps = detector.detect_silence_gaps(&boundaries);
assert!(gaps.is_empty());
}
#[test]
fn test_refine_with_audio_disabled() {
let config = BoundaryConfig::fast(); let detector = BoundaryDetector::new(config);
let boundaries = vec![WordBoundary::new(0.0, 1.0)];
let audio_energy = vec![0.5; 100];
let refined = detector
.refine_with_audio(&boundaries, &audio_energy, 50.0)
.expect("should succeed");
assert!(!refined[0].audio_refined);
}
#[test]
fn test_refine_with_audio_empty_energy() {
let detector = BoundaryDetector::default();
let boundaries = vec![WordBoundary::new(0.0, 1.0)];
let refined = detector
.refine_with_audio(&boundaries, &[], 50.0)
.expect("should succeed");
assert!(!refined[0].audio_refined);
}
#[test]
fn test_boundary_config_silence_builder() {
let config = BoundaryConfig::default().with_min_silence(0.1);
assert!((config.min_silence_duration - 0.1).abs() < f32::EPSILON);
}
#[test]
fn test_boundary_config_word_duration_builder() {
let config = BoundaryConfig::default().with_min_word_duration(0.2);
assert!((config.min_word_duration - 0.2).abs() < f32::EPSILON);
}
#[test]
fn test_word_boundary_with_both_confidences() {
let boundary = WordBoundary::new(0.0, 1.0).with_confidence(0.9, 0.8);
assert!((boundary.start_confidence - 0.9).abs() < f32::EPSILON);
assert!((boundary.end_confidence - 0.8).abs() < f32::EPSILON);
}
#[test]
fn test_word_boundary_tokens_builder() {
let boundary = WordBoundary::new(0.0, 1.0).with_tokens(vec![1, 2, 3]);
assert_eq!(boundary.token_indices, vec![1, 2, 3]);
}
#[test]
fn test_word_boundary_duration_calculation() {
let boundary = WordBoundary::new(1.5, 3.5);
assert!((boundary.duration() - 2.0).abs() < f32::EPSILON);
}
#[test]
fn test_word_boundary_avg_confidence() {
let boundary = WordBoundary::new(0.0, 1.0).with_confidence(0.8, 0.6);
let conf = boundary.confidence();
assert!((conf - 0.7).abs() < f32::EPSILON);
}
#[test]
fn test_word_boundary_is_high_confidence_both() {
let high = WordBoundary::new(0.0, 1.0).with_confidence(0.9, 0.85);
let low = WordBoundary::new(0.0, 1.0).with_confidence(0.5, 0.6);
assert!(high.is_high_confidence());
assert!(!low.is_high_confidence());
}
#[test]
fn test_word_boundary_audio_refined_flag() {
let boundary = WordBoundary::new(0.0, 1.0).with_audio_refined(true);
assert!(boundary.audio_refined);
}
#[test]
fn test_detect_boundaries_empty_alignments() {
let detector = BoundaryDetector::default();
let boundaries = detector
.detect_boundaries(&[], &[])
.expect("should succeed");
assert!(boundaries.is_empty());
}
#[test]
fn test_detect_boundaries_single_alignment() {
let detector = BoundaryDetector::default();
let alignments = vec![TokenAlignment::new(0, 100, 30, 0.9)];
let word_starts = vec![0];
let boundaries = detector
.detect_boundaries(&alignments, &word_starts)
.expect("should succeed");
assert_eq!(boundaries.len(), 1);
}
#[test]
fn test_refine_with_audio_boundaries() {
let detector = BoundaryDetector::default();
let boundaries = vec![WordBoundary::new(0.0, 0.5), WordBoundary::new(0.6, 1.0)];
let audio_energy: Vec<f32> = (0..100).map(|i| if i < 50 { 0.5 } else { 0.02 }).collect();
let refined = detector
.refine_with_audio(&boundaries, &audio_energy, 100.0)
.expect("should succeed");
assert_eq!(refined.len(), 2);
}
#[test]
fn test_detect_silence_gaps_multiple() {
let detector = BoundaryDetector::default();
let boundaries = vec![
WordBoundary::new(0.0, 0.5),
WordBoundary::new(1.0, 1.5),
WordBoundary::new(2.0, 2.5),
];
let gaps = detector.detect_silence_gaps(&boundaries);
assert_eq!(gaps.len(), 2);
}
#[test]
fn test_compute_boundary_confidence_single() {
let detector = BoundaryDetector::default();
let alignments = vec![TokenAlignment::new(0, 100, 30, 0.8)];
let conf = detector.compute_boundary_confidence(&alignments);
assert!(conf > 0.0 && conf <= 1.0);
}