(defsuite
  "match-literals"
  (deftest
    "match number"
    (assert-equal "one" (match 1 (1 "one") (2 "two"))))
  (deftest
    "match string"
    (assert-equal "hello" (match "hi" ("hi" "hello") ("bye" "goodbye"))))
  (deftest
    "match boolean"
    (assert-equal "yes" (match true (true "yes") (false "no"))))
  (deftest
    "match nil"
    (assert-equal "nothing" (match nil (nil "nothing") (_ "something")))))

(defsuite
  "match-binding"
  (deftest
    "wildcard matches anything"
    (assert-equal "ok" (match 42 (_ "ok"))))
  (deftest "symbol binds value" (assert-equal 42 (match 42 (x x))))
  (deftest "binding used in body" (assert-equal 84 (match 42 (x (* x 2))))))

(defsuite
  "match-lists"
  (deftest
    "match list structure"
    (assert-equal 3 (match (list 1 2) ((a b) (+ a b)))))
  (deftest
    "match nested list"
    (assert-equal
      "y"
      (match (list 1 (list 2 3)) ((a (b c)) (if (= c 3) "y" "n")))))
  (deftest
    "match empty list"
    (assert-equal "empty" (match (list) (() "empty") (_ "nonempty")))))

(defsuite
  "match-quoted"
  (deftest
    "match quoted symbol"
    (assert-equal
      "got-foo"
      (match (quote foo) ((quote foo) "got-foo") ((quote bar) "got-bar"))))
  (deftest
    "match quoted vs binding"
    (assert-equal
      "bound: foo"
      (match (quote foo) ((quote bar) "got-bar") (x (str "bound: " x))))))

(defsuite
  "match-predicates"
  (deftest
    "predicate match"
    (assert-equal
      "it's a number"
      (match 42 ((? number?) "it's a number") (_ "other"))))
  (deftest
    "predicate with string"
    (assert-equal
      "text"
      (match "hello" ((? number?) "num") ((? string?) "text") (_ "other"))))
  (deftest
    "no match errors"
    (assert-throws (fn () (match 42 (0 "zero") (1 "one"))))))
