plum
git clone https://git.pyrossh.dev/plum
A statically typed, imperative programming language inspired by rust, python
plum-core/tests/formatter_test.rs
#![allow(non_snake_case)]
use plum_core::formatSource;
#[test]
fn formatsSimpleFunction() {
let input = "fun main() =\n x = 1\n";
let result = formatSource(input).expect("formatSource should succeed");
assert!(result.contains("main()"));
assert!(result.contains("x ="));
}
#[test]
fn formatsBinaryOperatorSpacing() {
let input = "fun add(a: Int, b: Int) -> Int =\n a+b\n";
let result = formatSource(input).expect("formatSource should succeed");
assert!(result.contains("a + b"));
}
#[test]
fn rejectsSyntaxError() {
let input = "@@@@invalid@@@@\n";
let result = formatSource(input);
assert!(result.is_err());
}
#[test]
fn idempotentOnAlreadyFormatted() {
let input = "fun main() =\n x = 1 + 2\n";
let first = formatSource(input).expect("first pass");
let second = formatSource(&first).expect("second pass");
assert_eq!(first, second, "formatting should be idempotent");
}
/// Regression test for a real bug: Topiary inserts NO whitespace between
/// adjacent leaves unless a query says to, so keywords with no explicit
/// spacing rule glue to the next token ("module" + "test" -> "moduletest").
/// This exercises most of the keyword vocabulary in one pass.
#[test]
fn keywordsGetSpacedCorrectly() {
let input = "\
module test
import std/os
type Cat(IAnimal) =
name: Str
age: Int
fun speak(self) -> Str =
\"meow\"
fun classify(x: Int) -> Str =
if x < 0
return \"neg\"
else if x == 0
return \"zero\"
else
return \"pos\"
fun loop() -> Int =
i := 0
while i < 5
i = i + 1
return i
fun main() =
assert 1 == 1
return
";
let once = formatSource(input).expect("first pass");
assert!(once.contains("module test"), "got: {once}");
assert!(once.contains("import std/os"), "got: {once}");
assert!(once.contains("type Cat"), "got: {once}");
assert!(once.contains("fun speak"), "got: {once}");
assert!(once.contains("if x < 0"), "got: {once}");
assert!(once.contains("else if x == 0"), "got: {once}");
let twice = formatSource(&once).expect("second pass");
assert_eq!(once, twice, "formatting should be idempotent");
}
/// Regression test: `import std/os` used to format down to `import /` — the
/// `url` grammar rule matched each path segment with a bare inline regex (no
/// node of its own), and Topiary's leaf collection only ever copies a
/// child NODE's own span, silently dropping any parent text a bare regex
/// like that leaves uncovered.
#[test]
fn importPathSegmentsSurviveFormatting() {
let input = "module test\nimport std/http/content_type\n";
let once = formatSource(input).expect("first pass");
assert!(once.contains("import std/http/content_type"), "got: {once}");
}
/// Regression test: the ternary `?`/`:` had no spacing rule at all, and enum
/// variants / match cases (`| Foo`, `match ... case`) live directly under
/// their parent node (no wrapping body), so they need their own hardline
/// rules distinct from a `fn` body's.
#[test]
fn ternaryEnumAndMatchFormatCorrectlyAndIdempotently() {
let input = "\
module test
enum Color =
| Red
| Green
fun isRed(self) -> Bool =
match self
Red => True
Green => False
fun abs(x: Int) -> Int =
x < 0 ? -x : x
";
let once = formatSource(input).expect("first pass");
assert!(once.contains("x < 0 ? -x : x"), "got: {once}");
assert!(once.contains("| Red"), "got: {once}");
let twice = formatSource(&once).expect("second pass");
assert_eq!(once, twice, "formatting should be idempotent");
}
/// Regression test: a standalone comment between two statements/methods used
/// to glue onto the end of the previous line on a SECOND formatting pass
/// (the naive fix, `@prepend_hardline`, would instead wrongly force even a
/// TRAILING same-line comment onto its own line) — `@prepend_input_softline`
/// preserves whichever the source actually had.
#[test]
fn commentsFormatIdempotently() {
let input = "\
fun abs(self) -> Int =
self < 0 ? -self : self
# a standalone comment between two functions
fun square(self) -> Int =
self * self # a trailing comment
";
let once = formatSource(input).expect("first pass");
let twice = formatSource(&once).expect("second pass");
assert_eq!(once, twice, "formatting should be idempotent");
}