use super::*;
use crate::core::{context::Context, individual::Individual, population::Population, state::State};
use crate::fitness::Maximize;
fn fe(g: &[u8; 1]) -> u8 {
g[0]
}
fn make_state() -> State<[u8; 1], u8> {
let pop = Population::from_iter(vec![Individual::new([1])]);
State::new(pop, 0)
}
#[cfg(feature = "parallel")]
fn test_runtime() -> &'static pooled::Runtime {
use std::sync::LazyLock;
static RUNTIME: LazyLock<pooled::Runtime> = LazyLock::new(|| pooled::Runtime::new(1));
&RUNTIME
}
#[test]
fn custom_observer_receives_all_hooks() {
struct Tracker {
started: bool,
generations: usize,
ended: bool,
}
impl<G, F, Fe, R, C> Observer<G, F, Fe, R, C> for Tracker {
fn on_start(&mut self, _: &State<G, F>, _: &Context<Fe, R, C>) {
self.started = true;
}
fn on_generation(&mut self, _: &State<G, F>, _: &Context<Fe, R, C>) {
self.generations += 1;
}
fn on_end(&mut self, _: &State<G, F>, _: &Context<Fe, R, C>) {
self.ended = true;
}
}
let mut rng = rand::rng();
#[cfg(not(feature = "parallel"))]
let ctx = Context::new(&(fe as fn(&[u8; 1]) -> u8), &mut rng, &Maximize);
#[cfg(feature = "parallel")]
let ctx = Context::new(
&(fe as fn(&[u8; 1]) -> u8),
&mut rng,
&Maximize,
test_runtime(),
);
let state = make_state();
let mut tracker = Tracker {
started: false,
generations: 0,
ended: false,
};
tracker.on_start(&state, &ctx);
tracker.on_generation(&state, &ctx);
tracker.on_generation(&state, &ctx);
tracker.on_end(&state, &ctx);
assert!(tracker.started);
assert_eq!(tracker.generations, 2);
assert!(tracker.ended);
}
#[test]
fn noop_observer_compiles() {
let mut rng = rand::rng();
#[cfg(not(feature = "parallel"))]
let ctx = Context::new(&(fe as fn(&[u8; 1]) -> u8), &mut rng, &Maximize);
#[cfg(feature = "parallel")]
let ctx = Context::new(
&(fe as fn(&[u8; 1]) -> u8),
&mut rng,
&Maximize,
test_runtime(),
);
let state = make_state();
let mut noop = NoOp::new();
noop.on_start(&state, &ctx);
noop.on_generation(&state, &ctx);
noop.on_end(&state, &ctx);
}
#[test]
fn default_methods_are_noop() {
struct Empty;
impl<G, F, Fe, R, C> Observer<G, F, Fe, R, C> for Empty {}
let mut rng = rand::rng();
#[cfg(not(feature = "parallel"))]
let ctx = Context::new(&(fe as fn(&[u8; 1]) -> u8), &mut rng, &Maximize);
#[cfg(feature = "parallel")]
let ctx = Context::new(
&(fe as fn(&[u8; 1]) -> u8),
&mut rng,
&Maximize,
test_runtime(),
);
let state = make_state();
let mut empty = Empty;
empty.on_start(&state, &ctx);
empty.on_generation(&state, &ctx);
empty.on_end(&state, &ctx);
}