feat(java): Phase 1.5 — tree-sitter Java frontend, package-aware mv, e2e fixtures
This commit is contained in:
parent
55670030c3
commit
603f916ee9
25 changed files with 1288 additions and 366 deletions
151
tests/cli_java.rs
Normal file
151
tests/cli_java.rs
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
//! End-to-end tests for the `jmove` CLI against the Java fixtures.
|
||||
|
||||
mod common;
|
||||
|
||||
use common::{copy_fixture, in_root, jmove, read};
|
||||
use predicates::prelude::*;
|
||||
|
||||
fn fixture(name: &str) -> tempfile::TempDir {
|
||||
copy_fixture("java", name)
|
||||
}
|
||||
|
||||
const TEXT: &str = "src/main/java/com/example/util/Text.java";
|
||||
const MOVED: &str = "src/main/java/com/example/core/Text.java";
|
||||
|
||||
#[test]
|
||||
fn mv_between_packages_updates_declaration_and_every_importer() {
|
||||
let tmp = fixture("basic");
|
||||
jmove(&tmp, &["mv", TEXT, MOVED])
|
||||
.success()
|
||||
.stdout(predicate::str::contains("4 imports in 3 files"));
|
||||
|
||||
let moved = read(&in_root(tmp.path(), MOVED));
|
||||
assert!(moved.contains("package com.example.core;"), "{moved}");
|
||||
assert!(!moved.contains("com.example.util"), "{moved}");
|
||||
|
||||
let app = read(&in_root(
|
||||
tmp.path(),
|
||||
"src/main/java/com/example/app/App.java",
|
||||
));
|
||||
assert!(app.contains("import com.example.core.Text;"), "{app}");
|
||||
assert!(
|
||||
app.contains("import static com.example.core.Text.shout;"),
|
||||
"{app}"
|
||||
);
|
||||
// Specifiers that never named the moved class are byte-identical.
|
||||
assert!(app.contains("import com.example.unknown.*;"), "{app}");
|
||||
assert!(app.contains("import java.util.List;"), "{app}");
|
||||
|
||||
let user = read(&in_root(
|
||||
tmp.path(),
|
||||
"src/main/java/com/example/model/User.java",
|
||||
));
|
||||
assert!(user.contains("import com.example.core.Text;"), "{user}");
|
||||
assert!(!in_root(tmp.path(), TEXT).exists());
|
||||
|
||||
// Unresolvable Java imports (jdk, wildcard) are not "broken".
|
||||
jmove(&tmp, &["check"]).success();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mv_dry_run_previews_all_three_edits_without_writing() {
|
||||
let tmp = fixture("basic");
|
||||
jmove(&tmp, &["mv", TEXT, MOVED, "--dry-run"])
|
||||
.success()
|
||||
.stdout(predicate::str::contains("-package com.example.util;"))
|
||||
.stdout(predicate::str::contains("+package com.example.core;"))
|
||||
.stdout(predicate::str::contains("-import com.example.util.Text;"))
|
||||
.stdout(predicate::str::contains("+import com.example.core.Text;"))
|
||||
.stdout(predicate::str::contains(format!("move {TEXT} -> {MOVED}")));
|
||||
assert!(in_root(tmp.path(), TEXT).is_file());
|
||||
assert!(!in_root(tmp.path(), MOVED).exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mv_json_reports_package_and_importer_changes() {
|
||||
let tmp = fixture("basic");
|
||||
jmove(&tmp, &["mv", TEXT, MOVED, "--json"])
|
||||
.success()
|
||||
.stdout(
|
||||
predicate::str::contains("\"old\": \"com.example.util\"")
|
||||
.and(predicate::str::contains("\"new\": \"com.example.core\""))
|
||||
.and(predicate::str::contains(
|
||||
"\"old\": \"com.example.util.Text.shout\"",
|
||||
))
|
||||
.and(predicate::str::contains(
|
||||
"\"new\": \"com.example.core.Text.shout\"",
|
||||
))
|
||||
.and(predicate::str::contains("\"updated_imports\": 4")),
|
||||
);
|
||||
let changed = read(&in_root(tmp.path(), MOVED));
|
||||
assert!(changed.contains("package com.example.core"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rename_inside_same_package_keeps_package_declaration() {
|
||||
let tmp = fixture("basic");
|
||||
jmove(
|
||||
&tmp,
|
||||
&["mv", TEXT, "src/main/java/com/example/util/Paragraph.java"],
|
||||
)
|
||||
.success();
|
||||
let renamed = read(&in_root(
|
||||
tmp.path(),
|
||||
"src/main/java/com/example/util/Paragraph.java",
|
||||
));
|
||||
assert!(renamed.contains("package com.example.util;"), "{renamed}");
|
||||
let app = read(&in_root(
|
||||
tmp.path(),
|
||||
"src/main/java/com/example/app/App.java",
|
||||
));
|
||||
assert!(app.contains("import com.example.util.Paragraph;"), "{app}");
|
||||
assert!(
|
||||
app.contains("import static com.example.util.Paragraph.shout;"),
|
||||
"{app}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_outside_the_source_root_is_rejected() {
|
||||
let tmp = fixture("basic");
|
||||
jmove(&tmp, &["mv", TEXT, "webapp/core/Text.java", "--json"])
|
||||
.code(1)
|
||||
.stdout(
|
||||
predicate::str::contains("\"code\": \"PLAN_REJECTED\"")
|
||||
.and(predicate::str::contains("source root")),
|
||||
);
|
||||
assert!(in_root(tmp.path(), TEXT).is_file());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn java_file_must_keep_the_java_extension() {
|
||||
let tmp = fixture("basic");
|
||||
jmove(
|
||||
&tmp,
|
||||
&["mv", TEXT, "src/main/java/com/example/core/Text.txt"],
|
||||
)
|
||||
.code(1)
|
||||
.stderr(predicate::str::contains(".java extension"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_package_file_cannot_change_directory() {
|
||||
let tmp = fixture("basic");
|
||||
jmove(
|
||||
&tmp,
|
||||
&[
|
||||
"mv",
|
||||
"src/main/java/Main.java",
|
||||
"src/main/java/app/Main.java",
|
||||
],
|
||||
)
|
||||
.code(1)
|
||||
.stderr(predicate::str::contains("default package"));
|
||||
// ...but an in-place rename is fine and needs no rewrites.
|
||||
jmove(
|
||||
&tmp,
|
||||
&["mv", "src/main/java/Main.java", "src/main/java/Run.java"],
|
||||
)
|
||||
.success();
|
||||
assert!(in_root(tmp.path(), "src/main/java/Run.java").is_file());
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue