use super::multi::build_fusion_strategy;
use crate::types::MultiQuerySearchRequest;
fn request(strategy: &str) -> MultiQuerySearchRequest {
serde_json::from_value(serde_json::json!({
"vectors": [[0.1f32, 0.2f32]],
"strategy": strategy,
}))
.expect("test: the default multi-query body must deserialize")
}
#[test]
fn the_defaults_of_every_strategy_are_accepted() {
for strategy in [
"average",
"avg",
"maximum",
"max",
"rrf",
"weighted",
"relative_score",
"rsf",
] {
build_fusion_strategy(&request(strategy))
.unwrap_or_else(|error| panic!("'{strategy}' must build with its defaults: {error}"));
}
}
#[test]
fn weighted_defaults_are_the_canonical_constants() {
let strategy = build_fusion_strategy(&request("weighted")).expect("weighted must build");
match strategy {
velesdb_core::FusionStrategy::Weighted {
avg_weight,
max_weight,
hit_weight,
} => {
assert!((avg_weight - velesdb_core::DEFAULT_WEIGHTED_AVG_WEIGHT).abs() < f32::EPSILON);
assert!((max_weight - velesdb_core::DEFAULT_WEIGHTED_MAX_WEIGHT).abs() < f32::EPSILON);
assert!((hit_weight - velesdb_core::DEFAULT_WEIGHTED_HIT_WEIGHT).abs() < f32::EPSILON);
}
other => panic!("expected Weighted, got {other:?}"),
}
}
#[test]
fn a_negative_weighted_component_is_refused() {
let mut req = request("weighted");
req.avg_weight = -0.2;
req.max_weight = 0.9;
req.hit_weight = 0.3;
let error = build_fusion_strategy(&req).expect_err("a negative weight must be refused");
assert!(
error.contains("non-negative"),
"message should name the rule it broke, got: {error}"
);
}
#[test]
fn weighted_components_that_do_not_sum_to_one_are_refused() {
let mut req = request("weighted");
req.avg_weight = 0.9;
req.max_weight = 0.9;
req.hit_weight = 0.9;
let error = build_fusion_strategy(&req).expect_err("weights summing to 2.7 must be refused");
assert!(
error.contains("sum to 1.0"),
"message should name the rule it broke, got: {error}"
);
}
#[test]
fn a_non_finite_weighted_component_is_refused() {
for bad in [f32::NAN, f32::INFINITY, f32::NEG_INFINITY] {
let mut req = request("weighted");
req.avg_weight = bad;
let error = build_fusion_strategy(&req)
.err()
.unwrap_or_else(|| panic!("{bad} must be refused"));
assert!(
error.contains("finite") || error.contains("sum to 1.0"),
"message should name the rule {bad} broke, got: {error}"
);
}
}
#[test]
fn relative_score_weights_that_do_not_sum_to_one_are_refused() {
let mut req = request("rsf");
req.dense_weight = 0.9;
req.sparse_weight = 0.9;
let error = build_fusion_strategy(&req).expect_err("weights summing to 1.8 must be refused");
assert!(
error.contains("sum to 1.0"),
"message should name the rule it broke, got: {error}"
);
}
#[test]
fn a_non_finite_relative_score_weight_is_refused() {
let mut req = request("rsf");
req.dense_weight = f32::NAN;
req.sparse_weight = 0.5;
let error = build_fusion_strategy(&req).expect_err("a NaN weight must be refused");
assert!(
error.contains("finite"),
"message should name the rule it broke, got: {error}"
);
}
#[test]
fn an_unknown_strategy_keeps_its_original_casing_in_the_message() {
let error = build_fusion_strategy(&request("NoSuchStrategy"))
.expect_err("an unknown strategy must be refused");
assert!(
error.contains("NoSuchStrategy"),
"message should echo what the caller sent, got: {error}"
);
}