plum
git clone https://git.pyrossh.dev/plum
A statically typed, imperative programming language inspired by rust, python
plum-std/Testing.plum
module std
import std/Option
import std/Result
import std/List
import std/Bool
import std/Number
import std/Str
# Small jest/rspec-style assertion helpers for use inside `test` blocks, e.g.
#
# test "add works"
# assert expectEq(add(1, 2), 3)
# assert expectTrue(isEven(4))
#
# These are plain functions returning `Bool` (`assert` only takes a bare
# boolean expression — see `plum-core/parser.rs`'s `assert` rule), not a new
# grammar form. They exist purely to make the condition read like an
# assertion instead of a raw comparison.
#
# `expectArray`/`expectSome`/`expectOk`/`expectErr` below take a container
# type (`List[T]`/`Option[T]`/`Result[T, E]`) whose OWN generic param is
# nested inside the param type — this used to hit a real monomorphizer bug
# (misclassified as a "bare generic class reference" fn, then lost its type
# argument when the specialized signature was registered, mismatching the
# caller's concrete arg type; fixed in `plum-checker/src/monomorphize.rs`'s
# `fnGenericParams`/`resolveFnInstantiation`, see the
# `plum_generic_method_self_nesting_landmine`-adjacent compiler-bugs memory).
# The underlying type's own method (`result.isOk()`, `listA.equals(listB)`)
# still works too and reads just as well — use whichever fits the call site.
#
# CAVEAT on `expectEq`/`expectNotEq`/`expectObject`/`List.equals`: Plum's
# `==`/`!=` have no operator-overloading mechanism. For Int/Str/Bool/Float
# they do real value comparison (Str is content-compared, not
# reference-compared). For class/enum instances there is no such override,
# so `==` compiles to reference identity — `expectEq` on two
# separately-constructed-but-equal structs will wrongly report `false`. For
# those types, prefer the type's own `equals(self, other)` method (e.g.
# `Uuid.equals`, `Time.equals`) directly in `assert` instead.
fun expectTrue(cond: Bool) -> Bool =
cond
fun expectFalse(cond: Bool) -> Bool =
!cond
fun expectEq(a: T, b: T) -> Bool =
a == b
fun expectNotEq(a: T, b: T) -> Bool =
a != b
# See the module-level CAVEAT above — this is `expectEq` under a name that
# reads better at a class/struct call site; it does NOT do structural
# (field-by-field) comparison.
fun expectObject(a: T, b: T) -> Bool =
a == b
# Elementwise `List[T]` comparison — see the module-level CAVEAT above for
# what `List.equals`'s own `==` means when `T` is a class/enum.
fun expectArray(a: List[T], b: List[T]) -> Bool =
a.equals(b)
fun expectSome(o: Option[T]) -> Bool =
o.isSome()
fun expectNone(o: Option[T]) -> Bool =
o.isNone()
fun expectOk(r: Result[T, E]) -> Bool =
r.isOk()
fun expectErr(r: Result[T, E]) -> Bool =
r.isErr()
fun makeOkForTestingTest() -> Result[Int, Str] =
return Ok(5)
fun makeErrForTestingTest() -> Result[Int, Str] =
return Err("bad")
fun makeNoneForTestingTest() -> Option[Int] =
return None
test "expectTrue and expectFalse"
assert expectTrue(1 == 1)
assert expectFalse(1 == 2)
test "expectEq and expectNotEq"
assert expectEq(2 + 2, 4)
assert expectEq("ab" + "c", "abc")
assert expectNotEq(2 + 2, 5)
test "list equality via the List.equals method"
a := List(1, 2, 3)
b := List(1, 2, 3)
c := List(1, 2)
assert a.equals(b)
assert expectFalse(a.equals(c))
test "Option/Result checks via their own isSome/isNone/isOk/isErr methods"
assert Some(1).isSome()
assert makeNoneForTestingTest().isNone()
assert makeOkForTestingTest().isOk()
assert makeErrForTestingTest().isErr()
test "expectArray compares two List[T]s elementwise"
a := List(1, 2, 3)
b := List(1, 2, 3)
c := List(1, 2)
assert expectArray(a, b)
assert expectFalse(expectArray(a, c))
d := List("x", "y")
e := List("x", "y")
assert expectArray(d, e)
test "expectSome/expectNone/expectOk/expectErr check the right variant"
assert expectSome(Some(1))
assert expectFalse(expectSome(makeNoneForTestingTest()))
assert expectNone(makeNoneForTestingTest())
assert expectOk(makeOkForTestingTest())
assert expectFalse(expectOk(makeErrForTestingTest()))
assert expectErr(makeErrForTestingTest())
assert expectFalse(expectErr(makeOkForTestingTest()))