use super::*;
#[allow(unused_imports)]
use proptest::prelude::*;
#[allow(unused_imports)]
use std::collections::HashMap;
#[allow(unused_imports)]
use std::path::PathBuf;
#[test]
fn test_pattern_type_equality() {
assert_eq!(PatternType::ErrorHandling, PatternType::ErrorHandling);
assert_ne!(PatternType::ErrorHandling, PatternType::DataValidation);
}
#[test]
fn test_pattern_collection() {
let mut collection = PatternCollection::new();
assert_eq!(collection.file_count(), 0);
let pattern = AstPattern {
pattern_type: PatternType::ErrorHandling,
pattern_hash: "test123".to_string(),
frequency: 3,
locations: vec![],
variation_score: 0.0,
example_code: "test".to_string(),
estimated_loc: 10,
};
collection.add_pattern(pattern);
let summary = collection.summary();
assert_eq!(summary.repetitions, 3);
assert_eq!(summary.pattern_type, PatternType::ErrorHandling);
}
#[test]
fn test_extract_error_handling_patterns() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let file_path = PathBuf::from("test.rs");
let content = r#"
fn foo() {
match bar() -> Result<i32, Error> {
Ok(x) => Ok(x),
Err(e) => Err(e),
}
}
fn baz() {
match qux() -> Result<i32, Error> {
Ok(x) => Ok(x),
Err(e) => Err(e),
}
}
fn quux() {
match waldo() -> Result<i32, Error> {
Ok(x) => Ok(x),
Err(e) => Err(e),
}
}
"#;
let mut collection = PatternCollection::new();
extractor
.extract_error_handling_patterns(&file_path, content, &mut collection)
.expect("Pattern extraction should succeed");
assert!(
!collection.patterns.is_empty(),
"Should extract error handling patterns with >=3 structurally identical Result matches"
);
}
#[test]
fn test_extract_control_flow_patterns() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let file_path = PathBuf::from("test.rs");
let mut content = String::from("fn foo(x: i32) {\n if x > 10 {\n");
content.push_str(" } else if x > 5 {\n } else if x > 5 {\n } else if x > 5 {\n }\n}\n");
let mut collection = PatternCollection::new();
extractor
.extract_control_flow_patterns(&file_path, &content, &mut collection)
.expect("Pattern extraction should succeed");
assert!(
!collection.patterns.is_empty(),
"Should extract control flow patterns with >=3 structurally identical else-if chains"
);
}
#[test]
fn test_extract_data_transformation_patterns() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let file_path = PathBuf::from("test.rs");
let content = r#"
fn process1() {
items.iter().filter(|x| x > 0).map(|x| x + 1).collect()
}
fn process2() {
items.iter().filter(|x| x > 0).map(|x| x + 1).collect()
}
fn process3() {
items.iter().filter(|x| x > 0).map(|x| x + 1).collect()
}
fn process4() {
items.iter().filter(|x| x > 0).map(|x| x + 1).collect()
}
fn process5() {
items.iter().filter(|x| x > 0).map(|x| x + 1).collect()
}
"#;
let mut collection = PatternCollection::new();
extractor
.extract_data_transformation_patterns(&file_path, content, &mut collection)
.expect("Pattern extraction should succeed");
assert!(
!collection.patterns.is_empty(),
"Should extract data transformation patterns with >=3 structurally identical combinator calls"
);
}
#[test]
fn test_extract_api_call_patterns() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let file_path = PathBuf::from("test.rs");
let content = r#"
async fn fetch_data() {
let r1 = client.post("/endpoint", body).await;
let r2 = client.post("/endpoint", body).await;
let r3 = client.post("/endpoint", body).await;
let r4 = client.post("/endpoint", body).await;
}
"#;
let mut collection = PatternCollection::new();
extractor
.extract_api_call_patterns(&file_path, content, &mut collection)
.expect("Pattern extraction should succeed");
assert!(
!collection.patterns.is_empty(),
"Should extract API call patterns with >=3 structurally identical HTTP calls"
);
}
#[test]
fn test_extract_resource_management_patterns() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let file_path = PathBuf::from("test.rs");
let content = r#"
fn foo() {
let guard = mutex.lock();
let guard = mutex.lock();
let guard = mutex.lock();
let handle = resource.open();
let handle = resource.open();
let handle = resource.open();
}
"#;
let mut collection = PatternCollection::new();
extractor
.extract_resource_management_patterns(&file_path, content, &mut collection)
.expect("Pattern extraction should succeed");
assert!(
!collection.patterns.is_empty(),
"Should extract resource management patterns with >=3 structurally identical calls"
);
}
#[test]
fn test_extract_data_validation_patterns() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let file_path = PathBuf::from("test.rs");
let content = r#"
fn validate(input: &str) -> bool {
if input.is_empty() && input.len() > 0 {
return false;
}
if input.is_empty() && input.len() > 0 {
return false;
}
if input.is_empty() && input.len() > 0 {
return false;
}
if data.is_empty() && data.len() > 0 {
return false;
}
if name.is_empty() && name.len() > 0 {
return false;
}
if buf.is_empty() && buf.len() > 0 {
return false;
}
true
}
"#;
let mut collection = PatternCollection::new();
extractor
.extract_data_validation_patterns(&file_path, content, &mut collection)
.expect("Pattern extraction should succeed");
assert!(
!collection.patterns.is_empty(),
"Should extract data validation patterns with >=3 structurally identical compound checks"
);
}
#[test]
fn test_pattern_collection_get_patterns_for_file() {
let mut collection = PatternCollection::new();
let file_path = PathBuf::from("test.rs");
let pattern = AstPattern {
pattern_type: PatternType::ErrorHandling,
pattern_hash: "hash1".to_string(),
frequency: 5,
locations: vec![],
variation_score: 0.3,
example_code: "test code".to_string(),
estimated_loc: 20,
};
collection.add_pattern(pattern);
collection
.file_patterns
.insert(file_path.clone(), vec!["hash1".to_string()]);
let patterns = collection.get_patterns_for_file(&file_path);
assert_eq!(patterns.len(), 1, "Should retrieve pattern for file");
assert_eq!(patterns[0].pattern_hash, "hash1");
}
#[test]
fn test_empty_content_no_patterns() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let file_path = PathBuf::from("empty.rs");
let content = "";
let mut collection = PatternCollection::new();
extractor
.extract_error_handling_patterns(&file_path, content, &mut collection)
.expect("Should handle empty content");
assert!(
collection.patterns.is_empty(),
"Empty content should produce no patterns"
);
}
#[allow(unused_imports)]
use proptest::prelude::*;
proptest! {
#[test]
fn basic_property_stability(_input in ".*") {
prop_assert!(true);
}
#[test]
fn module_consistency_check(_x in 0u32..1000) {
prop_assert!(_x < 1001);
}
}
#[allow(unused_imports)]
use super::*;
#[test]
fn test_pattern_type_hash() {
use std::collections::HashMap;
let mut map = HashMap::new();
map.insert(PatternType::ErrorHandling, 1);
map.insert(PatternType::DataValidation, 2);
map.insert(PatternType::ResourceManagement, 3);
map.insert(PatternType::ControlFlow, 4);
map.insert(PatternType::DataTransformation, 5);
map.insert(PatternType::ApiCall, 6);
assert_eq!(map.len(), 6);
}
#[test]
fn test_pattern_type_clone_and_copy() {
let pt = PatternType::ErrorHandling;
let pt2 = pt; let pt3 = pt.clone(); assert_eq!(pt, pt2);
assert_eq!(pt, pt3);
}
#[test]
fn test_pattern_type_serialization() {
let pt = PatternType::DataValidation;
let json = serde_json::to_string(&pt).unwrap();
let deserialized: PatternType = serde_json::from_str(&json).unwrap();
assert_eq!(pt, deserialized);
}
#[test]
fn test_location_creation() {
let loc = Location {
file: PathBuf::from("test.rs"),
line: 42,
column: 10,
};
assert_eq!(loc.file, PathBuf::from("test.rs"));
assert_eq!(loc.line, 42);
assert_eq!(loc.column, 10);
}
#[test]
fn test_location_clone_and_debug() {
let loc = Location {
file: PathBuf::from("src/lib.rs"),
line: 100,
column: 5,
};
let cloned = loc.clone();
assert_eq!(format!("{:?}", loc), format!("{:?}", cloned));
}
#[test]
fn test_location_serialization() {
let loc = Location {
file: PathBuf::from("test.rs"),
line: 1,
column: 1,
};
let json = serde_json::to_string(&loc).unwrap();
let deserialized: Location = serde_json::from_str(&json).unwrap();
assert_eq!(loc.line, deserialized.line);
assert_eq!(loc.column, deserialized.column);
}
#[test]
fn test_ast_pattern_creation() {
let pattern = AstPattern {
pattern_type: PatternType::ControlFlow,
pattern_hash: "abc123".to_string(),
frequency: 5,
locations: vec![],
variation_score: 0.5,
example_code: "if x > 0 {}".to_string(),
estimated_loc: 10,
};
assert_eq!(pattern.frequency, 5);
assert_eq!(pattern.variation_score, 0.5);
}
#[test]
fn test_ast_pattern_clone() {
let pattern = AstPattern {
pattern_type: PatternType::ApiCall,
pattern_hash: "hash".to_string(),
frequency: 3,
locations: vec![Location {
file: PathBuf::from("api.rs"),
line: 10,
column: 1,
}],
variation_score: 0.2,
example_code: "client.get()".to_string(),
estimated_loc: 5,
};
let cloned = pattern.clone();
assert_eq!(pattern.pattern_hash, cloned.pattern_hash);
assert_eq!(pattern.frequency, cloned.frequency);
}
#[test]
fn test_pattern_collection_default() {
let collection = PatternCollection::default();
assert_eq!(collection.file_count(), 0);
assert!(collection.patterns.is_empty());
}
#[test]
fn test_pattern_collection_summary_with_patterns() {
let mut collection = PatternCollection::new();
collection.add_pattern(AstPattern {
pattern_type: PatternType::ErrorHandling,
pattern_hash: "error1".to_string(),
frequency: 5,
locations: vec![],
variation_score: 0.1,
example_code: "match result {}".to_string(),
estimated_loc: 10,
});
collection.add_pattern(AstPattern {
pattern_type: PatternType::DataValidation,
pattern_hash: "validate1".to_string(),
frequency: 10, locations: vec![],
variation_score: 0.3,
example_code: "if input.is_empty()".to_string(),
estimated_loc: 5,
});
let summary = collection.summary();
assert_eq!(summary.repetitions, 10);
assert_eq!(summary.pattern_type, PatternType::DataValidation);
}
#[test]
fn test_pattern_collection_get_patterns_nonexistent_file() {
let collection = PatternCollection::new();
let patterns = collection.get_patterns_for_file(Path::new("nonexistent.rs"));
assert!(patterns.is_empty());
}
#[test]
fn test_pattern_collection_with_file_patterns() {
let mut collection = PatternCollection::new();
let file_path = PathBuf::from("src/main.rs");
collection.add_pattern(AstPattern {
pattern_type: PatternType::ControlFlow,
pattern_hash: "cf_1".to_string(),
frequency: 2,
locations: vec![Location {
file: file_path.clone(),
line: 10,
column: 1,
}],
variation_score: 0.0,
example_code: "if".to_string(),
estimated_loc: 3,
});
collection
.file_patterns
.insert(file_path.clone(), vec!["cf_1".to_string()]);
let patterns = collection.get_patterns_for_file(&file_path);
assert_eq!(patterns.len(), 1);
assert_eq!(patterns[0].pattern_hash, "cf_1");
}
#[test]
fn test_pattern_extractor_creation() {
let config = EntropyConfig::default();
let extractor = PatternExtractor::new(config);
let _ = extractor;
}
#[test]
fn test_should_process_file_included() {
let config = EntropyConfig {
exclude_paths: vec!["**/tests/**".to_string()],
..EntropyConfig::default()
};
let extractor = PatternExtractor::new(config);
assert!(extractor.should_process_file(Path::new("src/lib.rs")));
assert!(extractor.should_process_file(Path::new("src/main.rs")));
}
#[test]
fn test_should_process_file_excluded() {
let config = EntropyConfig {
exclude_paths: vec!["**/target/**".to_string()],
..EntropyConfig::default()
};
let extractor = PatternExtractor::new(config);
assert!(!extractor.should_process_file(Path::new("target/debug/build.rs")));
}
#[test]
fn test_hash_pattern() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let hash1 = extractor.hash_pattern("test pattern 1");
let hash2 = extractor.hash_pattern("test pattern 2");
let hash3 = extractor.hash_pattern("test pattern 1");
assert_ne!(hash1, hash2);
assert_eq!(hash1, hash3);
}
#[test]
fn test_calculate_variation_score_single_match() {
use regex::Regex;
let extractor = PatternExtractor::new(EntropyConfig::default());
let content = "fn foo() {}";
let pattern = Regex::new(r"fn").unwrap();
let matches: Vec<_> = pattern.find_iter(content).collect();
let score = extractor.calculate_variation_score(&matches, content);
assert_eq!(score, 0.0);
}
#[test]
fn test_calculate_variation_score_multiple_similar() {
use regex::Regex;
let extractor = PatternExtractor::new(EntropyConfig::default());
let content = "fn foo() {} fn bar() {} fn baz() {}";
let pattern = Regex::new(r"fn \w+").unwrap();
let matches: Vec<_> = pattern.find_iter(content).collect();
let score = extractor.calculate_variation_score(&matches, content);
assert!(score >= 0.0 && score <= 1.0);
}
#[test]
fn test_calculate_string_similarity_identical() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let similarity = extractor.calculate_string_similarity("foo bar", "foo bar");
assert_eq!(similarity, 1.0);
}
#[test]
fn test_calculate_string_similarity_different() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let similarity = extractor.calculate_string_similarity("foo bar", "baz qux");
assert_eq!(similarity, 0.0);
}
#[test]
fn test_calculate_string_similarity_partial() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let similarity = extractor.calculate_string_similarity("foo bar baz", "foo bar qux");
assert!(similarity > 0.0 && similarity < 1.0);
}
#[test]
fn test_calculate_string_similarity_empty() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let similarity = extractor.calculate_string_similarity("", "");
assert_eq!(similarity, 0.0);
}
#[test]
fn test_calculate_pattern_variations() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let mut collection = PatternCollection::new();
collection.add_pattern(AstPattern {
pattern_type: PatternType::ControlFlow,
pattern_hash: "test".to_string(),
frequency: 3,
locations: vec![
Location {
file: PathBuf::from("a.rs"),
line: 1,
column: 1,
},
Location {
file: PathBuf::from("b.rs"),
line: 2,
column: 1,
},
Location {
file: PathBuf::from("c.rs"),
line: 3,
column: 1,
},
],
variation_score: 0.0,
example_code: "test".to_string(),
estimated_loc: 5,
});
extractor.calculate_pattern_variations(&mut collection);
let pattern = collection.patterns.get("test").unwrap();
assert!(pattern.variation_score >= 0.0 && pattern.variation_score <= 1.0);
}
#[test]
fn test_extract_ruchy_actor_patterns_with_actors() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let file_path = PathBuf::from("test.ruchy");
let content = r#"
actor Counter {
state: i32
}
actor Logger {
buffer: String
}
receive increment(value: i32) {
self.state += value
}
receive log(msg: String) {
self.buffer.push_str(&msg)
}
receive clear() {
self.buffer.clear()
}
"#;
let mut collection = PatternCollection::new();
extractor
.extract_ruchy_actor_patterns(&file_path, content, &mut collection)
.expect("Should extract patterns");
assert!(!collection.patterns.is_empty());
}
#[test]
fn test_extract_ruchy_actor_patterns_no_actors() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let file_path = PathBuf::from("test.ruchy");
let content = "fn main() { println!(\"hello\"); }";
let mut collection = PatternCollection::new();
extractor
.extract_ruchy_actor_patterns(&file_path, content, &mut collection)
.expect("Should handle empty result");
assert!(collection.patterns.is_empty());
}
#[test]
fn test_extract_ruchy_pipeline_patterns() {
use regex::Regex;
let extractor = PatternExtractor::new(EntropyConfig::default());
let file_path = PathBuf::from("test.ruchy");
let content = "data |> transform(x) |> filter(y) |> map(z) |> reduce(w) |> collect()";
let simple_pattern = Regex::new(r"\|>").unwrap();
let simple_matches: Vec<_> = simple_pattern.find_iter(content).collect();
assert!(
simple_matches.len() >= 5,
"Expected >= 5 pipe-greater-than, got {}: {:?}",
simple_matches.len(),
simple_matches
.iter()
.map(|m| m.as_str())
.collect::<Vec<_>>()
);
let mut collection = PatternCollection::new();
extractor
.extract_ruchy_pipeline_patterns(&file_path, content, &mut collection)
.expect("Should extract patterns");
}
#[test]
fn test_extract_ruchy_pipeline_patterns_insufficient() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let file_path = PathBuf::from("test.ruchy");
let content = "let x = a |> b();";
let mut collection = PatternCollection::new();
extractor
.extract_ruchy_pipeline_patterns(&file_path, content, &mut collection)
.expect("Should handle insufficient patterns");
assert!(collection.patterns.is_empty());
}
#[test]
fn test_extract_ruchy_message_passing_patterns() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let file_path = PathBuf::from("test.ruchy");
let content = r#"
counter <- increment(5)
logger <- log("test")
result <? query_status()
"#;
let mut collection = PatternCollection::new();
extractor
.extract_ruchy_message_passing_patterns(&file_path, content, &mut collection)
.expect("Should extract patterns");
assert!(!collection.patterns.is_empty());
}
#[test]
fn test_extract_ruchy_error_handling_patterns() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let file_path = PathBuf::from("test.ruchy");
let content = r#"
match get_value() -> Result<i32, Error> {
Ok(v) => v,
Err(e) => 0,
}
match parse_input() -> Result<String, Error> {
Ok(s) => s,
Err(_) => "default".to_string(),
}
"#;
let mut collection = PatternCollection::new();
extractor
.extract_ruchy_error_handling_patterns(&file_path, content, &mut collection)
.expect("Should extract patterns");
assert!(!collection.patterns.is_empty());
}
#[test]
fn test_extract_ruchy_pattern_matching_patterns() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let file_path = PathBuf::from("test.ruchy");
let content = r#"
enum State { Active, Inactive, Pending }
enum Command { Start, Stop, Pause, Resume }
match state {
State::Active => "active",
State::Inactive => "inactive",
State::Pending => "pending",
}
match command {
Command::Start => start(),
Command::Stop => stop(),
Command::Pause => pause(),
Command::Resume => resume(),
}
"#;
let mut collection = PatternCollection::new();
extractor
.extract_ruchy_pattern_matching_patterns(&file_path, content, &mut collection)
.expect("Should extract patterns");
assert!(!collection.patterns.is_empty());
}
#[test]
fn test_calculate_actor_variation_score_empty() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let score = extractor.calculate_actor_variation_score(&[], &[], "");
assert_eq!(score, 0.0);
}
#[test]
fn test_calculate_pipeline_variation_score_single() {
use regex::Regex;
let extractor = PatternExtractor::new(EntropyConfig::default());
let content = "|> transform(x)";
let pattern = Regex::new(r"\|\>").unwrap();
let matches: Vec<_> = pattern.find_iter(content).collect();
let score = extractor.calculate_pipeline_variation_score(&matches, content);
assert_eq!(score, 0.0);
}
#[test]
fn test_calculate_messaging_variation_score() {
use regex::Regex;
let extractor = PatternExtractor::new(EntropyConfig::default());
let content = "counter <- inc(1) counter <- inc(2) counter <- inc(3)";
let send_pattern = Regex::new(r"<-").unwrap();
let query_pattern = Regex::new(r"<\?").unwrap();
let sends: Vec<_> = send_pattern.find_iter(content).collect();
let queries: Vec<_> = query_pattern.find_iter(content).collect();
let score = extractor.calculate_messaging_variation_score(&sends, &queries, content);
assert!(score >= 0.0 && score <= 1.0);
}
#[test]
fn test_calculate_pattern_match_variation_score() {
use regex::Regex;
let extractor = PatternExtractor::new(EntropyConfig::default());
let content = r#"
enum A { X, Y }
enum B { P, Q }
match a { A::X => 1, A::Y => 2 }
match b { B::P => 3, B::Q => 4 }
"#;
let enum_pattern = Regex::new(r"enum\s+\w+\s*\{").unwrap();
let match_pattern = Regex::new(r"match\s+\w+\s*\{").unwrap();
let arrow_pattern = Regex::new(r"\w+::\w+\s*=>").unwrap();
let enums: Vec<_> = enum_pattern.find_iter(content).collect();
let matches: Vec<_> = match_pattern.find_iter(content).collect();
let arrows: Vec<_> = arrow_pattern.find_iter(content).collect();
let score =
extractor.calculate_pattern_match_variation_score(&enums, &matches, &arrows, content);
assert!(score >= 0.0 && score <= 1.0);
}
#[test]
fn test_extract_file_patterns_rust() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let file_path = PathBuf::from("test.rs");
let content = (0..8)
.map(|_| "if input.is_empty() && input.len() > 0 { return false; }".to_string())
.collect::<Vec<_>>()
.join("\n");
let mut collection = PatternCollection::new();
extractor
.extract_file_patterns(&file_path, &content, &mut collection)
.expect("Should extract patterns");
assert!(!collection.patterns.is_empty());
}
#[test]
fn test_extract_file_patterns_ruchy() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let file_path = PathBuf::from("test.ruchy");
let content = r#"
actor Counter {
value: i32
}
actor Logger {
buffer: Vec<String>
}
"#;
let mut collection = PatternCollection::new();
extractor
.extract_file_patterns(&file_path, content, &mut collection)
.expect("Should extract patterns");
}
#[test]
fn test_extract_file_patterns_rh_extension() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let file_path = PathBuf::from("test.rh");
let content = "actor Test {}";
let mut collection = PatternCollection::new();
extractor
.extract_file_patterns(&file_path, content, &mut collection)
.expect("Should handle .rh files");
}
#[test]
fn test_extract_file_patterns_generic() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let file_path = PathBuf::from("test.py"); let content = r#"
if x > 0:
pass
} else if x < 0 {
pass
} else if x == 0 {
pass
} else if True {
pass
}
"#;
let mut collection = PatternCollection::new();
extractor
.extract_file_patterns(&file_path, content, &mut collection)
.expect("Should handle generic files");
}
#[test]
fn test_extract_file_patterns_no_extension() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let file_path = PathBuf::from("Makefile");
let content = "all: build test";
let mut collection = PatternCollection::new();
let result = extractor.extract_file_patterns(&file_path, content, &mut collection);
assert!(result.is_ok());
}
#[test]
fn test_extract_patterns_with_unicode() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let file_path = PathBuf::from("test.rs");
let content = r#"
// 日本語コメント
if data.contains("こんにちは") && data.len() > 0 {
return true;
}
if data.contains("世界") && data.len() > 0 {
return true;
}
if data.contains("テスト") && data.len() > 0 {
return true;
}
if input.contains("日本") && input.len() > 0 {
return true;
}
if buf.contains("UTF-8") && buf.len() > 0 {
return true;
}
if name.contains("san") && name.len() > 0 {
return true;
}
"#;
let mut collection = PatternCollection::new();
extractor
.extract_data_validation_patterns(&file_path, content, &mut collection)
.expect("Should handle unicode");
assert!(!collection.patterns.is_empty());
}
#[test]
fn test_variation_score_utf8_boundary() {
use regex::Regex;
let extractor = PatternExtractor::new(EntropyConfig::default());
let content = "fn 日本語() {} fn テスト() {}";
let pattern = Regex::new(r"fn \S+\(\)").unwrap();
let matches: Vec<_> = pattern.find_iter(content).collect();
let score = extractor.calculate_variation_score(&matches, content);
assert!(score >= 0.0);
}
#[test]
fn test_limited_pattern_extraction() {
let extractor = PatternExtractor::new(EntropyConfig::default());
let file_path = PathBuf::from("test.rs");
let mut content = String::new();
for _ in 0..20 {
content.push_str("if input.is_empty() && input.len() > 0 { }\n");
}
let mut collection = PatternCollection::new();
extractor
.extract_data_validation_patterns(&file_path, &content, &mut collection)
.expect("Should limit patterns");
for pattern in collection.patterns.values() {
assert!(pattern.locations.len() <= 10);
}
}