#[cfg(test)]
mod tests {
use crate::remover::remove_decorators;
#[test]
fn test_remove_all_decorators() {
let source = r#"
from dissolve import replace_me
@replace_me(since="1.0.0")
def old_func(x):
return x + 1
@replace_me(since="2.0.0")
def another_func(y):
return y * 2
def regular_func(z):
return z - 1
"#;
let (count, result) = remove_decorators(source, None, true, None).unwrap();
assert_eq!(count, 2, "Should remove 2 functions");
assert!(!result.contains("@replace_me"));
assert!(!result.contains("def old_func(x):"));
assert!(!result.contains("def another_func(y):"));
assert!(result.contains("def regular_func(z):")); assert!(!result.contains("return x + 1"));
assert!(!result.contains("return y * 2"));
assert!(result.contains("return z - 1")); }
#[test]
fn test_remove_property_decorators() {
let source = r#"
from dissolve import replace_me
class MyClass:
@property
@replace_me(since="1.0.0")
def old_property(self):
return self.new_property
@property
def new_property(self):
return self._value
"#;
let (count, result) = remove_decorators(source, None, true, None).unwrap();
assert_eq!(count, 1, "Should remove 1 function");
assert!(!result.contains("@replace_me"));
assert!(!result.contains("def old_property(self):"));
assert!(result.contains("def new_property(self):")); assert!(result.contains("@property")); }
#[test]
fn test_remove_before_version() {
let source = r#"
from dissolve import replace_me
@replace_me(since="0.5.0")
def very_old_func(x):
return x + 1
@replace_me(since="1.0.0")
def old_func(y):
return y * 2
@replace_me(since="2.0.0")
def newer_func(z):
return z - 1
def regular_func(w):
return w / 2
"#;
let (count, result) = remove_decorators(source, Some("1.5.0"), false, None).unwrap();
assert_eq!(count, 2, "Should remove 2 functions with version < 1.5.0");
assert!(!result.contains(r#"@replace_me(since="0.5.0")"#));
assert!(!result.contains(r#"@replace_me(since="1.0.0")"#));
assert!(!result.contains("def very_old_func(x):"));
assert!(!result.contains("def old_func(y):"));
assert!(result.contains(r#"@replace_me(since="2.0.0")"#));
assert!(result.contains("def newer_func(z):"));
assert!(result.contains("def regular_func(w):"));
}
#[test]
fn test_no_remove_criteria() {
let source = r#"
from dissolve import replace_me
@replace_me()
def old_func(x):
return x + 1
"#;
let (count, result) = remove_decorators(source, None, false, None).unwrap();
assert_eq!(count, 0, "Should remove 0 functions");
assert_eq!(result, source);
}
#[test]
fn test_remove_in_version() {
let source = r#"
from dissolve import replace_me
@replace_me(since="1.0.0", remove_in="2.0.0")
def func_to_remove(x):
return x + 1
@replace_me(since="1.0.0", remove_in="3.0.0")
def func_to_keep(y):
return y + 1
"#;
let (count, result) = remove_decorators(source, None, false, Some("2.0.0")).unwrap();
assert_eq!(count, 1, "Should remove 1 function");
assert!(!result.contains("def func_to_remove(x):"));
assert!(result.contains("def func_to_keep(y):"));
}
#[test]
fn test_class_methods() {
let source = r#"
from dissolve import replace_me
class Calculator:
@classmethod
@replace_me(since="1.0.0")
def old_add(cls, x, y):
return cls.new_add(x, y)
@staticmethod
@replace_me(since="1.0.0")
def old_multiply(x, y):
return x * y
def regular_method(self, x):
return x + 1
"#;
let (count, result) = remove_decorators(source, None, true, None).unwrap();
assert_eq!(count, 2, "Should remove 2 methods");
assert!(!result.contains("def old_add(cls, x, y):"));
assert!(!result.contains("def old_multiply(x, y):"));
assert!(result.contains("def regular_method(self, x):"));
}
#[test]
fn test_nested_classes() {
let source = r#"
class Outer:
class Inner:
@replace_me()
def old_method(self):
return self.new_method()
def new_method(self):
return 42
"#;
let (count, result) = remove_decorators(source, None, true, None).unwrap();
assert_eq!(count, 1, "Should remove 1 method");
assert!(!result.contains("def old_method(self):"));
assert!(result.contains("def new_method(self):"));
assert!(result.contains("class Outer:"));
assert!(result.contains("class Inner:"));
}
#[test]
fn test_multiple_decorators() {
let source = r#"
from dissolve import replace_me
@deprecated
@replace_me(since="1.0.0")
@another_decorator
def old_func(x):
return x + 1
@deprecated
def other_func(y):
return y - 1
"#;
let (count, result) = remove_decorators(source, None, true, None).unwrap();
assert_eq!(count, 1, "Should remove 1 function");
assert!(!result.contains("def old_func(x):"));
assert!(!result.contains("@another_decorator"));
assert!(result.contains("def other_func(y):"));
assert!(result.contains("@deprecated")); }
#[test]
fn test_remove_decorators_line_count_decrease() {
use crate::remover::remove_decorators_from_file;
use std::fs;
use tempfile::TempDir;
let temp_dir = TempDir::new().unwrap();
let file_path = temp_dir.path().join("test.py");
let source = r#"from dissolve import replace_me
@replace_me(before_version="2.0.0")
def deprecated_func():
"""This function will be removed."""
pass
def keep_func():
"""This function stays."""
pass
"#;
fs::write(&file_path, source).unwrap();
let (removed_count, result) = remove_decorators_from_file(
&file_path.to_string_lossy(),
Some("3.0.0"), false,
false, Some("3.0.0"),
)
.unwrap();
let original_lines = source.lines().count();
let result_lines = result.lines().count();
println!("Original source:\n{}", source);
println!("Result source:\n{}", result);
println!(
"Original lines: {}, Result lines: {}",
original_lines, result_lines
);
assert!(
original_lines > result_lines,
"Original file ({} lines) should have more lines than result ({} lines)",
original_lines,
result_lines
);
assert_eq!(removed_count, 1, "Should report 1 function removed");
}
#[test]
fn test_remove_decorators_line_count_same_or_increase() {
use crate::remover::remove_decorators_from_file;
use std::fs;
use tempfile::TempDir;
let temp_dir = TempDir::new().unwrap();
let file_path = temp_dir.path().join("test.py");
let source = r#"from dissolve import remove_me
@remove_me(before_version="5.0.0")
def keep_func():
"""This function stays because version is in future."""
pass
"#;
fs::write(&file_path, source).unwrap();
let (removed_count, result) = remove_decorators_from_file(
&file_path.to_string_lossy(),
Some("1.0.0"), false,
false, Some("1.0.0"),
)
.unwrap();
let original_lines = source.lines().count();
let result_lines = result.lines().count();
assert!(
original_lines <= result_lines || original_lines == result_lines,
"Line count should not decrease when no functions are removed"
);
assert_eq!(removed_count, 0, "Should report 0 functions removed");
}
}