(defsuite
  "multiple-values"
  (deftest
    "values single returns value directly"
    (do
      (assert= 42 (values 42))
      (assert= "hi" (values "hi"))
      (assert= nil (values nil))))
  (deftest
    "values multiple returns marker dict"
    (do
      (let
        ((v (values 1 2 3)))
        (assert (dict? v))
        (assert= true (get v :_values false))
        (assert-equal (list 1 2 3) (get v :_list)))))
  (deftest
    "call-with-values basic two values"
    (do
      (assert=
        3
        (call-with-values
          (fn () (values 1 2))
          (fn (a b) (+ a b))))))
  (deftest
    "call-with-values three values"
    (do
      (assert=
        6
        (call-with-values
          (fn () (values 1 2 3))
          (fn (a b c) (+ a b c))))))
  (deftest
    "call-with-values single value passthrough"
    (do
      (assert= 10 (call-with-values (fn () 10) (fn (x) x)))))
  (deftest
    "call-with-values passes non-values result as single arg"
    (do (assert= "hello" (call-with-values (fn () "hello") (fn (x) x)))))
  (deftest
    "call-with-values with string concat"
    (do
      (assert=
        "ab"
        (call-with-values (fn () (values "a" "b")) (fn (a b) (str a b))))))
  (deftest
    "let-values basic two bindings"
    (do
      (let-values
        (((a b) (values 10 20)))
        (assert= 10 a)
        (assert= 20 b))))
  (deftest
    "let-values computes with bindings"
    (do
      (let-values
        (((x y) (values 3 4)))
        (assert= 7 (+ x y)))))
  (deftest
    "let-values three values"
    (do
      (let-values
        (((a b c) (values 1 2 3)))
        (assert= 6 (+ a b c)))))
  (deftest
    "let-values single value binding"
    (do (let-values (((x) (values 42))) (assert= 42 x))))
  (deftest
    "let-values multiple binding clauses"
    (do
      (let-values
        (((a b) (values 1 2))
          ((c d) (values 3 4)))
        (assert= 10 (+ a b c d)))))
  (deftest
    "let-values body is multiple expressions"
    (do
      (let-values
        (((a b) (values 5 6)))
        (define sum (+ a b))
        (assert= 11 sum))))
  (deftest
    "let-values with no bindings evals body"
    (do (let-values () (assert= 99 99))))
  (deftest
    "define-values binds multiple names"
    (do
      (define-values (x y) (values 7 8))
      (assert= 7 x)
      (assert= 8 y)))
  (deftest
    "define-values three names"
    (do
      (define-values (a b c) (values 10 20 30))
      (assert= 10 a)
      (assert= 20 b)
      (assert= 30 c)))
  (deftest
    "define-values single name"
    (do (define-values (n) (values 42)) (assert= 42 n)))
  (deftest
    "define-values used in computation"
    (do
      (define-values (w h) (values 6 7))
      (assert= 42 (* w h))))
  (deftest
    "values in let binding"
    (do
      (let
        ((v (values 100 200)))
        (assert= true (get v :_values false))
        (assert= 100 (first (get v :_list))))))
  (deftest
    "call-with-values with swap"
    (do
      (define (swap a b) (values b a))
      (assert=
        5
        (call-with-values
          (fn () (swap 3 5))
          (fn (first-val second-val) first-val)))))
  (deftest
    "let-values from function returning values"
    (do
      (define (min-max a b) (values (min a b) (max a b)))
      (let-values
        (((lo hi) (min-max 7 3)))
        (assert= 3 lo)
        (assert= 7 hi))))
  (deftest
    "nested let-values"
    (do
      (let-values
        (((a b) (values 1 2)))
        (let-values
          (((c d) (values 3 4)))
          (assert= 10 (+ a b c d))))))
  (deftest
    "call-with-values chained"
    (do
      (define
        result
        (call-with-values
          (fn
            ()
            (call-with-values
              (fn () (values 4 6))
              (fn (a b) (* a b))))
          (fn (x) x)))
      (assert= 24 result)))
  (deftest
    "values zero args produces dict"
    (do
      (let
        ((v (values)))
        (assert (dict? v))
        (assert (get v :_values false))
        (assert-equal (list) (get v :_list)))))
  (deftest
    "let-values strings"
    (do
      (let-values
        (((first-name last-name) (values "Alice" "Smith")))
        (assert= "Alice Smith" (str first-name " " last-name)))))
  (deftest
    "define-values with list values"
    (do
      (define-values
        (head tail)
        (values 1 (list 2 3 4)))
      (assert= 1 head)
      (assert-equal (list 2 3 4) tail))))