use crate::tests_common::{test_format, test_ir_format};
#[test]
fn format_trailing_comma_compact_param_set() {
test_format("{ a, b }: a");
test_format("{\n a,\n b,\n}: a");
}
#[test]
fn format_set_param_open_trailing_comment_hoisted() {
test_format("{ /*c*/ a, b, }: x");
test_format("{ /*c*/ }: x");
test_ir_format("{ /*c*/ a, b, }: x");
}
#[test]
fn format_trailing_comment_ignored_for_width() {
test_format("{\n unstableVersionInNixFormat = parsed != null; # heuristics\n}\n");
test_format(concat!(
"{\n x = a != null; ",
"# a trailing comment that is quite a bit longer than the binding itself but still irrelevant\n",
"}\n",
));
test_format("[\n a # c\n b\n]\n");
test_format(concat!(
"{\n someVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongName = ",
"aaaaaaaa != bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; # c\n}\n",
));
}
#[test]
fn format_trailing_comment_shift_for_idempotency() {
test_format("{ a # b\n= 1; }");
test_format("[ # c\n1\n]");
test_format("{ b # a\n? # a\nnull\n,}: b");
}
#[test]
fn format_paren_abstraction_absorbed_as_last_arg() {
test_ir_format("f (finalAttrs: {\n x = 1;\n y = 2;\n})");
}
#[test]
fn format_lambda_chain_stays_one_line_when_fits() {
test_format(
"{\n addPackageRequires =\n pkg: packageRequires: addPackageRequiresWhen pkg packageRequires (finalAttrs: previousAttrs: true);\n}",
);
test_format(
"{\n formatLoadPath =\n loadPathItem: \"-L ${\n if builtins.isString loadPathItem then loadPathItem else \"${loadPathItem}/share/emacs/site-lisp\"\n }\";\n}",
);
}
#[test]
fn format_nested_lambda_body_absorbed() {
test_ir_format("final: prev: {\n a = 1;\n b = 2;\n}");
}
#[test]
fn format_with_body_absorbed() {
test_ir_format("self: with self; {\n a = 1;\n b = 2;\n}");
test_ir_format("{\n meta = with lib; {\n license = mit;\n };\n}");
}
#[test]
fn format_assignment_rhs_app_with_string_last_arg() {
test_ir_format("{\n w = writeShellScript \"n\" ''\n echo a\n echo b\n '';\n}");
}
#[test]
fn format_if_elseif_chain_forced_multiline() {
test_ir_format("{ x = if a then \"x\" else if b then \"y\" else \"z\"; }");
}
#[test]
fn format_multi_arg_application_continuation_indent() {
test_ir_format("runCommand \"n\"\n {\n a = 1;\n }\n ''\n echo a\n ''");
}
#[test]
fn format_app_comment_before_last_arg_indent() {
test_format("(map toString\n # comment\n (builtins.filter f version))");
test_format(
"{\n v = lib.concat \".\" (\n map toString\n # comment\n (builtins.filter f version)\n );\n}",
);
}
#[test]
fn format_assignment_rhs_update_concat_plus_case1() {
test_format("{ meta = oldAttrs.meta // { description = \"x\"; }; }");
test_ir_format("{ meta = oldAttrs.meta // { description = \"x\"; }; }");
test_format("{ x = a.b or [ ] ++ [ y ]; }");
test_ir_format("{ x = a.b or [ ] ++ [ y ]; }");
test_format("{ x = lib.optionals a [ p ] ++ lib.optionals b [ q ]; }");
test_ir_format("{ x = /* c */ [ a ] ++ [ b ]; }");
test_ir_format("{ x = [ a ] ++ [ b ] ++ [ c ]; }");
}
#[test]
fn format_assignment_rhs_update_concat_plus_case2() {
test_format("{ x = a // { y = 1;\n z = 2;\n}; }");
test_ir_format("{ x = a // { y = 1;\n z = 2;\n}; }");
}
#[test]
fn format_app_multi_absorbable_args_indent() {
test_format("runCommand \"n\"\n {\n a = 1;\n }\n ''\n echo a\n ''");
test_format("f\n {\n a = 1;\n }\n (\n b: c\n )");
}
#[test]
fn format_app_set_absorb_in_binding() {
test_format("{\n x = mk {\n a = 1;\n } ''\n echo a\n '';\n}");
}
#[test]
fn format_interp_lone_application_absorbed() {
test_format("''\n ${lib.optionalString (!isWindows) ''\n one\n two\n ''}\n''");
test_format("''\n ${lib.optionalString a b ''\n one\n two\n ''}\n''");
test_ir_format("''\n ${lib.optionalString cond ''\n one\n two\n ''}\n''");
test_format(concat!(
"''\n x\n ${lib.optionalString cond ''\n",
" linkPath one two three four five six seven eight nine ten eleven twelve thirteen fourteen\n",
" ''}\n''",
));
test_format(concat!(
"''\n ${lib.concatMapStringsSep \"n\" (\n",
" e: \"ln -sfn ${e}/share/vscode/extensions/aaaa/bbb/ccc/dddd\"\n",
" ) nixExtsDrvs}\n''",
));
}
#[test]
fn format_interp_inline_short_forced_compact() {
test_format(concat!(
"''\n wrap a/very/long/share/vscode/extensions/ms-vscode.cpptools/debug/bin/OpenDebugAD7 ",
"--prefix PATH : ${lib.makeBinPath [ gdb ]}\n''",
));
test_ir_format("''\n prefix ${lib.makeBinPath [ gdb ]} suffix\n''");
}
#[test]
fn format_comparison_op_softline() {
test_format(concat!(
"{\n x =\n f (\n a:\n if cond ",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa then\n",
" a\n else\n b\n ) y != y;\n}",
));
test_format("{\n x =\n a ==\n # note\n b.c (d: e);\n}");
test_ir_format("a == b");
test_format("a // { b = 1; } == { c = 1; }");
}
#[test]
fn format_assignment_non_simple_selector_breaks_rhs() {
test_format(concat!(
"{\n \"PKG_CONFIG_GIMP_${pkgConfigMajorVersion}_0_GIMPLIBDIR\" = ",
"\"${placeholder \"out\"}/${gimp.targetLibDir}\";\n}",
));
test_format(concat!(
"{\n a.b.c.d.e = \"",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\";\n}",
));
}
#[test]
fn format_trailing_file_trivia_preserved() {
test_format("{ a = 1; }\n# trailing\n");
test_format("1\n/* block */\n");
test_ir_format("{ a = 1; }\n# trailing\n");
}
#[test]
fn format_interp_trailing_trivia_preserved() {
test_format("''\n ${ f a b\n # c\n }\n''");
test_format("\"${ x\n# c\n}\"");
}
#[test]
fn format_interp_leading_trivia_preserved() {
test_format("''\n ${ # leading\n x }\n''");
test_format("\"${ /* c */ x}\"");
test_format("{ ${ # c\nx } = 1; }");
test_format("a.${ # c\nx }");
}
#[test]
fn format_text_width_counts_chars_not_bytes() {
test_format(
"{\n getName =\n attrs: attrs.name or \"${attrs.pname or \"\u{ab}name-missing\u{bb}\"}-${attrs.version or \"\u{ab}version-missing\u{bb}\"}\";\n}\n",
);
}
#[test]
fn format_empty_set_with_pretrivia_keeps_linebreak() {
test_format("# c\n{\n}\n");
}
#[test]
fn format_indented_string_lone_interpolation_with_trailing_trivia() {
test_format("''\n${x\n# c\n}\n''\n");
test_format("''\n ${ x\n # multi\n # line\n }\n''\n");
}