use only_syntax::{ParseResultExt, format_range, format_source};
use text_size::{TextRange, TextSize};
#[test]
fn formatting_is_idempotent() {
let source = "!version 0.3\n\n\n!var target=\"release\"\n\nbuild(\n\tprofile = \"release\",\n)\n ? @has( \"cargo\" )\n & ( check,test )\n:\n\t|echo one\n\t|\n\t| echo two\n";
let formatted = format_source(source).expect("valid source should format");
assert_eq!(
formatted,
format_source(&formatted).expect("formatted source should parse")
);
assert_eq!(
formatted,
"!version 0.3\n!var target = \"release\"\n\nbuild(profile = \"release\") ? @has(\"cargo\") & (check, test):\n | echo one\n |\n | echo two\n"
);
}
#[test]
fn wraps_long_task_headers() {
let source = concat!(
"release(channel=\"nightly-build-with-a-long-channel-name\", ",
"destination=\"production-artifact-storage-with-a-long-name\") ",
"? @has(\"cargo\") & (sign, package) & upload shell~=bash:\n",
" echo unchanged $HOME\n",
);
assert_eq!(
format_source(source).expect("valid source should format"),
concat!(
"release(channel = \"nightly-build-with-a-long-channel-name\", destination = ",
"\"production-artifact-storage-with-a-long-name\")\n",
" ? @has(\"cargo\")\n",
" & (sign, package)\n",
" & upload\n",
" shell~=bash\n",
":\n",
" echo unchanged $HOME\n",
)
);
}
#[test]
fn wraps_headers_with_three_clauses() {
let source = "install() ? @os(\"windows\") & _release_build shell~=pwsh:\n echo ok\n";
assert_eq!(
format_source(source).expect("valid source should format"),
"install()\n ? @os(\"windows\")\n & _release_build\n shell~=pwsh\n:\n echo ok\n"
);
}
#[test]
fn formats_multiline_header_inside_namespace() {
let source = concat!(
"!version 0.3\n",
"[back] {\n",
" ci() & fmt & check & clippy & test:\n",
" echo done\n",
"}\n",
);
let formatted = format_source(source).expect("valid source should format");
assert_eq!(
formatted,
concat!(
"!version 0.3\n",
"\n",
"[back] {\n",
" ci()\n",
" & fmt\n",
" & check\n",
" & clippy\n",
" & test\n",
" :\n",
" echo done\n",
"}\n",
)
);
assert!(only_syntax::parse(&formatted).diagnostics().is_empty());
}
#[test]
fn preserves_comments_and_namespace_boundaries() {
let source = concat!(
"!version 0.3\n",
"# Build tools.\n",
"[ tools ] {\n",
"// Keep this comment. \n",
"build():\n",
" cargo build \n",
"}\n",
"root():\n",
" true\n",
);
assert_eq!(
format_source(source).expect("valid source should format"),
concat!(
"!version 0.3\n",
"\n",
"# Build tools.\n",
"[tools] {\n",
" // Keep this comment.\n",
" build():\n",
" cargo build \n",
"}\n",
"\n",
"root():\n",
" true\n",
)
);
}
#[test]
fn preserves_structured_metadata_comments() {
let source = "[help] Deploy app\n[desc] Supports staging\nrun():\n true\n";
assert_eq!(format_source(source).expect("source should format"), source);
}
#[test]
fn keeps_group_metadata_attached_after_blank_lines() {
let source = concat!(
"!version 0.4\n",
"[help] Development builds\n",
"[desc] Build in development mode.\n",
"\n",
"group dev {\n",
" build():\n",
" cargo build\n",
"}\n",
);
assert_eq!(
format_source(source).expect("source should format"),
concat!(
"!version 0.4\n",
"\n",
"[help] Development builds\n",
"[desc] Build in development mode.\n",
"group dev {\n",
"\n",
" build():\n",
" cargo build\n",
"}\n",
)
);
}
#[test]
fn orders_declaration_metadata() {
let source = "[fail] Failed\n[desc] Details\n[pass] Done\n[help] Build\nbuild():\n true\n";
assert_eq!(
format_source(source).expect("source should format"),
"[help] Build\n[desc] Details\n[pass] Done\n[fail] Failed\nbuild():\n true\n"
);
}
#[test]
fn formats_namespace_indentation() {
let source = "!version 0.3\n[dev] {\nrun():\n true\n }\n";
assert_eq!(
format_source(source).expect("valid source should format"),
"!version 0.3\n\n[dev] {\n run():\n true\n}\n"
);
}
#[test]
fn range_formats_one_declaration() {
let source = "first():\n true\nsecond( value=\"x\" ):\n\t|echo ok\n";
let start = TextSize::from(source.find("second").expect("task should exist") as u32);
let selection = TextRange::empty(start);
let (range, formatted) = format_range(source, selection)
.expect("valid source should format")
.expect("selection should touch a task");
assert_eq!(
&source[usize::from(range.start())..usize::from(range.end())],
"second( value=\"x\" ):\n\t|echo ok\n"
);
assert_eq!(formatted, "second(value = \"x\"):\n | echo ok\n");
}
#[test]
fn range_formats_namespaced_task_indentation() {
let source = "!version 0.3\n[dev] {\n build( value=\"x\" ):\n echo ok\n}\n";
let start = TextSize::from(source.find("build").expect("task should exist") as u32);
let (range, formatted) = format_range(source, TextRange::empty(start))
.expect("valid source should format")
.expect("selection should touch a task");
assert_eq!(
&source[usize::from(range.start())..usize::from(range.end())],
" build( value=\"x\" ):\n echo ok\n"
);
assert_eq!(formatted, " build(value = \"x\"):\n echo ok\n");
}
#[test]
fn formatting_rejects_invalid_source() {
assert!(format_source("broken(\n").is_err());
assert!(format_source("build(): cargo build\n").is_err());
assert!(format_source("build():").is_err());
}
#[test]
fn formats_dependency_arguments() {
let source = concat!(
"build(profile, mode):\n true\n",
"test(profile):\n true\n",
"ci() & ( build ( \"dev\" ,\"fast\" ) , test( \"ci\" ) ):\n true\n",
);
assert_eq!(
format_source(source).expect("source should format"),
concat!(
"build(profile, mode):\n true\n\n",
"test(profile):\n true\n\n",
"ci() & (build(\"dev\", \"fast\"), test(\"ci\")):\n true\n",
)
);
}