|  | 
|  | 1 | +//! Tests for LoRA PII detector implementation | 
|  | 2 | +
 | 
|  | 3 | +use super::pii_lora::*; | 
|  | 4 | +use crate::test_fixtures::{fixtures::*, test_utils::*}; | 
|  | 5 | +use rstest::*; | 
|  | 6 | +use serial_test::serial; | 
|  | 7 | +use std::sync::Arc; | 
|  | 8 | + | 
|  | 9 | +/// Test PIILoRAClassifier creation with cached model (OPTIMIZED) | 
|  | 10 | +#[rstest] | 
|  | 11 | +#[serial] | 
|  | 12 | +fn test_pii_lora_pii_lora_classifier_new(cached_pii_classifier: Option<Arc<PIILoRAClassifier>>) { | 
|  | 13 | +    if let Some(classifier) = cached_pii_classifier { | 
|  | 14 | +        println!("Testing PIILoRAClassifier with cached model - instant access!"); | 
|  | 15 | + | 
|  | 16 | +        // Test actual PII detection with cached model | 
|  | 17 | +        { | 
|  | 18 | +            let test_text = "My name is John Doe and my email is [email protected]"; | 
|  | 19 | +            match classifier.detect_pii(test_text) { | 
|  | 20 | +                Ok(result) => { | 
|  | 21 | +                    println!("Real model PII detection result: has_pii={}, types={:?}, confidence={:.3}, time={}ms", | 
|  | 22 | +                        result.has_pii, result.pii_types, result.confidence, result.processing_time_ms); | 
|  | 23 | + | 
|  | 24 | +                    // Validate real model output | 
|  | 25 | +                    assert!(result.confidence >= 0.0 && result.confidence <= 1.0); | 
|  | 26 | +                    assert!(result.processing_time_ms > 0); | 
|  | 27 | +                    assert!(result.processing_time_ms < 10000); | 
|  | 28 | + | 
|  | 29 | +                    // Check PII detection logic | 
|  | 30 | +                    if result.has_pii { | 
|  | 31 | +                        assert!(!result.pii_types.is_empty()); | 
|  | 32 | +                        assert!(!result.occurrences.is_empty()); | 
|  | 33 | +                    } else { | 
|  | 34 | +                        assert!(result.pii_types.is_empty()); | 
|  | 35 | +                        assert!(result.occurrences.is_empty()); | 
|  | 36 | +                    } | 
|  | 37 | +                } | 
|  | 38 | +                Err(e) => { | 
|  | 39 | +                    println!("Real model PII detection failed: {}", e); | 
|  | 40 | +                } | 
|  | 41 | +            } | 
|  | 42 | +        } | 
|  | 43 | +    } else { | 
|  | 44 | +        println!("Cached PII classifier not available, skipping test"); | 
|  | 45 | +    } | 
|  | 46 | +} | 
|  | 47 | + | 
|  | 48 | +/// Test cached model batch PII detection (OPTIMIZED) | 
|  | 49 | +#[rstest] | 
|  | 50 | +#[serial] | 
|  | 51 | +fn test_pii_lora_pii_lora_classifier_batch_detect( | 
|  | 52 | +    cached_pii_classifier: Option<Arc<PIILoRAClassifier>>, | 
|  | 53 | +) { | 
|  | 54 | +    if let Some(classifier) = cached_pii_classifier { | 
|  | 55 | +        println!("Testing batch PII detection with cached model!"); | 
|  | 56 | +        { | 
|  | 57 | +            let test_texts = vec![ | 
|  | 58 | +                "Hello, my name is Alice", | 
|  | 59 | +                "Contact me at [email protected]", | 
|  | 60 | +                "My phone number is 555-1234", | 
|  | 61 | +                "This is a normal message without PII", | 
|  | 62 | +            ]; | 
|  | 63 | + | 
|  | 64 | +            match classifier.batch_detect(&test_texts) { | 
|  | 65 | +                Ok(results) => { | 
|  | 66 | +                    println!( | 
|  | 67 | +                        "Real model batch PII detection succeeded with {} results", | 
|  | 68 | +                        results.len() | 
|  | 69 | +                    ); | 
|  | 70 | +                    assert_eq!(results.len(), test_texts.len()); | 
|  | 71 | + | 
|  | 72 | +                    for (i, result) in results.iter().enumerate() { | 
|  | 73 | +                        println!("Batch PII result {}: has_pii={}, types={:?}, confidence={:.3}, time={}ms", | 
|  | 74 | +                            i, result.has_pii, result.pii_types, result.confidence, result.processing_time_ms); | 
|  | 75 | + | 
|  | 76 | +                        // Validate each result | 
|  | 77 | +                        assert!(result.confidence >= 0.0 && result.confidence <= 1.0); | 
|  | 78 | +                        assert!(result.processing_time_ms > 0); | 
|  | 79 | + | 
|  | 80 | +                        // Check PII detection consistency | 
|  | 81 | +                        assert_eq!(result.has_pii, !result.pii_types.is_empty()); | 
|  | 82 | +                        assert_eq!(result.has_pii, !result.occurrences.is_empty()); | 
|  | 83 | +                    } | 
|  | 84 | +                } | 
|  | 85 | +                Err(e) => { | 
|  | 86 | +                    println!("Real model batch PII detection failed: {}", e); | 
|  | 87 | +                } | 
|  | 88 | +            } | 
|  | 89 | +        } | 
|  | 90 | +    } else { | 
|  | 91 | +        println!("Cached PII classifier not available, skipping batch test"); | 
|  | 92 | +    } | 
|  | 93 | +} | 
|  | 94 | + | 
|  | 95 | +/// Test cached model parallel PII detection (OPTIMIZED) | 
|  | 96 | +#[rstest] | 
|  | 97 | +#[serial] | 
|  | 98 | +fn test_pii_lora_pii_lora_classifier_parallel_detect( | 
|  | 99 | +    cached_pii_classifier: Option<Arc<PIILoRAClassifier>>, | 
|  | 100 | +) { | 
|  | 101 | +    if let Some(classifier) = cached_pii_classifier { | 
|  | 102 | +        println!("Testing parallel PII detection with cached model!"); | 
|  | 103 | +        { | 
|  | 104 | +            let test_texts = vec![ | 
|  | 105 | +                "My SSN is 123-45-6789", | 
|  | 106 | +                "Call me at (555) 123-4567", | 
|  | 107 | + | 
|  | 108 | +            ]; | 
|  | 109 | + | 
|  | 110 | +            match classifier.parallel_detect(&test_texts) { | 
|  | 111 | +                Ok(results) => { | 
|  | 112 | +                    println!( | 
|  | 113 | +                        "Real model parallel PII detection succeeded with {} results", | 
|  | 114 | +                        results.len() | 
|  | 115 | +                    ); | 
|  | 116 | +                    assert_eq!(results.len(), test_texts.len()); | 
|  | 117 | + | 
|  | 118 | +                    for (i, result) in results.iter().enumerate() { | 
|  | 119 | +                        println!("Parallel PII result {}: has_pii={}, types={:?}, confidence={:.3}, time={}ms", | 
|  | 120 | +                            i, result.has_pii, result.pii_types, result.confidence, result.processing_time_ms); | 
|  | 121 | + | 
|  | 122 | +                        // Validate each result | 
|  | 123 | +                        assert!(result.confidence >= 0.0 && result.confidence <= 1.0); | 
|  | 124 | +                        assert!(result.processing_time_ms > 0); | 
|  | 125 | + | 
|  | 126 | +                        // Check PII detection consistency | 
|  | 127 | +                        assert_eq!(result.has_pii, !result.pii_types.is_empty()); | 
|  | 128 | +                        assert_eq!(result.has_pii, !result.occurrences.is_empty()); | 
|  | 129 | + | 
|  | 130 | +                        // Validate occurrences if PII detected | 
|  | 131 | +                        if result.has_pii { | 
|  | 132 | +                            for occurrence in &result.occurrences { | 
|  | 133 | +                                assert!(!occurrence.pii_type.is_empty()); | 
|  | 134 | +                                assert!(!occurrence.token.is_empty()); | 
|  | 135 | +                                assert!( | 
|  | 136 | +                                    occurrence.confidence >= 0.0 && occurrence.confidence <= 1.0 | 
|  | 137 | +                                ); | 
|  | 138 | +                                assert!(occurrence.start_pos <= occurrence.end_pos); | 
|  | 139 | +                            } | 
|  | 140 | +                        } | 
|  | 141 | +                    } | 
|  | 142 | +                } | 
|  | 143 | +                Err(e) => { | 
|  | 144 | +                    println!("Real model parallel PII detection failed: {}", e); | 
|  | 145 | +                } | 
|  | 146 | +            } | 
|  | 147 | +        } | 
|  | 148 | +    } else { | 
|  | 149 | +        println!("Cached PII classifier not available, skipping parallel test"); | 
|  | 150 | +    } | 
|  | 151 | +} | 
|  | 152 | + | 
|  | 153 | +/// Test PIILoRAClassifier error handling with cached model (OPTIMIZED) | 
|  | 154 | +#[rstest] | 
|  | 155 | +#[serial] | 
|  | 156 | +fn test_pii_lora_pii_lora_classifier_error_handling( | 
|  | 157 | +    cached_pii_classifier: Option<Arc<PIILoRAClassifier>>, | 
|  | 158 | +) { | 
|  | 159 | +    if let Some(classifier) = cached_pii_classifier { | 
|  | 160 | +        println!("Testing error handling with cached model!"); | 
|  | 161 | + | 
|  | 162 | +        // Test with cached model first (should work) | 
|  | 163 | +        let test_text = "Test error handling"; | 
|  | 164 | +        match classifier.detect_pii(test_text) { | 
|  | 165 | +            Ok(_) => println!("Cached model error handling test passed"), | 
|  | 166 | +            Err(e) => println!("Cached model error: {}", e), | 
|  | 167 | +        } | 
|  | 168 | +    } else { | 
|  | 169 | +        println!("Cached PII classifier not available, skipping error handling test"); | 
|  | 170 | +    } | 
|  | 171 | + | 
|  | 172 | +    // Test error scenarios with invalid paths | 
|  | 173 | +    let invalid_model_result = PIILoRAClassifier::new("", true); | 
|  | 174 | +    assert!(invalid_model_result.is_err()); | 
|  | 175 | + | 
|  | 176 | +    let nonexistent_model_result = PIILoRAClassifier::new("/nonexistent/path/to/model", true); | 
|  | 177 | +    assert!(nonexistent_model_result.is_err()); | 
|  | 178 | + | 
|  | 179 | +    println!("PIILoRAClassifier error handling test passed"); | 
|  | 180 | +} | 
|  | 181 | + | 
|  | 182 | +/// Test PII detection output format with cached model (OPTIMIZED) | 
|  | 183 | +#[rstest] | 
|  | 184 | +#[serial] | 
|  | 185 | +fn test_pii_lora_pii_detection_output_format( | 
|  | 186 | +    cached_pii_classifier: Option<Arc<PIILoRAClassifier>>, | 
|  | 187 | +) { | 
|  | 188 | +    if let Some(classifier) = cached_pii_classifier { | 
|  | 189 | +        println!("Testing PII detection output format with cached model!"); | 
|  | 190 | + | 
|  | 191 | +        let test_text = "My name is John Doe and my email is [email protected]"; | 
|  | 192 | +        match classifier.detect_pii(test_text) { | 
|  | 193 | +            Ok(result) => { | 
|  | 194 | +                // Test output format | 
|  | 195 | +                assert!(result.confidence >= 0.0 && result.confidence <= 1.0); | 
|  | 196 | +                assert!(result.processing_time_ms > 0); | 
|  | 197 | + | 
|  | 198 | +                // Test PII types format (adapt to real model output) | 
|  | 199 | +                for pii_type in &result.pii_types { | 
|  | 200 | +                    assert!(!pii_type.is_empty()); | 
|  | 201 | +                    assert!(pii_type | 
|  | 202 | +                        .chars() | 
|  | 203 | +                        .all(|c| c.is_ascii_alphabetic() || c == '_' || c == '-')); | 
|  | 204 | +                    println!("  Detected PII type: '{}'", pii_type); | 
|  | 205 | +                } | 
|  | 206 | + | 
|  | 207 | +                println!("PII detection output format test passed with cached model"); | 
|  | 208 | +            } | 
|  | 209 | +            Err(e) => { | 
|  | 210 | +                println!("PII detection failed: {}", e); | 
|  | 211 | +            } | 
|  | 212 | +        } | 
|  | 213 | +    } else { | 
|  | 214 | +        println!("Cached PII classifier not available, skipping output format test"); | 
|  | 215 | +    } | 
|  | 216 | +} | 
|  | 217 | + | 
|  | 218 | +/// Test PII type classification with cached model (OPTIMIZED) | 
|  | 219 | +#[rstest] | 
|  | 220 | +#[serial] | 
|  | 221 | +fn test_pii_lora_pii_type_classification(cached_pii_classifier: Option<Arc<PIILoRAClassifier>>) { | 
|  | 222 | +    if let Some(classifier) = cached_pii_classifier { | 
|  | 223 | +        println!("Testing PII type classification with cached model!"); | 
|  | 224 | + | 
|  | 225 | +        let test_text = "My name is John Doe and my email is [email protected]"; | 
|  | 226 | +        match classifier.detect_pii(test_text) { | 
|  | 227 | +            Ok(result) => { | 
|  | 228 | +                for pii_type in &result.pii_types { | 
|  | 229 | +                    assert!(pii_type | 
|  | 230 | +                        .chars() | 
|  | 231 | +                        .all(|c| c.is_ascii_alphabetic() || c == '_' || c == '-')); | 
|  | 232 | +                    println!("  Detected PII type: '{}'", pii_type); | 
|  | 233 | +                } | 
|  | 234 | +                println!("PII type classification test passed with cached model"); | 
|  | 235 | +            } | 
|  | 236 | +            Err(e) => println!("PII type classification failed: {}", e), | 
|  | 237 | +        } | 
|  | 238 | +    } else { | 
|  | 239 | +        println!("Cached PII classifier not available, skipping type classification test"); | 
|  | 240 | +    } | 
|  | 241 | +} | 
|  | 242 | + | 
|  | 243 | +/// Test token-level PII detection with cached model (OPTIMIZED) | 
|  | 244 | +#[rstest] | 
|  | 245 | +#[serial] | 
|  | 246 | +fn test_pii_lora_token_level_pii_detection(cached_pii_classifier: Option<Arc<PIILoRAClassifier>>) { | 
|  | 247 | +    if let Some(classifier) = cached_pii_classifier { | 
|  | 248 | +        println!("Testing token-level PII detection with cached model!"); | 
|  | 249 | + | 
|  | 250 | +        let test_text = "My name is John Doe and my email is [email protected]"; | 
|  | 251 | +        match classifier.detect_pii(test_text) { | 
|  | 252 | +            Ok(result) => { | 
|  | 253 | +                // Test token-level detection | 
|  | 254 | +                for occurrence in &result.occurrences { | 
|  | 255 | +                    assert!(occurrence.start_pos <= occurrence.end_pos); | 
|  | 256 | +                    assert!(!occurrence.pii_type.is_empty()); | 
|  | 257 | +                    assert!(occurrence.confidence >= 0.0 && occurrence.confidence <= 1.0); | 
|  | 258 | +                    println!( | 
|  | 259 | +                        "  Token PII: '{}' at {}:{}, type='{}', confidence={:.3}", | 
|  | 260 | +                        occurrence.token, | 
|  | 261 | +                        occurrence.start_pos, | 
|  | 262 | +                        occurrence.end_pos, | 
|  | 263 | +                        occurrence.pii_type, | 
|  | 264 | +                        occurrence.confidence | 
|  | 265 | +                    ); | 
|  | 266 | +                } | 
|  | 267 | +                println!("Token-level PII detection test passed with cached model"); | 
|  | 268 | +            } | 
|  | 269 | +            Err(e) => println!("Token-level PII detection failed: {}", e), | 
|  | 270 | +        } | 
|  | 271 | +    } else { | 
|  | 272 | +        println!("Cached PII classifier not available, skipping token-level test"); | 
|  | 273 | +    } | 
|  | 274 | +} | 
|  | 275 | + | 
|  | 276 | +/// Performance test for PIILoRAClassifier cached model operations (OPTIMIZED) | 
|  | 277 | +#[rstest] | 
|  | 278 | +#[serial] | 
|  | 279 | +fn test_pii_lora_pii_lora_classifier_performance( | 
|  | 280 | +    cached_pii_classifier: Option<Arc<PIILoRAClassifier>>, | 
|  | 281 | +) { | 
|  | 282 | +    if let Some(classifier) = cached_pii_classifier { | 
|  | 283 | +        println!("Testing PIILoRAClassifier cached model performance"); | 
|  | 284 | + | 
|  | 285 | +        let test_texts = vec![ | 
|  | 286 | +            "My name is John Doe and my email is [email protected]", | 
|  | 287 | +            "Contact Alice at [email protected] or call 555-1234", | 
|  | 288 | +            "The weather is nice today", | 
|  | 289 | +        ]; | 
|  | 290 | + | 
|  | 291 | +        let (_, total_duration) = measure_execution_time(|| { | 
|  | 292 | +            for text in &test_texts { | 
|  | 293 | +                let (_, single_duration) = | 
|  | 294 | +                    measure_execution_time(|| match classifier.detect_pii(text) { | 
|  | 295 | +                        Ok(result) => { | 
|  | 296 | +                            assert!(result.confidence >= 0.0 && result.confidence <= 1.0); | 
|  | 297 | +                            assert!(result.processing_time_ms > 0); | 
|  | 298 | +                        } | 
|  | 299 | +                        Err(e) => println!("Performance test failed for '{}': {}", text, e), | 
|  | 300 | +                    }); | 
|  | 301 | +                assert!( | 
|  | 302 | +                    single_duration.as_secs() < 15, | 
|  | 303 | +                    "Single PII detection took too long: {:?}", | 
|  | 304 | +                    single_duration | 
|  | 305 | +                ); | 
|  | 306 | +            } | 
|  | 307 | +        }); | 
|  | 308 | + | 
|  | 309 | +        assert!( | 
|  | 310 | +            total_duration.as_secs() < 60, | 
|  | 311 | +            "Batch PII processing took too long: {:?}", | 
|  | 312 | +            total_duration | 
|  | 313 | +        ); | 
|  | 314 | +        println!( | 
|  | 315 | +            "PIILoRAClassifier cached model performance: {} texts in {:?}", | 
|  | 316 | +            test_texts.len(), | 
|  | 317 | +            total_duration | 
|  | 318 | +        ); | 
|  | 319 | +    } else { | 
|  | 320 | +        println!("Cached PII classifier not available, skipping performance test"); | 
|  | 321 | +    } | 
|  | 322 | +} | 
0 commit comments