impl EmptyInputResult {
pub fn handled_gracefully(input_type: &str, response: &str) -> Self {
Self {
input_type: input_type.to_string(),
handled: true,
response_type: response.to_string(),
panicked: false,
meets_qa025: true,
}
}
pub fn panicked(input_type: &str) -> Self {
Self {
input_type: input_type.to_string(),
handled: false,
response_type: "panic".to_string(),
panicked: true,
meets_qa025: false,
}
}
}
#[derive(Debug, Clone)]
pub struct EmptyInputTestCase {
pub name: String,
pub prompt: String,
pub expected_behavior: String,
}
impl EmptyInputTestCase {
pub fn empty_string() -> Self {
Self {
name: "Empty string".to_string(),
prompt: String::new(),
expected_behavior: "Return error or empty output".to_string(),
}
}
pub fn whitespace_only() -> Self {
Self {
name: "Whitespace only".to_string(),
prompt: " \n\t ".to_string(),
expected_behavior: "Treat as empty or process whitespace".to_string(),
}
}
pub fn single_space() -> Self {
Self {
name: "Single space".to_string(),
prompt: " ".to_string(),
expected_behavior: "Process or reject".to_string(),
}
}
}
#[test]
fn test_imp_178a_empty_input_result() {
let handled = EmptyInputResult::handled_gracefully("empty_string", "error_returned");
assert!(
handled.meets_qa025,
"IMP-178a: Graceful handling should meet QA-025"
);
assert!(!handled.panicked, "IMP-178a: Handled should not panic");
let panicked = EmptyInputResult::panicked("empty_string");
assert!(
!panicked.meets_qa025,
"IMP-178a: Panic should NOT meet QA-025"
);
assert!(panicked.panicked, "IMP-178a: Panicked should be true");
println!("\nIMP-178a: Empty Input Results:");
println!(
" Handled: meets_qa025={}, response={}",
handled.meets_qa025, handled.response_type
);
println!(
" Panicked: meets_qa025={}, panicked={}",
panicked.meets_qa025, panicked.panicked
);
}
#[test]
fn test_imp_178b_empty_input_cases() {
let empty = EmptyInputTestCase::empty_string();
assert!(
empty.prompt.is_empty(),
"IMP-178b: Empty string should be empty"
);
let whitespace = EmptyInputTestCase::whitespace_only();
assert!(
whitespace.prompt.trim().is_empty(),
"IMP-178b: Whitespace only should trim to empty"
);
let space = EmptyInputTestCase::single_space();
assert_eq!(
space.prompt.len(),
1,
"IMP-178b: Single space should have length 1"
);
println!("\nIMP-178b: Empty Input Test Cases:");
println!(" {}: prompt={:?}", empty.name, empty.prompt);
println!(" {}: prompt={:?}", whitespace.name, whitespace.prompt);
println!(" {}: prompt={:?}", space.name, space.prompt);
}
#[derive(Debug, Clone)]
pub struct InputValidator {
pub allow_empty: bool,
pub trim_whitespace: bool,
pub min_length: usize,
}
impl InputValidator {
pub fn strict() -> Self {
Self {
allow_empty: false,
trim_whitespace: true,
min_length: 1,
}
}
pub fn permissive() -> Self {
Self {
allow_empty: true,
trim_whitespace: false,
min_length: 0,
}
}
pub fn validate(&self, prompt: &str) -> std::result::Result<(), String> {
let check = if self.trim_whitespace {
prompt.trim()
} else {
prompt
};
if check.is_empty() && !self.allow_empty {
return Err("Empty prompt not allowed".to_string());
}
if check.len() < self.min_length {
return Err(format!(
"Prompt too short: {} < {}",
check.len(),
self.min_length
));
}
Ok(())
}
}
#[test]
fn test_imp_178c_input_validation() {
let strict = InputValidator::strict();
assert!(
strict.validate("hello").is_ok(),
"IMP-178c: Normal input should pass strict"
);
assert!(
strict.validate("").is_err(),
"IMP-178c: Empty should fail strict"
);
assert!(
strict.validate(" ").is_err(),
"IMP-178c: Whitespace should fail strict (trimmed)"
);
let permissive = InputValidator::permissive();
assert!(
permissive.validate("").is_ok(),
"IMP-178c: Empty should pass permissive"
);
assert!(
permissive.validate(" ").is_ok(),
"IMP-178c: Whitespace should pass permissive"
);
println!("\nIMP-178c: Input Validation:");
println!(
" Strict: empty={:?}, whitespace={:?}",
strict.validate(""),
strict.validate(" ")
);
println!(
" Permissive: empty={:?}, whitespace={:?}",
permissive.validate(""),
permissive.validate(" ")
);
}
#[test]
#[ignore = "Requires running llama.cpp server on port 8082"]
fn test_imp_178d_realworld_empty_input() {
let client = ModelHttpClient::with_timeout(30);
let empty_request = CompletionRequest {
model: "default".to_string(),
prompt: String::new(),
max_tokens: 10,
temperature: Some(0.0),
stream: false,
};
let result = client.llamacpp_completion("http://127.0.0.1:8082", &empty_request);
let handling = EmptyInputResult::handled_gracefully(
"empty_string",
if result.is_ok() { "success" } else { "error" },
);
println!("\nIMP-178d: Real-World Empty Input:");
println!(" Input type: {}", handling.input_type);
println!(" Response: {}", handling.response_type);
println!(" Panicked: {}", handling.panicked);
println!(
" QA-025: {}",
if handling.meets_qa025 { "PASS" } else { "FAIL" }
);
}
#[derive(Debug, Clone)]
pub struct MaxContextResult {
pub requested_length: usize,
pub max_length: usize,
pub exceeded: bool,
pub handling: String,
pub panicked: bool,
pub meets_qa026: bool,
}
impl MaxContextResult {
pub fn within_limit(requested: usize, max: usize) -> Self {
Self {
requested_length: requested,
max_length: max,
exceeded: false,
handling: "Processed normally".to_string(),
panicked: false,
meets_qa026: true,
}
}
pub fn exceeded_graceful(requested: usize, max: usize, handling: &str) -> Self {
Self {
requested_length: requested,
max_length: max,
exceeded: true,
handling: handling.to_string(),
panicked: false,
meets_qa026: true,
}
}
pub fn exceeded_panic(requested: usize, max: usize) -> Self {
Self {
requested_length: requested,
max_length: max,
exceeded: true,
handling: "Panic".to_string(),
panicked: true,
meets_qa026: false,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ContextOverflowStrategy {
Reject,
TruncateHead,
TruncateTail,
SlidingWindow,
}
#[derive(Debug, Clone)]
pub struct ContextLengthValidator {
pub max_length: usize,
pub overflow_strategy: ContextOverflowStrategy,
}
impl ContextLengthValidator {
pub fn new(max_length: usize, strategy: ContextOverflowStrategy) -> Self {
Self {
max_length,
overflow_strategy: strategy,
}
}
pub fn validate(&self, length: usize) -> MaxContextResult {
if length <= self.max_length {
MaxContextResult::within_limit(length, self.max_length)
} else {
let handling = match &self.overflow_strategy {
ContextOverflowStrategy::Reject => "Rejected with error",
ContextOverflowStrategy::TruncateHead => "Truncated from head",
ContextOverflowStrategy::TruncateTail => "Truncated from tail",
ContextOverflowStrategy::SlidingWindow => "Used sliding window",
};
MaxContextResult::exceeded_graceful(length, self.max_length, handling)
}
}
}
#[test]
fn test_imp_179a_max_context_result() {
let within = MaxContextResult::within_limit(1000, 2048);
assert!(!within.exceeded, "IMP-179a: Within limit should not exceed");
assert!(
within.meets_qa026,
"IMP-179a: Within limit should meet QA-026"
);
let exceeded = MaxContextResult::exceeded_graceful(4000, 2048, "Truncated");
assert!(exceeded.exceeded, "IMP-179a: Exceeded should be true");
assert!(
exceeded.meets_qa026,
"IMP-179a: Graceful handling should meet QA-026"
);
let panic = MaxContextResult::exceeded_panic(10000, 2048);
assert!(!panic.meets_qa026, "IMP-179a: Panic should NOT meet QA-026");
println!("\nIMP-179a: Max Context Results:");
println!(
" Within: {}/{}, exceeded={}, meets_qa026={}",
within.requested_length, within.max_length, within.exceeded, within.meets_qa026
);
println!(
" Exceeded: {}/{}, handling={}, meets_qa026={}",
exceeded.requested_length, exceeded.max_length, exceeded.handling, exceeded.meets_qa026
);
}
#[test]
fn test_imp_179b_context_validation() {
let reject_validator = ContextLengthValidator::new(2048, ContextOverflowStrategy::Reject);
let within = reject_validator.validate(1000);
assert!(
!within.exceeded,
"IMP-179b: 1000 tokens should be within 2048 limit"
);
let exceeded = reject_validator.validate(4000);
assert!(
exceeded.exceeded,
"IMP-179b: 4000 tokens should exceed 2048 limit"
);
assert!(
exceeded.handling.contains("Rejected"),
"IMP-179b: Should use reject strategy"
);
let truncate_validator =
ContextLengthValidator::new(2048, ContextOverflowStrategy::TruncateHead);
let truncated = truncate_validator.validate(4000);
assert!(
truncated.handling.contains("head"),
"IMP-179b: Should use truncate head strategy"
);
println!("\nIMP-179b: Context Validation:");
println!(
" Reject strategy: {} tokens -> {}",
4000, exceeded.handling
);
println!(" Truncate head: {} tokens -> {}", 4000, truncated.handling);
}
#[test]
fn test_imp_179c_overflow_strategies() {
let strategies = vec![
ContextOverflowStrategy::Reject,
ContextOverflowStrategy::TruncateHead,
ContextOverflowStrategy::TruncateTail,
ContextOverflowStrategy::SlidingWindow,
];
for strategy in &strategies {
let validator = ContextLengthValidator::new(2048, strategy.clone());
let result = validator.validate(5000);
assert!(
result.meets_qa026,
"IMP-179c: All strategies should meet QA-026"
);
assert!(result.exceeded, "IMP-179c: All should detect exceeding");
}
println!("\nIMP-179c: Overflow Strategies:");
for strategy in strategies {
let validator = ContextLengthValidator::new(2048, strategy.clone());
let result = validator.validate(5000);
println!(" {:?}: {}", strategy, result.handling);
}
}