#[cfg(test)]
use crate::structures::{Chromosome, Gene};
use genetic_algorithms::{
fitness::FitnessFnWrapper, operations::selection::truncation::truncation_selection,
};
fn make_chromosome(fitness: f64) -> Chromosome {
Chromosome {
dna: vec![Gene { id: 0 }],
fitness,
age: 0,
fitness_fn: FitnessFnWrapper::default(),
fitness_values: vec![],
}
}
#[test]
fn test_truncation_selection_produces_correct_number_of_pairs() {
let pop: Vec<Chromosome> = (0..10).map(|i| make_chromosome(i as f64 * 10.0)).collect();
let pairs = truncation_selection(&pop, 4, 2);
assert_eq!(pairs.len(), 4);
}
#[test]
fn test_truncation_selection_empty_on_small_population() {
let pop = vec![make_chromosome(42.0)];
let pairs = truncation_selection(&pop, 1, 2);
assert!(pairs.is_empty());
let empty: Vec<Chromosome> = Vec::new();
let pairs = truncation_selection(&empty, 1, 2);
assert!(pairs.is_empty());
}
#[test]
fn test_truncation_selection_selects_only_from_top_half() {
let pop: Vec<Chromosome> = (0..20).map(|i| make_chromosome(i as f64)).collect();
let top_half_indices: std::collections::HashSet<usize> = (10..20).collect();
for _ in 0..200 {
let pairs = truncation_selection(&pop, 5, 2);
for group in &pairs {
assert!(
top_half_indices.contains(&group[0]),
"Index {} is not in the top half ({:?})",
group[0],
top_half_indices
);
assert!(
top_half_indices.contains(&group[1]),
"Index {} is not in the top half ({:?})",
group[1],
top_half_indices
);
}
}
}
#[test]
fn test_truncation_selection_handles_equal_fitness() {
let pop: Vec<Chromosome> = (0..10).map(|_| make_chromosome(5.0)).collect();
let pairs = truncation_selection(&pop, 3, 2);
assert_eq!(pairs.len(), 3);
for group in &pairs {
assert!(group[0] < pop.len());
assert!(group[1] < pop.len());
}
}
#[test]
fn test_truncation_selection_with_two_chromosomes() {
let pop = vec![make_chromosome(1.0), make_chromosome(2.0)];
let pairs = truncation_selection(&pop, 1, 2);
assert_eq!(pairs.len(), 1);
for group in &pairs {
assert!(group[0] < 2);
assert!(group[1] < 2);
}
}