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
2ec05c8 1
module std
2ec05c8 2
b7071c9 3
import std/Option
b7071c9 4
import std/Result
b7071c9 5
import std/List
73b5e55 6
import std/Bool
ca5fd6f 7
import std/Number
29313cb 8
import std/Str
2ec05c8 9
2ec05c8 10
# Small jest/rspec-style assertion helpers for use inside `test` blocks, e.g.
2ec05c8 11
#
2ec05c8 12
#   test "add works"
a9a0147 13
#     assert expectEq(add(1, 2), 3)
a9a0147 14
#     assert expectTrue(isEven(4))
2ec05c8 15
#
a9a0147 16
# These are plain functions returning `Bool` (`assert` only takes a bare
a9a0147 17
# boolean expression — see `plum-core/parser.rs`'s `assert` rule), not a new
a9a0147 18
# grammar form. They exist purely to make the condition read like an
2ec05c8 19
# assertion instead of a raw comparison.
2ec05c8 20
#
2ec05c8 21
# `expectArray`/`expectSome`/`expectOk`/`expectErr` below take a container
2ec05c8 22
# type (`List[T]`/`Option[T]`/`Result[T, E]`) whose OWN generic param is
2ec05c8 23
# nested inside the param type — this used to hit a real monomorphizer bug
2ec05c8 24
# (misclassified as a "bare generic class reference" fn, then lost its type
2ec05c8 25
# argument when the specialized signature was registered, mismatching the
2ec05c8 26
# caller's concrete arg type; fixed in `plum-checker/src/monomorphize.rs`'s
2ec05c8 27
# `fnGenericParams`/`resolveFnInstantiation`, see the
2ec05c8 28
# `plum_generic_method_self_nesting_landmine`-adjacent compiler-bugs memory).
2ec05c8 29
# The underlying type's own method (`result.isOk()`, `listA.equals(listB)`)
2ec05c8 30
# still works too and reads just as well — use whichever fits the call site.
2ec05c8 31
#
2ec05c8 32
# CAVEAT on `expectEq`/`expectNotEq`/`expectObject`/`List.equals`: Plum's
2ec05c8 33
# `==`/`!=` have no operator-overloading mechanism. For Int/Str/Bool/Float
2ec05c8 34
# they do real value comparison (Str is content-compared, not
2ec05c8 35
# reference-compared). For class/enum instances there is no such override,
2ec05c8 36
# so `==` compiles to reference identity — `expectEq` on two
2ec05c8 37
# separately-constructed-but-equal structs will wrongly report `false`. For
2ec05c8 38
# those types, prefer the type's own `equals(self, other)` method (e.g.
a9a0147 39
# `Uuid.equals`, `Time.equals`) directly in `assert` instead.
2ec05c8 40
2ec05c8 41
fun expectTrue(cond: Bool) -> Bool =
2ec05c8 42
  cond
2ec05c8 43
2ec05c8 44
fun expectFalse(cond: Bool) -> Bool =
2ec05c8 45
  !cond
2ec05c8 46
2ec05c8 47
fun expectEq(a: T, b: T) -> Bool =
2ec05c8 48
  a == b
2ec05c8 49
2ec05c8 50
fun expectNotEq(a: T, b: T) -> Bool =
2ec05c8 51
  a != b
2ec05c8 52
2ec05c8 53
# See the module-level CAVEAT above — this is `expectEq` under a name that
2ec05c8 54
# reads better at a class/struct call site; it does NOT do structural
2ec05c8 55
# (field-by-field) comparison.
2ec05c8 56
fun expectObject(a: T, b: T) -> Bool =
2ec05c8 57
  a == b
2ec05c8 58
2ec05c8 59
# Elementwise `List[T]` comparison — see the module-level CAVEAT above for
2ec05c8 60
# what `List.equals`'s own `==` means when `T` is a class/enum.
2ec05c8 61
fun expectArray(a: List[T], b: List[T]) -> Bool =
2ec05c8 62
  a.equals(b)
2ec05c8 63
2ec05c8 64
fun expectSome(o: Option[T]) -> Bool =
2ec05c8 65
  o.isSome()
2ec05c8 66
2ec05c8 67
fun expectNone(o: Option[T]) -> Bool =
2ec05c8 68
  o.isNone()
2ec05c8 69
2ec05c8 70
fun expectOk(r: Result[T, E]) -> Bool =
2ec05c8 71
  r.isOk()
2ec05c8 72
2ec05c8 73
fun expectErr(r: Result[T, E]) -> Bool =
2ec05c8 74
  r.isErr()
2ec05c8 75
2ec05c8 76
fun makeOkForTestingTest() -> Result[Int, Str] =
2ec05c8 77
  return Ok(5)
2ec05c8 78
2ec05c8 79
fun makeErrForTestingTest() -> Result[Int, Str] =
2ec05c8 80
  return Err("bad")
2ec05c8 81
2ec05c8 82
fun makeNoneForTestingTest() -> Option[Int] =
2ec05c8 83
  return None
2ec05c8 84
2ec05c8 85
test "expectTrue and expectFalse"
a9a0147 86
  assert expectTrue(1 == 1)
a9a0147 87
  assert expectFalse(1 == 2)
2ec05c8 88
2ec05c8 89
test "expectEq and expectNotEq"
a9a0147 90
  assert expectEq(2 + 2, 4)
a9a0147 91
  assert expectEq("ab" + "c", "abc")
a9a0147 92
  assert expectNotEq(2 + 2, 5)
2ec05c8 93
2ec05c8 94
test "list equality via the List.equals method"
4a2384c 95
  a := List(1, 2, 3)
4a2384c 96
  b := List(1, 2, 3)
4a2384c 97
  c := List(1, 2)
a9a0147 98
  assert a.equals(b)
a9a0147 99
  assert expectFalse(a.equals(c))
2ec05c8 100
2ec05c8 101
test "Option/Result checks via their own isSome/isNone/isOk/isErr methods"
a9a0147 102
  assert Some(1).isSome()
a9a0147 103
  assert makeNoneForTestingTest().isNone()
a9a0147 104
  assert makeOkForTestingTest().isOk()
a9a0147 105
  assert makeErrForTestingTest().isErr()
2ec05c8 106
2ec05c8 107
test "expectArray compares two List[T]s elementwise"
4a2384c 108
  a := List(1, 2, 3)
4a2384c 109
  b := List(1, 2, 3)
4a2384c 110
  c := List(1, 2)
a9a0147 111
  assert expectArray(a, b)
a9a0147 112
  assert expectFalse(expectArray(a, c))
4a2384c 113
  d := List("x", "y")
4a2384c 114
  e := List("x", "y")
a9a0147 115
  assert expectArray(d, e)
2ec05c8 116
2ec05c8 117
test "expectSome/expectNone/expectOk/expectErr check the right variant"
a9a0147 118
  assert expectSome(Some(1))
a9a0147 119
  assert expectFalse(expectSome(makeNoneForTestingTest()))
a9a0147 120
  assert expectNone(makeNoneForTestingTest())
a9a0147 121
  assert expectOk(makeOkForTestingTest())
a9a0147 122
  assert expectFalse(expectOk(makeErrForTestingTest()))
a9a0147 123
  assert expectErr(makeErrForTestingTest())
a9a0147 124
  assert expectFalse(expectErr(makeOkForTestingTest()))