use pictor_eval::boolq::{BoolQDataset, BoolQEvaluator, BoolQItem};
fn make_item(passage: &str, question: &str, answer: bool) -> BoolQItem {
BoolQItem {
passage: passage.to_string(),
question: question.to_string(),
answer,
}
}
fn sky_yes() -> BoolQItem {
make_item("The sky is blue during the day.", "Is the sky blue?", true)
}
fn sky_no() -> BoolQItem {
make_item(
"The sky turns red at sunset.",
"Is the sky always blue?",
false,
)
}
#[test]
fn boolq_extract_yes_variants() {
assert_eq!(BoolQEvaluator::extract_answer("Yes"), Some(true));
assert_eq!(BoolQEvaluator::extract_answer("YES"), Some(true));
assert_eq!(BoolQEvaluator::extract_answer("yes"), Some(true));
assert_eq!(
BoolQEvaluator::extract_answer("Yes, that is correct."),
Some(true)
);
assert_eq!(BoolQEvaluator::extract_answer("yes."), Some(true));
}
#[test]
fn boolq_extract_no_variants() {
assert_eq!(BoolQEvaluator::extract_answer("No"), Some(false));
assert_eq!(BoolQEvaluator::extract_answer("NO"), Some(false));
assert_eq!(BoolQEvaluator::extract_answer("no"), Some(false));
assert_eq!(
BoolQEvaluator::extract_answer("No, it is not."),
Some(false)
);
assert_eq!(BoolQEvaluator::extract_answer("no."), Some(false));
}
#[test]
fn boolq_extract_none_for_ambiguous() {
assert_eq!(BoolQEvaluator::extract_answer("maybe"), None);
assert_eq!(BoolQEvaluator::extract_answer(""), None);
assert_eq!(BoolQEvaluator::extract_answer("I don't know"), None);
assert_eq!(BoolQEvaluator::extract_answer("Perhaps"), None);
assert_eq!(BoolQEvaluator::extract_answer("uncertain"), None);
}
#[test]
fn boolq_score_correct_yes() {
let eval = BoolQEvaluator::new();
assert!(eval.score("Yes", true));
assert!(!eval.score("No", true));
}
#[test]
fn boolq_score_correct_no() {
let eval = BoolQEvaluator::new();
assert!(eval.score("No", false));
assert!(!eval.score("Yes", false));
}
#[test]
fn boolq_build_prompt_format() {
let eval = BoolQEvaluator::new();
let item = make_item("The sky is blue.", "Is the sky blue?", true);
let prompt = eval.build_prompt(&item);
assert!(prompt.contains("Passage: The sky is blue."));
assert!(prompt.contains("Question: Is the sky blue?"));
assert!(prompt.ends_with("Answer:"));
}
#[test]
fn boolq_evaluate_completions_perfect() {
let ds = BoolQDataset::from_items(vec![sky_yes(), sky_no()]);
let eval = BoolQEvaluator::new();
let completions = vec!["Yes".to_string(), "No".to_string()];
let result = eval.evaluate_completions(&ds, &completions);
assert_eq!(result.correct, 2);
assert_eq!(result.total, 2);
assert!((result.accuracy - 1.0).abs() < 1e-6);
}
#[test]
fn boolq_evaluate_completions_counts_yes_no() {
let ds = BoolQDataset::from_items(vec![
make_item("P1", "Q1", true),
make_item("P2", "Q2", false),
]);
let eval = BoolQEvaluator::new();
let completions = vec!["Yes".to_string(), "No".to_string()];
let result = eval.evaluate_completions(&ds, &completions);
assert_eq!(result.yes_predicted, 1);
assert_eq!(result.no_predicted, 1);
assert_eq!(result.correct, 2);
}
#[test]
fn boolq_evaluate_completions_all_wrong() {
let ds = BoolQDataset::from_items(vec![sky_yes(), sky_no()]);
let eval = BoolQEvaluator::new();
let completions = vec!["No".to_string(), "Yes".to_string()];
let result = eval.evaluate_completions(&ds, &completions);
assert_eq!(result.correct, 0);
assert_eq!(result.total, 2);
assert!(result.accuracy.abs() < 1e-6);
}
#[test]
fn boolq_evaluate_logits_yes() {
let ds = BoolQDataset::from_items(vec![make_item("P", "Q", true)]);
let eval = BoolQEvaluator::new();
let result = eval.evaluate_logits(&ds, &[[3.0_f32, 1.0_f32]]);
assert_eq!(result.correct, 1);
assert_eq!(result.yes_predicted, 1);
assert_eq!(result.no_predicted, 0);
}
#[test]
fn boolq_evaluate_logits_no() {
let ds = BoolQDataset::from_items(vec![make_item("P", "Q", false)]);
let eval = BoolQEvaluator::new();
let result = eval.evaluate_logits(&ds, &[[0.5_f32, 2.0_f32]]);
assert_eq!(result.correct, 1);
assert_eq!(result.yes_predicted, 0);
assert_eq!(result.no_predicted, 1);
}
#[test]
fn boolq_empty_dataset() {
let ds = BoolQDataset::from_items(vec![]);
let result = BoolQEvaluator::new().evaluate_completions(&ds, &[]);
assert_eq!(result.total, 0);
assert_eq!(result.correct, 0);
assert!((result.accuracy - 0.0).abs() < 1e-6);
}
#[test]
fn boolq_default_impl() {
let _ = BoolQEvaluator::new();
}
#[test]
fn boolq_short_string_no_panic() {
assert_eq!(BoolQEvaluator::extract_answer("y"), None);
assert_eq!(BoolQEvaluator::extract_answer("n"), None);
assert_eq!(BoolQEvaluator::extract_answer("a"), None);
}
#[test]
fn boolq_leading_whitespace() {
assert_eq!(BoolQEvaluator::extract_answer(" Yes"), Some(true));
assert_eq!(BoolQEvaluator::extract_answer("\t\nNo"), Some(false));
assert_eq!(
BoolQEvaluator::extract_answer(" YES, definitely"),
Some(true)
);
}
#[test]
fn boolq_accuracy_pct_matches_accuracy() {
let ds = BoolQDataset::from_items(vec![sky_yes()]);
let eval = BoolQEvaluator::new();
let result = eval.evaluate_completions(&ds, &["Yes".to_string()]);
assert!((result.accuracy_pct - result.accuracy * 100.0).abs() < 1e-4);
}