use crate::common::*;
use llman::tool::command::CleanUselessCommentsArgs;
use llman::tool::config::ToolConfig;
use llman::tool::processor::CommentProcessor;
#[test]
fn test_config_default_values() {
let _env = TestEnvironment::new();
let config = ToolConfig::default();
assert_eq!(config.version, "0.1");
assert!(config.tools.clean_useless_comments.is_some());
let clean_config = config.tools.clean_useless_comments.unwrap();
assert!(!clean_config.scope.include.is_empty());
}
#[test]
fn test_config_yaml_parsing() {
let env = TestEnvironment::new();
let config_content = r#"
version: "0.1"
tools:
clean-useless-comments:
scope:
include:
- "**/*.py"
- "**/*.js"
exclude:
- "**/node_modules/**"
- "**/target/**"
lang-rules:
python:
single-line-comments: true
multi-line-comments: false
min-comment-length: 10
preserve-patterns:
- "^\\s*#\\s*(TODO|FIXME):"
javascript:
single-line-comments: true
multi-line-comments: true
doc-comments: false
min-comment-length: 15
preserve-patterns:
- "^\\s*//\\s*(TODO|FIXME):"
- "^\\s*/\\*\\*.*?\\*/"
"#;
env.create_config(config_content);
let config = ToolConfig::load(env.path().join(".llman").join("config.yaml")).unwrap();
assert_eq!(config.version, "0.1");
assert!(config.tools.clean_useless_comments.is_some());
let clean_config = config.tools.clean_useless_comments.unwrap();
assert_eq!(clean_config.scope.include.len(), 2);
assert_eq!(clean_config.scope.exclude.len(), 2);
assert!(clean_config.scope.include.contains(&"**/*.py".to_string()));
assert!(clean_config.scope.include.contains(&"**/*.js".to_string()));
assert!(clean_config.lang_rules.python.is_some());
assert!(clean_config.lang_rules.javascript.is_some());
let python_rules = clean_config.lang_rules.python.unwrap();
assert_eq!(python_rules.single_line_comments, Some(true));
assert_eq!(python_rules.multi_line_comments, Some(false));
assert_eq!(python_rules.min_comment_length, Some(10));
assert_eq!(python_rules.preserve_patterns.unwrap().len(), 1);
let js_rules = clean_config.lang_rules.javascript.unwrap();
assert_eq!(js_rules.single_line_comments, Some(true));
assert_eq!(js_rules.multi_line_comments, Some(true));
assert_eq!(js_rules.doc_comments, Some(false));
assert_eq!(js_rules.min_comment_length, Some(15));
assert_eq!(js_rules.preserve_patterns.unwrap().len(), 2);
}
#[test]
fn test_config_invalid_yaml() {
let env = TestEnvironment::new();
let invalid_yaml = r#"
version: "0.1"
tools:
clean-useless-comments:
scope:
include:
- "**/*.py"
invalid_yaml: [unclosed array
lang-rules:
python:
single-line-comments: not_a_boolean
"#;
env.create_config(invalid_yaml);
let config_result = ToolConfig::load(env.path().join(".llman").join("config.yaml"));
assert!(config_result.is_err(), "Should fail to load invalid YAML");
}
#[test]
fn test_config_missing_required_fields() {
let env = TestEnvironment::new();
let incomplete_config = r#"
# Missing version field
tools:
clean-useless-comments:
scope:
include:
- "**/*.py"
# Missing lang-rules
"#;
env.create_config(incomplete_config);
let config_result = ToolConfig::load(env.path().join(".llman").join("config.yaml"));
match config_result {
Ok(config) => {
assert!(config.version.is_empty() || config.version == "0.1");
}
Err(_) => {
}
}
}
#[test]
fn test_config_invalid_types() {
let env = TestEnvironment::new();
let config_with_invalid_types = r#"
version: "0.1"
tools:
clean-useless-comments:
scope:
include: "should_be_array_not_string"
exclude: 12345 # Should be array
lang-rules:
python:
single-line-comments: "should_be_boolean"
min-comment-length: "should_be_number"
preserve-patterns: "should_be_array"
"#;
env.create_config(config_with_invalid_types);
let config_result = ToolConfig::load(env.path().join(".llman").join("config.yaml"));
assert!(config_result.is_err(), "Should fail due to type mismatches");
}
#[test]
fn test_config_invalid_regex_patterns() {
let env = TestEnvironment::new();
let config_with_invalid_regex = r#"
version: "0.1"
tools:
clean-useless-comments:
scope:
include:
- "**/*.py"
lang-rules:
python:
single-line-comments: true
preserve-patterns:
- "[invalid_regex*(unclosed"
- "^\\s*#\\s*(TODO|FIXME):" # This one is valid
min-comment-length: 10
"#;
env.create_config(config_with_invalid_regex);
let config_result = ToolConfig::load(env.path().join(".llman").join("config.yaml"));
match config_result {
Ok(config) => {
let test_file = env.create_file(
"test.py",
"# TODO: preserve this\n# remove this\ndef test(): pass",
);
let args = CleanUselessCommentsArgs {
config: Some(env.path().join(".llman").join("config.yaml")),
dry_run: true,
yes: false,
interactive: false,
force: false,
verbose: true,
git_only: false,
files: vec![test_file],
};
let mut processor = CommentProcessor::new(config, args);
let result = processor.process();
match result {
Ok(_) => println!("Handled invalid regex gracefully"),
Err(e) => println!("Failed as expected with invalid regex: {:?}", e),
}
}
Err(_) => {
}
}
}
#[test]
fn test_config_edge_case_values() {
let env = TestEnvironment::new();
let edge_case_config = r#"
version: "0.1"
tools:
clean-useless-comments:
scope:
include: []
exclude: []
lang-rules:
python:
single-line-comments: true
multi-line-comments: false
min-comment-length: 0 # Edge case: zero minimum
preserve-patterns: [] # Edge case: empty patterns
javascript:
single-line-comments: false # Edge case: disabled processing
min-comment-length: 999999 # Edge case: very large minimum
preserve-patterns: # Edge case: complex patterns
- "^\\s*//\\s*(TODO|FIXME|NOTE|HACK|XXX):\\s*.*$"
- "^\\s*/\\*\\*[\\s\\S]*?\\*/"
- "^\\s*//\\s*@[a-zA-Z].*$"
"#;
env.create_config(edge_case_config);
let config_result = ToolConfig::load(env.path().join(".llman").join("config.yaml"));
assert!(config_result.is_ok(), "Should handle edge case values");
let config = config_result.unwrap();
let clean_config = config.tools.clean_useless_comments.unwrap();
assert_eq!(clean_config.scope.include.len(), 0);
assert_eq!(clean_config.scope.exclude.len(), 0);
let python_rules = clean_config.lang_rules.python.unwrap();
assert_eq!(python_rules.min_comment_length, Some(0));
assert_eq!(python_rules.preserve_patterns.unwrap().len(), 0);
let js_rules = clean_config.lang_rules.javascript.unwrap();
assert_eq!(js_rules.min_comment_length, Some(999999));
assert_eq!(js_rules.preserve_patterns.unwrap().len(), 3);
}
#[test]
fn test_config_unicode_support() {
let env = TestEnvironment::new();
let unicode_config = r#"
version: "0.1"
tools:
clean-useless-comments:
scope:
include:
- "**/*.py"
- "**/*.测试.py" # Unicode filename pattern
lang-rules:
python:
single-line-comments: true
preserve-patterns:
- "^\\s*#\\s*(TODO|FIXME|注意|修复):" # Unicode patterns
- "^\\s*#.*[🚀⚠️]" # Emoji in patterns
min-comment-length: 5
# Unicode comment for configuration
description: "这是一个配置文件"
author: "开发者👨💻"
"#;
env.create_config(unicode_config);
let config_result = ToolConfig::load(env.path().join(".llman").join("config.yaml"));
assert!(
config_result.is_ok(),
"Should handle Unicode in configuration"
);
let config = config_result.unwrap();
let clean_config = config.tools.clean_useless_comments.unwrap();
assert!(
clean_config
.scope
.include
.contains(&"**/*.测试.py".to_string())
);
let python_rules = clean_config.lang_rules.python.unwrap();
let patterns = python_rules.preserve_patterns.unwrap();
assert!(
patterns
.iter()
.any(|p| p.contains("注意") || p.contains("修复"))
);
}
#[test]
fn test_config_file_not_found() {
let env = TestEnvironment::new();
let config_result = ToolConfig::load(env.path().join("nonexistent_config.yaml"));
assert!(
config_result.is_err(),
"Should fail to load non-existent config file"
);
}
#[test]
fn test_config_partial_configuration() {
let env = TestEnvironment::new();
let partial_config = r#"
version: "0.1"
tools:
clean-useless-comments:
scope:
include:
- "**/*.py"
# lang-rules section is missing - should use defaults
"#;
env.create_config(partial_config);
let config_result = ToolConfig::load(env.path().join(".llman").join("config.yaml"));
match config_result {
Ok(config) => {
let clean_config = config.tools.clean_useless_comments.unwrap();
assert_eq!(clean_config.scope.include.len(), 1);
}
Err(_) => {
}
}
}
#[test]
fn test_config_schema_validation() {
let env = TestEnvironment::new();
let config_content = r#"
version: "0.1"
tools:
clean-useless-comments:
scope:
include:
- "**/*.py"
lang-rules:
python:
single-line-comments: true
min-comment-length: 10
"#;
env.create_config(config_content);
let _config = ToolConfig::load(env.path().join(".llman").join("config.yaml")).unwrap();
let schema_result = ToolConfig::generate_schema();
assert!(schema_result.is_ok(), "Should generate valid JSON schema");
let schema = schema_result.unwrap();
assert!(!schema.is_empty(), "Schema should have content");
}
#[test]
fn test_config_environment_substitution() {
let env = TestEnvironment::new();
let config_with_env = r#"
version: "0.1"
tools:
clean-useless-comments:
scope:
include:
- "**/*.py"
lang-rules:
python:
single-line-comments: true
min-comment-length: ${TEST_MIN_LENGTH}
"#;
env.create_config(config_with_env);
let config_result = ToolConfig::load(env.path().join(".llman").join("config.yaml"));
match config_result {
Ok(config) => {
let clean_config = config.tools.clean_useless_comments.unwrap();
let python_rules = clean_config.lang_rules.python.unwrap();
println!(
"Environment substitution result: {:?}",
python_rules.min_comment_length
);
}
Err(_) => {
println!("Environment substitution not implemented or failed");
}
}
}
#[test]
fn test_config_inheritance_and_overrides() {
let env = TestEnvironment::new();
let global_config = r#"
version: "0.1"
tools:
clean-useless-comments:
scope:
include:
- "**/*.py"
- "**/*.js"
exclude:
- "**/test/**"
lang-rules:
python:
single-line-comments: true
min-comment-length: 10
javascript:
single-line-comments: true
min-comment-length: 15
"#;
env.create_config(global_config);
let config = ToolConfig::load(env.path().join(".llman").join("config.yaml")).unwrap();
let clean_config = config.tools.clean_useless_comments.unwrap();
assert_eq!(clean_config.scope.include.len(), 2);
assert_eq!(clean_config.scope.exclude.len(), 1);
let python_rules = clean_config.lang_rules.python.unwrap();
let js_rules = clean_config.lang_rules.javascript.unwrap();
assert_eq!(python_rules.min_comment_length, Some(10));
assert_eq!(js_rules.min_comment_length, Some(15));
}
#[test]
fn test_config_validation_integration() {
let env = TestEnvironment::new();
let test_file = env.create_file(
"test.py",
"# Short comment\n# TODO: Important comment\ndef test(): pass",
);
let valid_config = r#"
version: "0.1"
tools:
clean-useless-comments:
scope:
include:
- "**/*.py"
lang-rules:
python:
single-line-comments: true
preserve-patterns:
- "^\\s*#\\s*(TODO|FIXME):"
min-comment-length: 15
"#;
env.create_config(valid_config);
let config = ToolConfig::load(env.path().join(".llman").join("config.yaml")).unwrap();
let args = CleanUselessCommentsArgs {
config: Some(env.path().join(".llman").join("config.yaml")),
dry_run: true,
yes: false,
interactive: false,
force: false,
verbose: true,
git_only: false,
files: vec![test_file],
};
let mut processor = CommentProcessor::new(config, args);
let result = processor.process();
assert!(
result.is_ok(),
"Config should work correctly with processor"
);
let processing_result = result.unwrap();
assert_eq!(
processing_result.errors, 0,
"Should have no processing errors"
);
println!(
"Files changed: {} (this is normal for dry-run with conservative settings)",
processing_result.files_changed.len()
);
}
#[test]
fn test_config_typescript_rules() {
let env = TestEnvironment::new();
let typescript_config = r#"
version: "0.1"
tools:
clean-useless-comments:
scope:
include:
- "**/*.ts"
- "**/*.tsx"
lang-rules:
javascript:
single-line-comments: true
multi-line-comments: true
doc-comments: false
preserve-patterns:
- "^\\s*//\\s*(TODO|FIXME):"
- "^\\s*/\\*\\*[\\s\\S]*?\\*/"
- "^\\s*//\\s*@[a-zA-Z].*$"
min-comment-length: 12
"#;
env.create_config(typescript_config);
let config = ToolConfig::load(env.path().join(".llman").join("config.yaml")).unwrap();
let clean_config = config.tools.clean_useless_comments.unwrap();
let js_rules = clean_config.lang_rules.javascript.unwrap();
assert_eq!(js_rules.single_line_comments, Some(true));
assert_eq!(js_rules.multi_line_comments, Some(true));
assert_eq!(js_rules.doc_comments, Some(false));
assert_eq!(js_rules.min_comment_length, Some(12));
assert_eq!(js_rules.preserve_patterns.unwrap().len(), 3);
assert!(clean_config.scope.include.contains(&"**/*.ts".to_string()));
assert!(clean_config.scope.include.contains(&"**/*.tsx".to_string()));
}