use perl_module::{
IncRoot,
IncRootKind,
LoadTiming,
ModuleImportKind,
apply_module_rename_edits,
contains_module_token,
contains_standalone_module_token,
extract_module_reference,
file_path_to_module_name,
find_standalone_module_token_ranges,
has_standalone_module_token_boundaries,
is_module_identifier_char,
is_module_token_char,
legacy_package_separator,
line_references_isa_assignment,
line_references_module_import,
line_references_package_declaration,
line_references_qualified_call,
module_name_to_path,
module_path_to_name,
module_variant_pairs,
normalize_package_separator,
parse_module_import_head,
parse_module_token,
plan_module_rename_edits,
replace_module_token,
};
#[test]
fn test_api_facade_exports_all_types() {
let _ = normalize_package_separator("Foo::Bar");
let _ = normalize_package_separator("Foo'Bar");
assert_eq!(normalize_package_separator("Foo::Bar"), "Foo::Bar");
assert_eq!(normalize_package_separator("Foo'Bar"), "Foo::Bar");
}
#[test]
fn test_name_module_functions() {
let legacy = legacy_package_separator("::");
assert_eq!(legacy.as_ref(), "'");
let pairs = module_variant_pairs("My::Module", "Your::Module");
assert!(
!pairs.is_empty(),
"module_variant_pairs should return non-empty list of (old, new) pairs"
);
}
#[test]
fn test_path_module_functions() {
let path = module_name_to_path("My::Module");
assert_eq!(path, "My/Module.pm");
let module_from_path = module_path_to_name("My/Module.pm");
assert_eq!(module_from_path, "My::Module");
let file_module = file_path_to_module_name("/home/user/lib/My/Module.pm");
assert_eq!(file_module, "My::Module");
}
#[test]
fn test_token_core_module_functions() {
assert!(is_module_token_char('M'));
assert!(is_module_token_char('y'));
assert!(is_module_token_char('0'));
assert!(is_module_token_char('_'));
assert!(is_module_token_char(':')); assert!(!is_module_token_char(' '));
assert!(is_module_identifier_char('M'));
assert!(is_module_identifier_char('_'));
assert!(!is_module_identifier_char(':'));
let source = "use My::Module;";
let start = 4; let end = 15; assert!(has_standalone_module_token_boundaries(source, start, end));
}
#[test]
fn test_import_module_types_are_accessible() {
let _timing = LoadTiming::CompileTime;
let _kind = ModuleImportKind::Use;
}
#[test]
fn test_parse_module_import_head_function() -> Result<(), Box<dyn std::error::Error>> {
let head = parse_module_import_head("use My::Module;")
.ok_or("expected import head for `use My::Module;`")?;
assert_eq!(head.token, "My::Module");
assert_eq!(head.kind, ModuleImportKind::Use);
Ok(())
}
#[test]
fn test_boundary_module_functions() {
let source = "use My::Module; my $var = My::Module::func();";
assert!(contains_standalone_module_token(source, "My::Module"));
let ranges = find_standalone_module_token_ranges(source, "My::Module");
let count = ranges.count();
assert!(count > 0, "should find at least one module token range");
}
#[test]
fn test_token_module_functions() {
assert!(contains_module_token("use My::Module;", "My::Module"));
let (rewritten, changed) =
replace_module_token("use My::Module;", "My::Module", "Your::Module");
assert!(changed);
assert_eq!(rewritten, "use Your::Module;");
}
#[test]
fn test_token_parser_function() -> Result<(), Box<dyn std::error::Error>> {
let token =
parse_module_token("My::Module", 0).ok_or("expected to parse canonical module token")?;
assert_eq!(token.start, 0);
assert_eq!(token.end, "My::Module".len());
Ok(())
}
#[test]
fn test_import_match_module_function() {
assert!(line_references_module_import("use My::Module;", "My::Module"));
assert!(!line_references_module_import("my $var = 'My::Module';", "My::Module"));
}
#[test]
fn test_reference_module_functions() -> Result<(), Box<dyn std::error::Error>> {
let source = "use My::Module;";
let module_name = extract_module_reference(source, 4)
.ok_or("expected module reference at offset 4 in `use My::Module;`")?;
assert_eq!(module_name, "My::Module");
Ok(())
}
#[test]
fn test_rename_module_functions() {
let source = "use My::Module;\n";
let edits = plan_module_rename_edits(source, "My::Module", "Your::Module");
assert!(!edits.is_empty(), "should produce rename edits for import line");
let rewritten = apply_module_rename_edits(source, &edits);
assert_eq!(rewritten, "use Your::Module;\n");
}
#[test]
fn test_rename_module_predicates() {
assert!(line_references_isa_assignment("@ISA = qw(My::Module);", "My::Module"));
assert!(!line_references_isa_assignment("my $x = 1;", "My::Module"));
assert!(line_references_package_declaration("package My::Module;", "My::Module"));
assert!(!line_references_package_declaration("use My::Module;", "My::Module"));
assert!(line_references_qualified_call("My::Module::func();", "My::Module"));
assert!(!line_references_qualified_call("'My::Module::func();'", "My::Module"));
}
#[test]
fn test_resolution_module_types_accessible() {
let inc_root = IncRoot {
kind: IncRootKind::ExternalAbsolute,
path: "/usr/lib/perl".into(),
precedence: 1,
source: "system".into(),
};
assert_eq!(inc_root.kind, IncRootKind::ExternalAbsolute);
}
#[test]
fn test_empty_module_name_handling() {
assert!(!contains_module_token("use My::Module;", ""));
assert!(!contains_standalone_module_token("use My::Module;", ""));
let edits = plan_module_rename_edits("use My::Module;", "", "Your::Module");
assert!(edits.is_empty(), "should not generate edits with empty old module");
}
#[test]
fn test_identical_rename_produces_no_edits() {
let source = "use My::Module;\n";
let edits = plan_module_rename_edits(source, "My::Module", "My::Module");
assert!(edits.is_empty(), "renaming to same name should produce no edits");
}
#[test]
fn test_module_names_with_numbers_and_underscores() {
let name = "My_Module_v2";
assert!(is_module_token_char('_'));
assert!(is_module_token_char('2'));
let path = module_name_to_path(name);
assert_eq!(path, "My_Module_v2.pm");
}
#[test]
fn test_deeply_nested_module_names() {
let deep = "Foo::Bar::Baz::Qux::Quux::Corge";
let path = module_name_to_path(deep);
assert_eq!(path, "Foo/Bar/Baz/Qux/Quux/Corge.pm");
}
#[test]
fn test_single_segment_module_names() {
let single = "Simple";
let path = module_name_to_path(single);
assert_eq!(path, "Simple.pm");
}
#[test]
fn test_module_token_at_start_of_line() {
let source = "use My::Module;";
assert!(contains_module_token(source, "My::Module"));
let source2 = "My::Module::func();";
assert!(contains_module_token(source2, "My::Module::func"));
}
#[test]
fn test_module_token_at_end_of_line() {
let source = "use My::Module;";
assert!(contains_module_token(source, "My::Module"));
}
#[test]
fn test_module_token_surrounded_by_whitespace() {
let source = "use My::Module ;";
assert!(contains_module_token(source, "My::Module"));
}
#[test]
fn test_api_rs_re_export_count() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
#[test]
fn test_legacy_package_separator_preservation() {
let legacy = normalize_package_separator("Foo'Bar'Baz");
assert_eq!(legacy, "Foo::Bar::Baz");
let variants = module_variant_pairs("Foo'Bar", "Baz'Qux");
assert!(variants.len() > 1, "should generate multiple variant pairs");
}
#[test]
fn test_token_parsing_roundtrip() -> Result<(), Box<dyn std::error::Error>> {
let name = "Complex::Nested::Module::Name";
let token =
parse_module_token(name, 0).ok_or("expected token parse to succeed for nested module")?;
assert_eq!(token.start, 0);
assert_eq!(token.end, name.len());
Ok(())
}
#[test]
fn test_rename_multiline_source() {
let source = "use My::Module;\nuse My::Module::Sub;\nmy $x = 'literal';\n";
let edits = plan_module_rename_edits(source, "My::Module", "Your::Module");
assert!(!edits.is_empty(), "should find at least one edit");
assert_eq!(
edits.iter().filter(|e| e.line < 2).count(),
edits.len(),
"all edits should be on import lines"
);
}
#[test]
fn test_consumer_import_pattern_all_modules() {
use perl_module::boundary::contains_standalone_module_token as contains_token;
use perl_module::import_match::line_references_module_import as matches_import;
use perl_module::name::normalize_package_separator as normalize;
use perl_module::path::module_name_to_path as to_path;
use perl_module::token::contains_module_token as contains;
use perl_module::token_core::is_module_token_char as is_token_char;
assert_eq!(normalize("Foo'Bar"), "Foo::Bar");
assert_eq!(to_path("Foo::Bar"), "Foo/Bar.pm");
assert!(is_token_char('M'));
assert!(matches_import("use Foo;", "Foo"));
assert!(contains("use Foo;", "Foo"));
assert!(contains_token("use Foo;", "Foo"));
}
#[test]
fn test_documentation_62_migrated_tests_present() {
}