;; test-vectors.sx — Tests for vector primitives

(defsuite
  "vectors"
  (deftest
    "make-vector default fill is nil"
    (let
      ((v (make-vector 3)))
      (assert (vector? v))
      (assert-equal 3 (vector-length v))
      (assert-equal nil (vector-ref v 0))
      (assert-equal nil (vector-ref v 1))
      (assert-equal nil (vector-ref v 2))))
  (deftest
    "make-vector with fill value"
    (let
      ((v (make-vector 4 99)))
      (assert-equal 4 (vector-length v))
      (assert-equal 99 (vector-ref v 0))
      (assert-equal 99 (vector-ref v 1))
      (assert-equal 99 (vector-ref v 2))
      (assert-equal 99 (vector-ref v 3))))
  (deftest
    "make-vector size zero"
    (let ((v (make-vector 0))) (assert-equal 0 (vector-length v))))
  (deftest
    "make-vector size one"
    (let
      ((v (make-vector 1 "x")))
      (assert-equal 1 (vector-length v))
      (assert-equal "x" (vector-ref v 0))))
  (deftest
    "vector constructor no args"
    (let ((v (vector))) (assert-equal 0 (vector-length v))))
  (deftest
    "vector constructor with args"
    (let
      ((v (vector 10 20 30)))
      (assert-equal 3 (vector-length v))
      (assert-equal 10 (vector-ref v 0))
      (assert-equal 20 (vector-ref v 1))
      (assert-equal 30 (vector-ref v 2))))
  (deftest
    "vector constructor strings"
    (let
      ((v (vector "a" "b" "c")))
      (assert-equal "a" (vector-ref v 0))
      (assert-equal "b" (vector-ref v 1))
      (assert-equal "c" (vector-ref v 2))))
  (deftest "vector? true for vector" (assert (vector? (make-vector 3))))
  (deftest "vector? false for list" (assert (not (vector? (list 1 2 3)))))
  (deftest "vector? false for number" (assert (not (vector? 42))))
  (deftest "vector? false for nil" (assert (not (vector? nil))))
  (deftest "vector? false for string" (assert (not (vector? "hello"))))
  (deftest "vector-length zero" (assert-equal 0 (vector-length (vector))))
  (deftest
    "vector-length three"
    (assert-equal 3 (vector-length (vector 1 2 3))))
  (deftest
    "vector-length after make-vector"
    (assert-equal 7 (vector-length (make-vector 7 0))))
  (deftest
    "vector-ref first element"
    (assert-equal 1 (vector-ref (vector 1 2 3) 0)))
  (deftest
    "vector-ref last element"
    (assert-equal 3 (vector-ref (vector 1 2 3) 2)))
  (deftest
    "vector-ref middle element"
    (assert-equal 2 (vector-ref (vector 1 2 3) 1)))
  (deftest
    "vector-set! mutates in place"
    (let
      ((v (vector 1 2 3)))
      (vector-set! v 1 99)
      (assert-equal 99 (vector-ref v 1))
      (assert-equal 1 (vector-ref v 0))
      (assert-equal 3 (vector-ref v 2))))
  (deftest
    "vector-set! first slot"
    (let
      ((v (make-vector 3 0)))
      (vector-set! v 0 42)
      (assert-equal 42 (vector-ref v 0))))
  (deftest
    "vector-set! last slot"
    (let
      ((v (make-vector 3 0)))
      (vector-set! v 2 77)
      (assert-equal 77 (vector-ref v 2))))
  (deftest
    "vector-set! returns nil"
    (let ((v (make-vector 3 0))) (assert-equal nil (vector-set! v 0 1))))
  (deftest
    "vector->list empty"
    (assert-equal (list) (vector->list (vector))))
  (deftest
    "vector->list numbers"
    (assert-equal (list 1 2 3) (vector->list (vector 1 2 3))))
  (deftest
    "vector->list strings"
    (assert-equal (list "a" "b") (vector->list (vector "a" "b"))))
  (deftest
    "list->vector empty"
    (let ((v (list->vector (list)))) (assert-equal 0 (vector-length v))))
  (deftest
    "list->vector numbers"
    (let
      ((v (list->vector (list 10 20 30))))
      (assert-equal 3 (vector-length v))
      (assert-equal 10 (vector-ref v 0))
      (assert-equal 20 (vector-ref v 1))
      (assert-equal 30 (vector-ref v 2))))
  (deftest
    "vector-fill! sets all elements"
    (let
      ((v (vector 1 2 3)))
      (vector-fill! v 0)
      (assert-equal 0 (vector-ref v 0))
      (assert-equal 0 (vector-ref v 1))
      (assert-equal 0 (vector-ref v 2))))
  (deftest
    "vector-fill! returns nil"
    (assert-equal nil (vector-fill! (make-vector 2 0) 7)))
  (deftest
    "vector-fill! string fill"
    (let
      ((v (make-vector 3 "")))
      (vector-fill! v "x")
      (assert-equal "x" (vector-ref v 0))
      (assert-equal "x" (vector-ref v 2))))
  (deftest
    "vector-copy full copy"
    (let
      ((v1 (vector 1 2 3)) (v2 (vector-copy (vector 1 2 3))))
      (assert-equal 3 (vector-length v2))
      (assert-equal 1 (vector-ref v2 0))
      (assert-equal 2 (vector-ref v2 1))
      (assert-equal 3 (vector-ref v2 2))))
  (deftest
    "vector-copy is independent"
    (let
      ((v1 (vector 1 2 3)))
      (let
        ((v2 (vector-copy v1)))
        (vector-set! v1 0 99)
        (assert-equal 1 (vector-ref v2 0)))))
  (deftest
    "vector-copy with start"
    (let
      ((v (vector-copy (vector 10 20 30 40) 1)))
      (assert-equal 3 (vector-length v))
      (assert-equal 20 (vector-ref v 0))
      (assert-equal 30 (vector-ref v 1))
      (assert-equal 40 (vector-ref v 2))))
  (deftest
    "vector-copy with start and end"
    (let
      ((v (vector-copy (vector 10 20 30 40) 1 3)))
      (assert-equal 2 (vector-length v))
      (assert-equal 20 (vector-ref v 0))
      (assert-equal 30 (vector-ref v 1))))
  (deftest
    "vector-copy empty slice"
    (let
      ((v (vector-copy (vector 1 2 3) 1 1)))
      (assert-equal 0 (vector-length v))))
  (deftest
    "vector-ref out of bounds raises"
    (let
      ((ok false))
      (guard (exn (else (set! ok true))) (vector-ref (vector 1 2 3) 5))
      (assert ok)))
  (deftest
    "vector-ref negative index raises"
    (let
      ((ok false))
      (guard (exn (else (set! ok true))) (vector-ref (vector 1 2 3) -1))
      (assert ok)))
  (deftest
    "vector-set! out of bounds raises"
    (let
      ((ok false))
      (guard
        (exn (else (set! ok true)))
        (vector-set! (vector 1 2 3) 10 99))
      (assert ok)))
  (deftest
    "vector list round-trip"
    (let
      ((lst (list 5 10 15 20)))
      (assert-equal lst (vector->list (list->vector lst)))))
  (deftest
    "vector mutation does not affect copy"
    (let
      ((v1 (vector 1 2 3)))
      (let
        ((v2 (vector-copy v1)))
        (vector-set! v2 0 100)
        (assert-equal 1 (vector-ref v1 0))
        (assert-equal 100 (vector-ref v2 0)))))
  (deftest
    "vector-length after fill"
    (let
      ((v (make-vector 5 0)))
      (vector-fill! v 1)
      (assert-equal 5 (vector-length v)))))
