use llman::tool::command::CleanUselessCommentsArgs;
use llman::tool::config::Config;
use llman::tool::processor::CommentProcessor;
mod common;
use common::*;
use std::process::Command;
#[test]
fn test_python_comment_processing_removes_short_comments_and_preserves_important_ones() {
let env = TestEnvironment::new();
let test_file = env.create_file("test.py", test_content::PYTHON_CODE_WITH_COMMENTS);
env.create_python_clean_config(test_constants::DEFAULT_MIN_COMMENT_LENGTH);
let config = Config::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: false,
git_only: false,
files: vec![test_file.clone()],
};
let mut processor = CommentProcessor::new(config, args);
let result = processor.process().unwrap();
assert_eq!(
result.files_changed.len(),
1,
"Expected exactly 1 file to have changes, got {}",
result.files_changed.len()
);
assert_eq!(
result.errors, 0,
"Expected no processing errors, got {}",
result.errors
);
}
#[test]
fn test_javascript_comment_processing_preserves_patterns_and_filters_by_length() {
let env = TestEnvironment::new();
let test_file = env.create_file("test.js", test_content::JAVASCRIPT_CODE_WITH_COMMENTS);
env.create_javascript_clean_config(test_constants::SHORT_COMMENT_LENGTH * 3);
let config = Config::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: false,
git_only: false,
files: vec![test_file.clone()],
};
let mut processor = CommentProcessor::new(config, args);
let result = processor.process().unwrap();
assert_eq!(result.errors, 0, "Expected no processing errors");
println!(
"Files processed: {}, Files changed: {}",
result.files_changed.len(),
result.files_changed.len()
);
}
#[test]
fn test_rust_comment_processing() {
let env = TestEnvironment::new();
let rust_code = r#"// Short
fn main() {
println!("Hello"); // x
/// This is a doc comment and should be preserved
// TODO: This should be preserved
}
"#;
let config_content = r#"
version: "0.1"
tools:
clean-useless-comments:
scope:
include:
- "**/*.rs"
lang-rules:
rust:
single-line-comments: true
doc-comments: false
preserve-patterns:
- "^\\s*//\\s*(TODO|FIXME):"
- "^\\s*///"
min-comment-length: 15
"#;
let test_file = env.create_file("test.rs", rust_code);
env.create_config(config_content);
let config = Config::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: false,
git_only: false,
files: vec![test_file.clone()],
};
let mut processor = CommentProcessor::new(config, args);
let result = processor.process().unwrap();
assert!(!result.files_changed.is_empty());
}
#[test]
fn test_typescript_rules_prefer_typescript_config() {
let env = TestEnvironment::new();
let ts_code = r#"// short comment
const value = 1;
"#;
let config_content = r#"
version: "0.1"
tools:
clean-useless-comments:
scope:
include:
- "**/*.ts"
lang-rules:
javascript:
single-line-comments: true
min-comment-length: 5
typescript:
single-line-comments: true
min-comment-length: 50
"#;
let test_file = env.create_file("test.ts", ts_code);
env.create_config(config_content);
let config = Config::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: false,
git_only: false,
files: vec![test_file.clone()],
};
let mut processor = CommentProcessor::new(config, args);
let result = processor.process().unwrap();
assert_eq!(result.files_changed.len(), 1);
}
#[test]
fn test_preserve_important_comments() {
let env = TestEnvironment::new();
let code = r#"#!/usr/bin/env python3
# x
def important_function():
# TODO: This is a TODO item
# FIXME: This needs to be fixed
# NOTE: This is an important note
# y
print("Hello")
"#;
let config_content = r#"
version: "0.1"
tools:
clean-useless-comments:
scope:
include:
- "**/*.py"
lang-rules:
python:
single-line-comments: true
preserve-patterns:
- "^\\s*#\\s*(TODO|FIXME|NOTE):"
min-comment-length: 10
"#;
let test_file = env.create_file("test.py", code);
env.create_config(config_content);
let config = Config::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: false,
git_only: false,
files: vec![test_file.clone()],
};
let mut processor = CommentProcessor::new(config, args);
let result = processor.process().unwrap();
assert!(!result.files_changed.is_empty());
}
#[test]
fn test_file_scoping() {
let env = TestEnvironment::new();
env.create_file("test.py", "# Python comment");
env.create_file("test.js", "// JavaScript comment");
env.create_file("test.txt", "# Text file comment - should be ignored");
let config_content = r#"
version: "0.1"
tools:
clean-useless-comments:
scope:
include:
- "**/*.py"
- "**/*.js"
exclude:
- "**/ignored/**"
lang-rules:
python:
single-line-comments: true
min-comment-length: 5
javascript:
single-line-comments: true
min-comment-length: 5
"#;
env.create_config(config_content);
let config = Config::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: false,
git_only: false,
files: vec![],
};
let mut processor = CommentProcessor::new(config, args);
let result = processor.process_with_cwd(env.path()).unwrap();
assert_eq!(
result.errors, 0,
"Expected no errors, but got {}",
result.errors
);
}
#[test]
fn test_git_only_processes_tracked_files() {
let env = TestEnvironment::new();
let _test_file = env.create_file("tracked.py", "# x\n");
Command::new("git")
.args(["add", "tracked.py"])
.current_dir(env.path())
.output()
.expect("Failed to add file to git index");
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 = Config::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: false,
git_only: true,
files: vec![],
};
let mut processor = CommentProcessor::new(config, args);
let result = processor.process_with_cwd(env.path()).unwrap();
assert_eq!(result.files_changed.len(), 1);
}
#[test]
fn test_dry_run_mode() {
let env = TestEnvironment::new();
let original_content = r#"# Short comment
def hello():
pass
"#;
let test_file = env.create_file("test.py", original_content);
let config_content = r#"
version: "0.1"
tools:
clean-useless-comments:
scope:
include:
- "**/*.py"
lang-rules:
python:
single-line-comments: true
min-comment-length: 20
"#;
env.create_config(config_content);
let config = Config::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: false, git_only: false,
files: vec![test_file.clone()],
};
let mut processor = CommentProcessor::new(config, args);
let result = processor.process().unwrap();
assert_eq!(result.files_changed.len(), 1);
let actual_content = std::fs::read_to_string(&test_file).unwrap();
assert_eq!(actual_content, original_content);
}