diff --git a/tests/it_context_optimizer.rs b/tests/it_context_optimizer.rs new file mode 100644 index 0000000..12f2707 --- /dev/null +++ b/tests/it_context_optimizer.rs @@ -0,0 +1,212 @@ +//! Integration tests for M3.8 Context Optimizer +//! +//! Tests the full 4-stage pipeline: Detection → Compression → CCR → Integration + +use mem_core::{ContextOptimizer, ContextOptimizerConfig, ContentType}; + +#[test] +fn test_optimizer_detects_json() { + let optimizer = ContextOptimizer::new().expect("failed to create optimizer"); + let json = r#"{"status": "success", "count": 42, "items": [1, 2, 3]}"#; + + let result = optimizer.optimize(json).expect("optimize failed"); + assert_eq!(result.content_type, ContentType::Json); + assert!(result.original_tokens > 0); +} + +#[test] +fn test_optimizer_detects_log() { + let optimizer = ContextOptimizer::new().expect("failed to create optimizer"); + let log = "ERROR: connection timeout at 2026-08-28T09:15:00Z\n at main.rs:42"; + + let result = optimizer.optimize(log).expect("optimize failed"); + assert_eq!(result.content_type, ContentType::Log); +} + +#[test] +fn test_optimizer_detects_code() { + let optimizer = ContextOptimizer::new().expect("failed to create optimizer"); + let code = r#" +fn main() { + println!("hello"); +} + "#; + + let result = optimizer.optimize(code).expect("optimize failed"); + assert_eq!(result.content_type, ContentType::Code); +} + +#[test] +fn test_optimizer_compresses_npm_logs() { + let optimizer = ContextOptimizer::new().expect("failed to create optimizer"); + + let npm_log = r#" +npm WARN deprecated info@0.8.0: package no longer supported +npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.3.2 +npm notice created a lockfile as package-lock.json. +npm ERR! 404 Not Found - GET https://registry.npmjs.org/react@99.0.0 +npm ERR! 404 +npm ERR! It is likely you are behind a proxy. +npm ERR! A complete log of this error: +npm ERR! /home/user/.npm/_logs/error.log + "#; + + let result = optimizer.optimize(npm_log).expect("optimize failed"); + + // Should detect as log + assert_eq!(result.content_type, ContentType::Log); + + // Should compress + assert!(result.compressed_tokens < result.original_tokens); + + // Should keep error markers + assert!(result.compressed.to_lowercase().contains("npm err!")); + assert!(result.compressed.contains("404")); + + // Should drop noise + assert!(!result.compressed.contains("WARN deprecated")); + assert!(!result.compressed.contains("notice created")); +} + +#[test] +fn test_optimizer_handles_json_array() { + let optimizer = ContextOptimizer::new().expect("failed to create optimizer"); + + let json_array = r#" +[ + {"id": 1, "name": "Alice", "status": "active"}, + {"id": 2, "name": "Bob", "status": "inactive"}, + {"id": 3, "name": "Charlie", "status": "active"}, + {"id": 4, "name": "Diana", "status": "active"} +] + "#; + + let result = optimizer.optimize(json_array).expect("optimize failed"); + + // Should detect JSON + assert_eq!(result.content_type, ContentType::Json); + assert!(result.original_tokens > 0); +} + +#[test] +fn test_optimizer_detects_diff() { + let optimizer = ContextOptimizer::new().expect("failed to create optimizer"); + + let diff = r#"--- a/config.yaml ++++ b/config.yaml +@@ -1,3 +1,3 @@ + server: + host: localhost +- port: 8080 ++ port: 9000 + "#; + + let result = optimizer.optimize(diff).expect("optimize failed"); + assert_eq!(result.content_type, ContentType::Diff); +} + +#[test] +fn test_optimizer_passthrough_when_disabled() { + let config = ContextOptimizerConfig { + enabled: false, + ..Default::default() + }; + let optimizer = ContextOptimizer::with_config(config).expect("failed to create optimizer"); + + let content = "ERROR: something failed"; + let result = optimizer.optimize(content).expect("optimize failed"); + + // Should be unchanged + assert_eq!(result.compressed, content); + assert_eq!(result.original_tokens, result.compressed_tokens); +} + +#[test] +fn test_optimizer_with_compression_disabled() { + let config = ContextOptimizerConfig { + enabled: true, + compress_logs: false, + ..Default::default() + }; + let optimizer = ContextOptimizer::with_config(config).expect("failed to create optimizer"); + + let log = "ERROR: connection timeout\nWARN: slow response\nINFO: connected"; + let result = optimizer.optimize(log).expect("optimize failed"); + + // Should be unchanged since compression is disabled + assert_eq!(result.compressed, log); +} + +#[test] +fn test_optimizer_token_counting() { + let optimizer = ContextOptimizer::new().expect("failed to create optimizer"); + + let short = "hello world"; + let short_result = optimizer.optimize(short).expect("optimize failed"); + + let long = "This is a much longer piece of text with many words to test the token counting. ".repeat(10); + let long_result = optimizer.optimize(&long).expect("optimize failed"); + + // Longer text should have more tokens + assert!(long_result.original_tokens > short_result.original_tokens); +} + +#[test] +fn test_optimizer_with_cargo_error() { + let optimizer = ContextOptimizer::new().expect("failed to create optimizer"); + + let cargo_error = r#" + Compiling myapp v0.1.0 +error[E0425]: cannot find value `unknown_var` in this scope + --> src/main.rs:42:5 + | + 42 | unknown_var = 42; + | ^^^^^^^^^^^ not found in this scope + +error: aborting due to 1 previous error + "#; + + let result = optimizer.optimize(cargo_error).expect("optimize failed"); + + // Should detect as log + assert_eq!(result.content_type, ContentType::Log); + + // Should keep error lines + assert!(result.compressed.contains("error[E0425]")); + assert!(result.compressed.contains("src/main.rs:42")); + + // Should drop compilation noise + assert!(!result.compressed.contains("Compiling myapp")); +} + +#[test] +fn test_optimizer_real_world_scenario() { + let optimizer = ContextOptimizer::new().expect("failed to create optimizer"); + + // Simulate a chunk from a real failure log with mixed content + let mixed_content = r#" +2026-08-28T09:15:00Z DEBUG: Starting npm install +npm WARN deprecated info@0.8.0: package no longer supported +npm notice created a lockfile +npm WARN optional SKIPPING OPTIONAL DEPENDENCY +2026-08-28T09:15:05Z INFO: dependency resolution +npm ERR! 404 Not Found - GET https://registry.npmjs.org/react@99.0.0 +npm ERR! 404 +npm ERR! It is likely you are behind a proxy +npm ERR! A complete log: /home/user/.npm/_logs/error.log +2026-08-28T09:15:10Z WARN: slow network + "#; + + let result = optimizer.optimize(mixed_content).expect("optimize failed"); + + // Should detect as log (has timestamps + errors) + assert_eq!(result.content_type, ContentType::Log); + + // Should reduce size + assert!(result.compressed.len() < mixed_content.len()); + + // Should preserve critical information + assert!(result.compressed.to_lowercase().contains("npm err!")); + assert!(result.compressed.contains("404")); + assert!(result.compressed.contains("2026-08-28")); // Timestamps may be kept +}