use std::num::NonZeroU64;
use serde_json::{Value, json};
use super::support::{Fixture, TestResult, request, values};
#[test]
fn percentile_service_nearest_rank_returns_95_with_zero_skipped() -> TestResult {
let documents: Vec<_> = (1..=100)
.map(|reading| json!({"reading":reading}))
.collect();
let fixture = Fixture::new(None, &documents)?;
let answer = fixture.run(
&request("patients | percentile(.reading; 95)", NonZeroU64::MIN),
&[],
)?;
assert_eq!(values(&answer)?, vec![json!(95)]);
assert_eq!(answer.get("skipped").ok_or("missing skipped")?, 0);
assert_eq!(
answer.get("records_read").ok_or("missing records_read")?,
100
);
assert_eq!(
answer.get("stages").ok_or("missing stages")?,
&json!(["percentile"])
);
assert!(answer.get("next").ok_or("missing next")?.is_null());
let rows = answer
.get("rows")
.and_then(Value::as_array)
.ok_or("missing rows")?;
let origin = rows
.first()
.and_then(|row| row.get("origin"))
.ok_or("missing origin")?;
assert_eq!(origin.get("id").ok_or("missing id")?, "");
assert_eq!(
origin.get("collection").ok_or("missing collection")?,
"patients"
);
assert_eq!(
origin.get("version").ok_or("missing version")?,
answer
.get("selection")
.and_then(|selection| selection.get("version"))
.ok_or("missing selection.version")?
);
Ok(())
}
#[test]
fn percentile_service_counts_skips_and_excludes_denied_records() -> TestResult {
let fixture = Fixture::new(
None,
&[
json!({"reading":1}),
json!({"reading":999}),
json!({"reading":"3"}),
json!({}),
json!({"reading":null}),
json!({"reading":2}),
],
)?;
let answer = fixture.run(
&request("patients | percentile(.reading; 100)", NonZeroU64::MIN),
&[("patients", "p1")],
)?;
assert_eq!(values(&answer)?, vec![json!(2)]);
assert_eq!(answer.get("skipped").ok_or("missing skipped")?, 3);
assert!(answer.get("next").ok_or("missing next")?.is_null());
Ok(())
}
#[test]
fn percentile_service_empty_input_is_null_with_zero_skipped() -> TestResult {
let fixture = Fixture::new(None, &[])?;
let answer = fixture.run(
&request("patients | percentile(.reading; 95)", NonZeroU64::MIN),
&[],
)?;
assert_eq!(values(&answer)?, vec![Value::Null]);
assert_eq!(answer.get("skipped").ok_or("missing skipped")?, 0);
assert_eq!(answer.get("records_read").ok_or("missing scan count")?, 0);
Ok(())
}
#[test]
fn percentile_service_101_is_named_before_worker_admission() -> TestResult {
let mut fixture = Fixture::new(None, &[])?;
fixture.no_worker();
let error = fixture
.run(
&request("patients | percentile(.reading; 101)", NonZeroU64::MIN),
&[],
)
.err()
.ok_or("101 accepted")?;
assert_eq!(error.code, "query_percentile_range");
assert!(error.message.contains("percentile"));
assert!(error.message.contains("0 to 100"));
Ok(())
}
#[test]
fn percentile_service_scan_limit_refuses_without_a_partial_value() -> TestResult {
let mut fixture = Fixture::new(None, &[json!({"reading":1}), json!({"reading":2})])?;
fixture.scan(NonZeroU64::MIN);
let error = fixture
.run(
&request("patients | percentile(.reading; 95)", NonZeroU64::MIN),
&[],
)
.err()
.ok_or("partial percentile accepted")?;
assert_eq!(error.code, "query_scan_limit");
assert_eq!(error.message, "records read exceed scan limit 1");
Ok(())
}