#[cfg(test)]
mod tests {
use crate::ruff_parser::migrate_file_with_improved_ruff;
use crate::types::TypeIntrospectionMethod;
#[test]
fn test_simple_function_replacement() {
let source = r#"
from dissolve import replace_me
@replace_me()
def old_func(x, y):
return new_func(x * 2, y + 1)
result = old_func(5, 10)
"#;
let test_ctx = crate::tests::test_utils::TestContext::new(source);
let result = migrate_file_with_improved_ruff(
source,
"test_module",
test_ctx.file_path,
TypeIntrospectionMethod::PyrightLsp,
)
.unwrap();
assert!(result.contains("new_func(5 * 2, 10 + 1)"));
assert!(!result.contains("result = old_func(5, 10)"));
}
#[test]
fn test_method_replacement() {
let source = r#"
from dissolve import replace_me
class OldClass:
@replace_me()
def old_method(self, x):
return self.new_method(x * 2)
obj = OldClass()
result = obj.old_method(5)
"#;
let test_ctx = crate::tests::test_utils::TestContext::new(source);
let result = migrate_file_with_improved_ruff(
source,
"test_module",
test_ctx.file_path,
TypeIntrospectionMethod::PyrightLsp,
)
.unwrap();
assert!(result.contains("obj.new_method(5 * 2)"));
assert!(!result.contains("result = obj.old_method(5)"));
}
#[test]
fn test_args_kwargs_replacement() {
let source = r#"
from dissolve import replace_me
@replace_me()
def old_func(a, b, *args, **kwargs):
return new_func(a + 1, b * 2, *args, **kwargs)
# Various call patterns
old_func(1, 2)
old_func(1, 2, 3, 4)
old_func(1, 2, x=3)
old_func(1, 2, 3, x=4, y=5)
"#;
let test_ctx = crate::tests::test_utils::TestContext::new(source);
let result = migrate_file_with_improved_ruff(
source,
"test_module",
test_ctx.file_path,
TypeIntrospectionMethod::PyrightLsp,
)
.unwrap();
assert!(result.contains("new_func(1 + 1, 2 * 2)"));
assert!(result.contains("new_func(1 + 1, 2 * 2, 3, 4)"));
assert!(result.contains("new_func(1 + 1, 2 * 2, x=3)"));
assert!(result.contains("new_func(1 + 1, 2 * 2, 3, x=4, y=5)"));
}
#[test]
fn test_preserves_formatting() {
let source = r#"from dissolve import replace_me
@replace_me()
def old_func(x):
"""Old function docstring"""
return new_func(x * 2)
# This is an important comment
result = old_func(5) # Inline comment
# Another comment
print(result)
"#;
let test_ctx = crate::tests::test_utils::TestContext::new(source);
let result = migrate_file_with_improved_ruff(
source,
"test_module",
test_ctx.file_path,
TypeIntrospectionMethod::PyrightLsp,
)
.unwrap();
assert!(result.contains("# This is an important comment"));
assert!(result.contains("# Inline comment"));
assert!(result.contains("# Another comment"));
assert!(result.contains("\"\"\"Old function docstring\"\"\""));
}
#[test]
fn test_nested_calls() {
let source = r#"
from dissolve import replace_me
@replace_me()
def old_outer(x):
return new_outer(x)
@replace_me()
def old_inner(y):
return new_inner(y)
# Nested call
result = old_outer(old_inner(5))
"#;
let mut result = source.to_string();
loop {
let test_ctx = crate::tests::test_utils::TestContext::new(&result);
let migrated = migrate_file_with_improved_ruff(
&result,
"test_module",
test_ctx.file_path,
TypeIntrospectionMethod::PyrightLsp,
)
.unwrap();
if migrated == result {
break;
}
result = migrated;
}
let expected = r#"
from dissolve import replace_me
@replace_me()
def old_outer(x):
return new_outer(x)
@replace_me()
def old_inner(y):
return new_inner(y)
# Nested call
result = new_outer(new_inner(5))
"#;
assert_eq!(result, expected);
}
#[test]
fn test_class_replacement() {
let source = r#"
from dissolve import replace_me
@replace_me()
class OldClass:
def __init__(self, x):
self.value = NewClass(x * 2)
obj = OldClass(5)
"#;
let test_ctx = crate::tests::test_utils::TestContext::new(source);
let result = migrate_file_with_improved_ruff(
source,
"test_module",
test_ctx.file_path,
TypeIntrospectionMethod::PyrightLsp,
)
.unwrap();
assert!(result.contains("NewClass(5 * 2)"));
assert!(!result.contains("obj = OldClass(5)"));
}
#[test]
fn test_single_element_tuple_formatting() {
use crate::stub_collector::RuffDeprecatedFunctionCollector;
let source = r#"
from dissolve import replace_me
@replace_me(replacement=(42,)) # Single element tuple with trailing comma
def old_func():
pass
"#;
let collector = RuffDeprecatedFunctionCollector::new("test_module".to_string(), None);
let result = collector.collect_from_source(source.to_string()).unwrap();
assert_eq!(result.replacements.len(), 1);
let replacement = result.replacements.get("test_module.old_func").unwrap();
assert!(
replacement.replacement_expr.contains("(42,)")
|| replacement.replacement_expr.contains("(42, )"),
"Single element tuple should have trailing comma, got: {}",
replacement.replacement_expr
);
}
#[test]
fn test_multi_element_tuple_formatting() {
use crate::stub_collector::RuffDeprecatedFunctionCollector;
let source = r#"
from dissolve import replace_me
@replace_me(replacement=(1, 2, 3)) # Multi-element tuple
def old_func():
pass
"#;
let collector = RuffDeprecatedFunctionCollector::new("test_module".to_string(), None);
let result = collector.collect_from_source(source.to_string()).unwrap();
assert_eq!(result.replacements.len(), 1);
let replacement = result.replacements.get("test_module.old_func").unwrap();
assert!(
replacement.replacement_expr.contains("(1, 2, 3)"),
"Multi-element tuple formatting incorrect: {}",
replacement.replacement_expr
);
}
}