use crate::MeasurementAggregate;
use super::{MeasurementMeanError, MeasurementSummary};
#[test]
fn summary_mean_preserves_recording_and_saturation_contracts() {
let mut summary = MeasurementSummary::EMPTY;
assert_eq!(summary.mean(), Ok(None));
summary.record(0);
assert_eq!(summary.mean(), Ok(Some(0)));
summary.record(9);
assert_eq!(summary.mean(), Ok(Some(4)));
summary.record(u64::MAX - 9);
assert_eq!(summary.total(), u128::from(u64::MAX));
assert_eq!(summary.mean(), Ok(Some(u128::from(u64::MAX) / 3)));
assert!(!summary.aggregate().total_saturated());
summary.record(1);
assert_eq!(summary.mean(), Ok(Some((u128::from(u64::MAX) + 1) / 4)));
assert!(!summary.aggregate().total_saturated());
assert_eq!(summary.latest(), Some(1));
let mut saturated_count = MeasurementSummary {
aggregate: maximum_zero_count(),
latest: 0,
};
assert_eq!(saturated_count.mean(), Ok(Some(0)));
saturated_count.record(9);
assert_eq!(
saturated_count.mean(),
Err(MeasurementMeanError::SaturatedSamples)
);
}
#[test]
fn summary_means_are_available_in_constant_evaluation() {
const PROJECTIONS: (Option<u128>, Option<u128>) = {
let mut summary = MeasurementSummary::EMPTY;
summary.record(9);
summary.record(0);
let Ok(mean) = summary.mean() else {
panic!("exact mean")
};
let Ok(scaled) = summary.scaled_mean(10) else {
panic!("exact scaled mean")
};
(mean, scaled)
};
assert_eq!(PROJECTIONS, (Some(4), Some(45)));
let mut summary = MeasurementSummary::EMPTY;
assert_eq!(summary.scaled_mean(10), Ok(None));
summary.record(0);
assert_eq!(summary.scaled_mean(10), Ok(Some(0)));
summary = MeasurementSummary::from_parts(maximum_zero_count(), Some(0)).unwrap();
assert_eq!(summary.scaled_mean(u64::MAX), Ok(Some(0)));
summary.record(0);
assert_eq!(
summary.scaled_mean(0),
Err(MeasurementMeanError::SaturatedSamples)
);
}
#[test]
fn empty_and_measured_zero_are_distinct() {
let mut summary = MeasurementSummary::EMPTY;
assert_eq!(summary, MeasurementSummary::default());
assert_eq!(summary.samples(), 0);
assert_eq!(summary.total(), 0);
assert_eq!(summary.latest(), None);
assert_eq!(summary.maximum(), None);
summary.record(0);
assert_eq!(summary.samples(), 1);
assert_eq!(summary.total(), 0);
assert_eq!(summary.latest(), Some(0));
assert_eq!(summary.maximum(), Some(0));
}
#[test]
fn latest_and_maximum_follow_individual_observations() {
let mut summary = MeasurementSummary::EMPTY;
for value in [7, 12, 3, 0] {
summary.record(value);
}
assert_eq!(summary.samples(), 4);
assert_eq!(summary.total(), 22);
assert_eq!(summary.latest(), Some(0));
assert_eq!(summary.maximum(), Some(12));
}
#[test]
fn total_saturation_preserves_count_latest_and_maximum() {
let mut aggregate = MeasurementAggregate::EMPTY;
for _ in 0..64 {
aggregate.merge(aggregate);
aggregate.record(u64::MAX);
}
aggregate.record(u64::MAX);
aggregate.record(u64::MAX);
let mut summary = MeasurementSummary {
aggregate,
latest: u64::MAX,
};
assert_eq!(summary.total(), u128::MAX);
assert!(!summary.aggregate().total_saturated());
summary.record(1);
summary.record(2);
assert_eq!(summary.samples(), u64::MAX);
assert_eq!(summary.total(), u128::MAX);
assert!(summary.aggregate().samples_saturated());
assert!(summary.aggregate().total_saturated());
assert_eq!(summary.latest(), Some(2));
assert_eq!(summary.maximum(), Some(u64::MAX));
}
#[test]
fn count_saturation_does_not_freeze_other_observations() {
let mut summary = MeasurementSummary {
aggregate: maximum_zero_count(),
latest: 0,
};
summary.record(4);
assert_eq!(summary.samples(), u64::MAX);
assert_eq!(summary.total(), 4);
assert_eq!(summary.latest(), Some(4));
assert_eq!(summary.maximum(), Some(4));
}
#[test]
fn recording_is_available_in_constant_evaluation() {
const SUMMARY: MeasurementSummary = {
let mut summary = MeasurementSummary::EMPTY;
summary.record(9);
summary.record(2);
summary
};
assert_eq!(SUMMARY.samples(), 2);
assert_eq!(SUMMARY.total(), 11);
assert_eq!(SUMMARY.latest(), Some(2));
assert_eq!(SUMMARY.maximum(), Some(9));
}
fn maximum_zero_count() -> MeasurementAggregate {
let mut aggregate = MeasurementAggregate::EMPTY;
for _ in 0..64 {
aggregate.merge(aggregate);
aggregate.record(0);
}
aggregate
}