plum

#treesitter#compiler#wasm

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()))