mod common;
use common::{Session, TempProject};
fn fixture(label: &str, packages: &str) -> TempProject {
let project = TempProject::new(label);
project.write("default.project.json", "{\n \"name\": \"fixture\",\n \"tree\": {}\n}\n");
project.write(
"rproj.toml",
&format!(
"mode = \"expert\"\npackage_workflow = \"wally\"\npackages = [{packages}]\ntools_at_creation = [\"selene\", \"stylua\"]\n"
),
);
project
}
#[test]
fn a_stale_selene_config_is_brought_up_to_date() {
let project = fixture("selene-stale", "\"vide\", \"testez\"");
project.write(
"selene.toml",
"std = \"roblox\"\n\n[rules]\nunused_variable = \"allow\"\nmixed_table = \"warn\"\n",
);
let outcome = Session::start(project.path(), &["upgrade", "--yes"]).finish();
assert_eq!(outcome.code, 0, "{}", outcome.text);
let selene = project.read("selene.toml");
assert!(selene.contains(r#"mixed_table = "allow""#), "vide waiver missing:\n{selene}");
assert!(selene.contains(r#"std = "roblox+testez""#), "testez std missing:\n{selene}");
assert!(selene.contains(r#"exclude = ["Packages/**"#), "vendored exclude missing:\n{selene}");
assert!(selene.contains(r#"unused_variable = "allow""#), "clobbered a user choice:\n{selene}");
}
#[test]
fn a_project_without_a_create_style_ui_library_keeps_the_lint() {
let project = fixture("selene-nonvide", "\"charm\"");
project.write("selene.toml", "std = \"roblox\"\n\n[rules]\nmixed_table = \"warn\"\n");
assert_eq!(Session::start(project.path(), &["upgrade", "--yes"]).finish().code, 0);
assert!(project.read("selene.toml").contains(r#"mixed_table = "warn""#));
}
#[test]
fn deprecated_editor_settings_are_replaced_not_merely_supplemented() {
let project = fixture("vscode-deprecated", "\"charm\"");
project.write(
".vscode/settings.json",
"{\n \"editor.rulers\": [100],\n \"luau-lsp.plugin.enabled\": true,\n \"luau-lsp.types.roblox\": true\n}\n",
);
let outcome = Session::start(project.path(), &["upgrade", "--yes"]).finish();
assert_eq!(outcome.code, 0, "{}", outcome.text);
let settings = project.read(".vscode/settings.json");
assert!(settings.contains(r#""luau-lsp.studioPlugin.enabled": true"#), "{settings}");
assert!(!settings.contains(r#""luau-lsp.plugin.enabled""#), "deprecated key kept:\n{settings}");
assert!(!settings.contains(r#""luau-lsp.types.roblox""#), "deprecated key kept:\n{settings}");
assert!(settings.contains(r#""files.eol": "\n""#), "{settings}");
assert!(settings.contains(r#""editor.rulers""#), "unrelated key lost:\n{settings}");
}
#[test]
fn a_second_run_reports_nothing_to_do() {
let project = fixture("idempotent", "\"vide\"");
project.write("selene.toml", "std = \"roblox\"\n\n[rules]\nmixed_table = \"warn\"\n");
assert_eq!(Session::start(project.path(), &["upgrade", "--yes"]).finish().code, 0);
let after_first = project.read("selene.toml");
let second = Session::start(project.path(), &["upgrade", "--yes"]).finish();
assert_eq!(second.code, 0, "{}", second.text);
second.assert_contains("already up to date");
assert_eq!(project.read("selene.toml"), after_first, "second run rewrote the file");
}
#[test]
fn files_the_user_owns_are_left_alone() {
let project = fixture("hands-off", "\"vide\"");
project.write("selene.toml", "std = \"roblox\"\n\n[rules]\nmixed_table = \"warn\"\n");
let stylua = "column_width = 80\nindent_type = \"Spaces\"\n";
project.write("stylua.toml", stylua);
let manifest = "{\n \"name\": \"fixture\",\n \"tree\": {}\n}\n";
assert_eq!(Session::start(project.path(), &["upgrade", "--yes"]).finish().code, 0);
assert_eq!(project.read("stylua.toml"), stylua, "stylua.toml is the user's");
assert_eq!(project.read("default.project.json"), manifest, "the project file is the user's");
}
#[test]
fn a_project_with_no_manifest_is_refused_with_a_reason() {
let project = TempProject::new("no-manifest");
project.write("default.project.json", "{}\n");
let outcome = Session::start(project.path(), &["upgrade", "--yes"]).finish();
assert_eq!(outcome.code, 1, "{}", outcome.text);
outcome.assert_contains("no rproj.toml");
}
#[test]
fn a_directory_that_is_not_a_project_is_refused() {
let project = TempProject::new("not-a-project");
let outcome = Session::start(project.path(), &["upgrade", "--yes"]).finish();
assert_eq!(outcome.code, 1, "{}", outcome.text);
outcome.assert_contains("no default.project.json");
}