;; test-sequences.sx — Phase 11: sequence protocol tests

(defsuite
  "sequences"
  (deftest
    "seq-to-list nil is empty list"
    (assert-equal (list) (seq-to-list nil)))
  (deftest
    "seq-to-list list is identity"
    (assert-equal
      (list 1 2 3)
      (seq-to-list (list 1 2 3))))
  (deftest
    "seq-to-list vector to list"
    (assert-equal
      (list 10 20 30)
      (seq-to-list (vector 10 20 30))))
  (deftest
    "seq-to-list string to char list"
    (assert-equal (list "a" "b" "c") (seq-to-list "abc")))
  (deftest
    "seq-to-list empty string to empty list"
    (assert-equal (list) (seq-to-list "")))
  (deftest
    "sequence-to-list nil is empty list"
    (assert-equal (list) (sequence-to-list nil)))
  (deftest
    "sequence-to-list list is identity"
    (assert-equal
      (list 1 2 3)
      (sequence-to-list (list 1 2 3))))
  (deftest
    "sequence-to-list vector to list"
    (assert-equal (list "x" "y") (sequence-to-list (vector "x" "y"))))
  (deftest
    "sequence-to-list string to char list"
    (assert-equal (list "h" "i") (sequence-to-list "hi")))
  (deftest
    "sequence-to-vector nil is empty vector"
    (let
      ((v (sequence-to-vector nil)))
      (do (assert (vector? v)) (assert= 0 (vector-length v)))))
  (deftest
    "sequence-to-vector list to vector"
    (let
      ((v (sequence-to-vector (list 1 2 3))))
      (do
        (assert (vector? v))
        (assert= 3 (vector-length v))
        (assert= 1 (vector-ref v 0))
        (assert= 3 (vector-ref v 2)))))
  (deftest
    "sequence-to-vector string to vector of chars"
    (let
      ((v (sequence-to-vector "abc")))
      (do
        (assert (vector? v))
        (assert= 3 (vector-length v))
        (assert= "a" (vector-ref v 0))
        (assert= "c" (vector-ref v 2)))))
  (deftest
    "sequence-length nil is 0"
    (assert= 0 (sequence-length nil)))
  (deftest
    "sequence-length empty list is 0"
    (assert= 0 (sequence-length (list))))
  (deftest
    "sequence-length list of 3"
    (assert=
      3
      (sequence-length (list 1 2 3))))
  (deftest
    "sequence-length empty vector is 0"
    (assert= 0 (sequence-length (vector))))
  (deftest
    "sequence-length vector of 4"
    (assert=
      4
      (sequence-length (vector 10 20 30 40))))
  (deftest
    "sequence-length empty string is 0"
    (assert= 0 (sequence-length "")))
  (deftest
    "sequence-length string hello"
    (assert= 5 (sequence-length "hello")))
  (deftest
    "sequence-ref list first"
    (assert=
      10
      (sequence-ref (list 10 20 30) 0)))
  (deftest
    "sequence-ref list last"
    (assert=
      30
      (sequence-ref (list 10 20 30) 2)))
  (deftest
    "sequence-ref vector middle"
    (assert=
      20
      (sequence-ref (vector 10 20 30) 1)))
  (deftest
    "sequence-ref string first char"
    (assert= "h" (sequence-ref "hello" 0)))
  (deftest
    "sequence-ref string last char"
    (assert= "o" (sequence-ref "hello" 4)))
  (deftest
    "sequence-append two lists"
    (assert-equal
      (list 1 2 3 4)
      (sequence-append
        (list 1 2)
        (list 3 4))))
  (deftest
    "sequence-append list with empty"
    (assert-equal
      (list 1 2)
      (sequence-append (list 1 2) (list))))
  (deftest
    "sequence-append two strings"
    (assert= "hello world" (sequence-append "hello " "world")))
  (deftest
    "sequence-append empty strings"
    (assert= "abc" (sequence-append "" "abc")))
  (deftest
    "in-range 1-arg gives 0..n-1"
    (assert-equal
      (list 0 1 2 3 4)
      (in-range 5)))
  (deftest
    "in-range 1-arg zero is empty"
    (assert-equal (list) (in-range 0)))
  (deftest
    "in-range 2-arg start and end"
    (assert-equal
      (list 1 2 3)
      (in-range 1 4)))
  (deftest
    "in-range 2-arg same start end is empty"
    (assert-equal (list) (in-range 3 3)))
  (deftest
    "in-range 3-arg with step 2"
    (assert-equal
      (list 0 2 4)
      (in-range 0 6 2)))
  (deftest
    "in-range result is a list"
    (assert (list? (in-range 5))))
  (deftest
    "in-range length is correct"
    (assert= 10 (len (in-range 10))))
  (deftest
    "map over vector"
    (assert-equal
      (list 2 4 6)
      (map
        (fn (x) (* x 2))
        (vector 1 2 3))))
  (deftest
    "filter over vector keeps odds"
    (assert-equal
      (list 1 3 5)
      (filter
        odd?
        (vector 1 2 3 4 5))))
  (deftest
    "reduce over vector sums"
    (assert=
      10
      (reduce
        +
        0
        (vector 1 2 3 4))))
  (deftest
    "some over vector finds odd"
    (assert (some odd? (vector 2 4 3 6))))
  (deftest
    "every? over vector all even"
    (assert
      (every? even? (vector 2 4 6 8))))
  (deftest
    "every? over vector fails with odd"
    (assert= false (every? even? (vector 2 3 6))))
  (deftest
    "map over in-range squares"
    (assert-equal
      (list 0 1 4 9 16)
      (map (fn (x) (* x x)) (in-range 5))))
  (deftest
    "filter over in-range keeps evens"
    (assert-equal
      (list 0 2 4 6)
      (filter even? (in-range 7))))
  (deftest
    "reduce over in-range sums"
    (assert= 15 (reduce + 0 (in-range 6))))
  (deftest
    "map over string returns char list"
    (assert-equal (list "a" "b" "c") (map (fn (c) c) "abc")))
  (deftest
    "filter over string keeps matching chars"
    (assert-equal (list "p" "p") (filter (fn (c) (= c "p")) "apple"))))
