571 lines
16 KiB
Rust
571 lines
16 KiB
Rust
use std::fs;
|
|
|
|
use assert_cmd::Command;
|
|
use predicates::prelude::*;
|
|
use tempfile::TempDir;
|
|
|
|
fn bin() -> Command {
|
|
Command::cargo_bin("rws").unwrap()
|
|
}
|
|
|
|
fn create_package(root: &std::path::Path, name: &str, with_justfile: bool) -> std::path::PathBuf {
|
|
let path = root.join(name);
|
|
fs::create_dir_all(path.join(".rws")).unwrap();
|
|
fs::write(
|
|
path.join("package.xml"),
|
|
format!("<package><name>{name}</name></package>"),
|
|
)
|
|
.unwrap();
|
|
if with_justfile {
|
|
fs::write(path.join(".rws/justfile"), "start:\n @echo start\n").unwrap();
|
|
}
|
|
path
|
|
}
|
|
|
|
#[test]
|
|
fn init_creates_workspace_and_generated_justfile() {
|
|
let temp = TempDir::new().unwrap();
|
|
let workspace = temp.path().join("ws");
|
|
|
|
bin()
|
|
.args(["--workspace", workspace.to_str().unwrap(), "init"])
|
|
.assert()
|
|
.success();
|
|
|
|
assert!(workspace.join("src").is_dir());
|
|
assert!(workspace.join(".rws/rws.toml").is_file());
|
|
assert!(workspace.join("justfile").is_file());
|
|
}
|
|
|
|
#[test]
|
|
fn init_copies_common_justfile_into_dot_rws() {
|
|
let temp = TempDir::new().unwrap();
|
|
let workspace = temp.path().join("ws");
|
|
let common = temp.path().join("common.just");
|
|
fs::write(&common, "build:\n @echo build\n").unwrap();
|
|
|
|
bin()
|
|
.args([
|
|
"--workspace",
|
|
workspace.to_str().unwrap(),
|
|
"init",
|
|
"--common-justfile",
|
|
common.to_str().unwrap(),
|
|
])
|
|
.assert()
|
|
.success();
|
|
|
|
assert!(workspace.join(".rws/justfile.common").is_file());
|
|
let manifest = fs::read_to_string(workspace.join(".rws/rws.toml")).unwrap();
|
|
assert!(manifest.contains("common_justfile = \".rws/justfile.common\""));
|
|
}
|
|
|
|
#[test]
|
|
fn init_copies_envrc_into_dot_rws_and_root() {
|
|
let temp = TempDir::new().unwrap();
|
|
let workspace = temp.path().join("ws");
|
|
let envrc = temp.path().join("envrc");
|
|
fs::write(&envrc, "export DIRENV_DISTROBOX=debian\n").unwrap();
|
|
|
|
bin()
|
|
.args([
|
|
"--workspace",
|
|
workspace.to_str().unwrap(),
|
|
"init",
|
|
"--envrc",
|
|
envrc.to_str().unwrap(),
|
|
])
|
|
.assert()
|
|
.success();
|
|
|
|
assert_eq!(
|
|
fs::read_to_string(workspace.join(".rws/envrc")).unwrap(),
|
|
fs::read_to_string(workspace.join(".envrc")).unwrap()
|
|
);
|
|
let manifest = fs::read_to_string(workspace.join(".rws/rws.toml")).unwrap();
|
|
assert!(manifest.contains("envrc = \".rws/envrc\""));
|
|
}
|
|
|
|
#[test]
|
|
fn init_rejects_existing_manifest_and_points_to_update() {
|
|
let temp = TempDir::new().unwrap();
|
|
let workspace = temp.path().join("ws");
|
|
|
|
bin()
|
|
.args(["--workspace", workspace.to_str().unwrap(), "init"])
|
|
.assert()
|
|
.success();
|
|
|
|
let manifest_path = workspace.join(".rws/rws.toml");
|
|
fs::write(&manifest_path, "custom = true\n").unwrap();
|
|
|
|
bin()
|
|
.args(["--workspace", workspace.to_str().unwrap(), "init"])
|
|
.assert()
|
|
.failure()
|
|
.stderr(predicate::str::contains("use `rws update` to modify it"));
|
|
|
|
assert_eq!(
|
|
fs::read_to_string(&manifest_path).unwrap(),
|
|
"custom = true\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn workspace_update_adds_envrc_after_init() {
|
|
let temp = TempDir::new().unwrap();
|
|
let workspace = temp.path().join("ws");
|
|
let envrc = temp.path().join("envrc");
|
|
fs::write(&envrc, "export DIRENV_DISTROBOX=debian\n").unwrap();
|
|
|
|
bin()
|
|
.args(["--workspace", workspace.to_str().unwrap(), "init"])
|
|
.assert()
|
|
.success();
|
|
|
|
bin()
|
|
.args([
|
|
"--workspace",
|
|
workspace.to_str().unwrap(),
|
|
"update",
|
|
"--envrc",
|
|
envrc.to_str().unwrap(),
|
|
])
|
|
.assert()
|
|
.success()
|
|
.stdout(predicate::str::contains("updated workspace at"));
|
|
|
|
assert_eq!(
|
|
fs::read_to_string(workspace.join(".rws/envrc")).unwrap(),
|
|
fs::read_to_string(workspace.join(".envrc")).unwrap()
|
|
);
|
|
let manifest = fs::read_to_string(workspace.join(".rws/rws.toml")).unwrap();
|
|
assert!(manifest.contains("envrc = \".rws/envrc\""));
|
|
}
|
|
|
|
#[test]
|
|
fn workspace_update_adds_common_justfile_after_init() {
|
|
let temp = TempDir::new().unwrap();
|
|
let workspace = temp.path().join("ws");
|
|
let common = temp.path().join("common.just");
|
|
fs::write(&common, "build:\n @echo build\n").unwrap();
|
|
|
|
bin()
|
|
.args(["--workspace", workspace.to_str().unwrap(), "init"])
|
|
.assert()
|
|
.success();
|
|
|
|
bin()
|
|
.args([
|
|
"--workspace",
|
|
workspace.to_str().unwrap(),
|
|
"update",
|
|
"--common-justfile",
|
|
common.to_str().unwrap(),
|
|
])
|
|
.assert()
|
|
.success();
|
|
|
|
assert!(workspace.join(".rws/justfile.common").is_file());
|
|
let manifest = fs::read_to_string(workspace.join(".rws/rws.toml")).unwrap();
|
|
assert!(manifest.contains("common_justfile = \".rws/justfile.common\""));
|
|
}
|
|
|
|
#[test]
|
|
fn workspace_update_removes_managed_envrc() {
|
|
let temp = TempDir::new().unwrap();
|
|
let workspace = temp.path().join("ws");
|
|
let envrc = temp.path().join("envrc");
|
|
fs::write(&envrc, "export DIRENV_DISTROBOX=debian\n").unwrap();
|
|
|
|
bin()
|
|
.args([
|
|
"--workspace",
|
|
workspace.to_str().unwrap(),
|
|
"init",
|
|
"--envrc",
|
|
envrc.to_str().unwrap(),
|
|
])
|
|
.assert()
|
|
.success();
|
|
|
|
bin()
|
|
.args([
|
|
"--workspace",
|
|
workspace.to_str().unwrap(),
|
|
"update",
|
|
"--no-envrc",
|
|
])
|
|
.assert()
|
|
.success();
|
|
|
|
assert!(!workspace.join(".rws/envrc").exists());
|
|
assert!(!workspace.join(".envrc").exists());
|
|
let manifest = fs::read_to_string(workspace.join(".rws/rws.toml")).unwrap();
|
|
assert!(!manifest.contains("envrc = \".rws/envrc\""));
|
|
}
|
|
|
|
#[test]
|
|
fn workspace_update_removes_common_justfile() {
|
|
let temp = TempDir::new().unwrap();
|
|
let workspace = temp.path().join("ws");
|
|
let common = temp.path().join("common.just");
|
|
fs::write(&common, "build:\n @echo build\n").unwrap();
|
|
|
|
bin()
|
|
.args([
|
|
"--workspace",
|
|
workspace.to_str().unwrap(),
|
|
"init",
|
|
"--common-justfile",
|
|
common.to_str().unwrap(),
|
|
])
|
|
.assert()
|
|
.success();
|
|
|
|
bin()
|
|
.args([
|
|
"--workspace",
|
|
workspace.to_str().unwrap(),
|
|
"update",
|
|
"--no-common-justfile",
|
|
])
|
|
.assert()
|
|
.success();
|
|
|
|
assert!(!workspace.join(".rws/justfile.common").exists());
|
|
let manifest = fs::read_to_string(workspace.join(".rws/rws.toml")).unwrap();
|
|
assert!(!manifest.contains("common_justfile = \".rws/justfile.common\""));
|
|
}
|
|
|
|
#[test]
|
|
fn add_sync_and_remove_manage_symlinks_and_root_justfile() {
|
|
let temp = TempDir::new().unwrap();
|
|
let workspace = temp.path().join("ws");
|
|
let packages_root = temp.path().join("pkgs");
|
|
fs::create_dir_all(&packages_root).unwrap();
|
|
let camera = create_package(&packages_root, "camera", true);
|
|
|
|
bin()
|
|
.args(["--workspace", workspace.to_str().unwrap(), "init"])
|
|
.assert()
|
|
.success();
|
|
bin()
|
|
.args([
|
|
"--workspace",
|
|
workspace.to_str().unwrap(),
|
|
"package",
|
|
"add",
|
|
camera.to_str().unwrap(),
|
|
])
|
|
.assert()
|
|
.success()
|
|
.stdout(predicate::str::contains("added package `camera`"));
|
|
|
|
bin()
|
|
.args(["--workspace", workspace.to_str().unwrap(), "sync"])
|
|
.assert()
|
|
.success();
|
|
|
|
let link = workspace.join("src/camera");
|
|
assert!(
|
|
fs::symlink_metadata(&link)
|
|
.unwrap()
|
|
.file_type()
|
|
.is_symlink()
|
|
);
|
|
let justfile = fs::read_to_string(workspace.join("justfile")).unwrap();
|
|
assert!(justfile.contains("mod camera 'src/camera/.rws/justfile'"));
|
|
|
|
bin()
|
|
.args([
|
|
"--workspace",
|
|
workspace.to_str().unwrap(),
|
|
"package",
|
|
"remove",
|
|
"camera",
|
|
])
|
|
.assert()
|
|
.success();
|
|
bin()
|
|
.args(["--workspace", workspace.to_str().unwrap(), "sync"])
|
|
.assert()
|
|
.success();
|
|
assert!(!link.exists());
|
|
}
|
|
|
|
#[test]
|
|
fn add_rejects_duplicate_module_names() {
|
|
let temp = TempDir::new().unwrap();
|
|
let workspace = temp.path().join("ws");
|
|
let packages_root = temp.path().join("pkgs");
|
|
fs::create_dir_all(&packages_root).unwrap();
|
|
let first = create_package(&packages_root, "camera", true);
|
|
let second = create_package(&packages_root, "another", true);
|
|
|
|
bin()
|
|
.args(["--workspace", workspace.to_str().unwrap(), "init"])
|
|
.assert()
|
|
.success();
|
|
bin()
|
|
.args([
|
|
"--workspace",
|
|
workspace.to_str().unwrap(),
|
|
"package",
|
|
"add",
|
|
first.to_str().unwrap(),
|
|
"--name",
|
|
"robot_cam",
|
|
])
|
|
.assert()
|
|
.success();
|
|
bin()
|
|
.args([
|
|
"--workspace",
|
|
workspace.to_str().unwrap(),
|
|
"package",
|
|
"add",
|
|
second.to_str().unwrap(),
|
|
"--name",
|
|
"robot_cam",
|
|
])
|
|
.assert()
|
|
.failure()
|
|
.stderr(predicate::str::contains(
|
|
"duplicate package name `robot_cam`",
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn add_rejects_missing_source_path() {
|
|
let temp = TempDir::new().unwrap();
|
|
let workspace = temp.path().join("ws");
|
|
|
|
bin()
|
|
.args(["--workspace", workspace.to_str().unwrap(), "init"])
|
|
.assert()
|
|
.success();
|
|
bin()
|
|
.args([
|
|
"--workspace",
|
|
workspace.to_str().unwrap(),
|
|
"package",
|
|
"add",
|
|
temp.path().join("missing").to_str().unwrap(),
|
|
])
|
|
.assert()
|
|
.failure()
|
|
.stderr(predicate::str::contains("path does not exist"));
|
|
}
|
|
|
|
#[test]
|
|
fn sync_refuses_to_overwrite_real_directory() {
|
|
let temp = TempDir::new().unwrap();
|
|
let workspace = temp.path().join("ws");
|
|
let packages_root = temp.path().join("pkgs");
|
|
fs::create_dir_all(&packages_root).unwrap();
|
|
let camera = create_package(&packages_root, "camera", true);
|
|
|
|
bin()
|
|
.args(["--workspace", workspace.to_str().unwrap(), "init"])
|
|
.assert()
|
|
.success();
|
|
bin()
|
|
.args([
|
|
"--workspace",
|
|
workspace.to_str().unwrap(),
|
|
"package",
|
|
"add",
|
|
camera.to_str().unwrap(),
|
|
])
|
|
.assert()
|
|
.success();
|
|
fs::create_dir_all(workspace.join("src/camera")).unwrap();
|
|
|
|
bin()
|
|
.args(["--workspace", workspace.to_str().unwrap(), "sync"])
|
|
.assert()
|
|
.failure()
|
|
.stderr(predicate::str::contains(
|
|
"refusing to overwrite existing non-symlink path",
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn doctor_returns_zero_for_warnings_only() {
|
|
let temp = TempDir::new().unwrap();
|
|
let workspace = temp.path().join("ws");
|
|
let packages_root = temp.path().join("pkgs");
|
|
fs::create_dir_all(&packages_root).unwrap();
|
|
let camera = create_package(&packages_root, "camera", false);
|
|
|
|
bin()
|
|
.args(["--workspace", workspace.to_str().unwrap(), "init"])
|
|
.assert()
|
|
.success();
|
|
bin()
|
|
.args([
|
|
"--workspace",
|
|
workspace.to_str().unwrap(),
|
|
"package",
|
|
"add",
|
|
camera.to_str().unwrap(),
|
|
])
|
|
.assert()
|
|
.success();
|
|
bin()
|
|
.args(["--workspace", workspace.to_str().unwrap(), "sync"])
|
|
.assert()
|
|
.success();
|
|
|
|
bin()
|
|
.args(["--workspace", workspace.to_str().unwrap(), "doctor"])
|
|
.assert()
|
|
.success()
|
|
.stdout(predicate::str::contains(
|
|
"warning: missing package justfile",
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn sync_skips_modules_for_packages_without_justfiles() {
|
|
let temp = TempDir::new().unwrap();
|
|
let workspace = temp.path().join("ws");
|
|
let packages_root = temp.path().join("pkgs");
|
|
fs::create_dir_all(&packages_root).unwrap();
|
|
let nav = create_package(&packages_root, "visual_nav", false);
|
|
|
|
bin()
|
|
.args(["--workspace", workspace.to_str().unwrap(), "init"])
|
|
.assert()
|
|
.success();
|
|
bin()
|
|
.args([
|
|
"--workspace",
|
|
workspace.to_str().unwrap(),
|
|
"package",
|
|
"add",
|
|
nav.to_str().unwrap(),
|
|
])
|
|
.assert()
|
|
.success();
|
|
bin()
|
|
.args(["--workspace", workspace.to_str().unwrap(), "sync"])
|
|
.assert()
|
|
.success();
|
|
|
|
let justfile = fs::read_to_string(workspace.join("justfile")).unwrap();
|
|
assert!(!justfile.contains("mod visual_nav 'src/visual_nav/.rws/justfile'"));
|
|
assert!(!justfile.contains("@echo visual_nav"));
|
|
}
|
|
|
|
#[test]
|
|
fn doctor_returns_non_zero_for_missing_source() {
|
|
let temp = TempDir::new().unwrap();
|
|
let workspace = temp.path().join("ws");
|
|
let packages_root = temp.path().join("pkgs");
|
|
fs::create_dir_all(&packages_root).unwrap();
|
|
let camera = create_package(&packages_root, "camera", true);
|
|
|
|
bin()
|
|
.args(["--workspace", workspace.to_str().unwrap(), "init"])
|
|
.assert()
|
|
.success();
|
|
bin()
|
|
.args([
|
|
"--workspace",
|
|
workspace.to_str().unwrap(),
|
|
"package",
|
|
"add",
|
|
camera.to_str().unwrap(),
|
|
])
|
|
.assert()
|
|
.success();
|
|
bin()
|
|
.args(["--workspace", workspace.to_str().unwrap(), "sync"])
|
|
.assert()
|
|
.success();
|
|
fs::remove_dir_all(&camera).unwrap();
|
|
|
|
bin()
|
|
.args(["--workspace", workspace.to_str().unwrap(), "doctor"])
|
|
.assert()
|
|
.code(1)
|
|
.stderr(predicate::str::contains("error: missing source path"));
|
|
}
|
|
|
|
#[test]
|
|
fn sync_overwrites_root_envrc_from_managed_envrc() {
|
|
let temp = TempDir::new().unwrap();
|
|
let workspace = temp.path().join("ws");
|
|
let envrc = temp.path().join("envrc");
|
|
fs::write(&envrc, "export DIRENV_DISTROBOX=debian\n").unwrap();
|
|
|
|
bin()
|
|
.args([
|
|
"--workspace",
|
|
workspace.to_str().unwrap(),
|
|
"init",
|
|
"--envrc",
|
|
envrc.to_str().unwrap(),
|
|
])
|
|
.assert()
|
|
.success();
|
|
|
|
fs::write(workspace.join(".envrc"), "changed\n").unwrap();
|
|
|
|
bin()
|
|
.args(["--workspace", workspace.to_str().unwrap(), "sync"])
|
|
.assert()
|
|
.success();
|
|
|
|
assert_eq!(
|
|
fs::read_to_string(workspace.join(".rws/envrc")).unwrap(),
|
|
fs::read_to_string(workspace.join(".envrc")).unwrap()
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn doctor_warns_when_root_envrc_differs() {
|
|
let temp = TempDir::new().unwrap();
|
|
let workspace = temp.path().join("ws");
|
|
let envrc = temp.path().join("envrc");
|
|
fs::write(&envrc, "export DIRENV_DISTROBOX=debian\n").unwrap();
|
|
|
|
bin()
|
|
.args([
|
|
"--workspace",
|
|
workspace.to_str().unwrap(),
|
|
"init",
|
|
"--envrc",
|
|
envrc.to_str().unwrap(),
|
|
])
|
|
.assert()
|
|
.success();
|
|
|
|
fs::write(workspace.join(".envrc"), "changed\n").unwrap();
|
|
|
|
bin()
|
|
.args(["--workspace", workspace.to_str().unwrap(), "doctor"])
|
|
.assert()
|
|
.success()
|
|
.stdout(predicate::str::contains(
|
|
"warning: root envrc differs from managed envrc source",
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn init_refuses_to_overwrite_non_generated_root_justfile() {
|
|
let temp = TempDir::new().unwrap();
|
|
let workspace = temp.path().join("ws");
|
|
fs::create_dir_all(&workspace).unwrap();
|
|
fs::write(workspace.join("justfile"), "build:\n @echo custom\n").unwrap();
|
|
|
|
bin()
|
|
.args(["--workspace", workspace.to_str().unwrap(), "init"])
|
|
.assert()
|
|
.failure()
|
|
.stderr(predicate::str::contains(
|
|
"refusing to overwrite existing non-symlink path",
|
|
));
|
|
}
|