;; Stream hierarchy tests — ReadStream / WriteStream / ReadWriteStream
;; built on a `collection` + `position` pair. Reads use Smalltalk's
;; 1-indexed `at:`; writes use the collection's `add:`.

(set! st-test-pass 0)
(set! st-test-fail 0)
(set! st-test-fails (list))

(st-bootstrap-classes!)
(define ev (fn (src) (smalltalk-eval src)))
(define evp (fn (src) (smalltalk-eval-program src)))

;; ── 1. Class hierarchy ──
(st-test "ReadStream < PositionableStream"
  (st-class-inherits-from? "ReadStream" "PositionableStream") true)
(st-test "WriteStream < PositionableStream"
  (st-class-inherits-from? "WriteStream" "PositionableStream") true)
(st-test "ReadWriteStream < WriteStream"
  (st-class-inherits-from? "ReadWriteStream" "WriteStream") true)

;; ── 2. ReadStream basics ──
(st-test "ReadStream next" (evp "^ (ReadStream on: #(1 2 3)) next") 1)

(st-test "ReadStream sequential reads"
  (evp
    "| s |
     s := ReadStream on: #(10 20 30).
     ^ {s next. s next. s next}")
  (list 10 20 30))

(st-test "ReadStream atEnd"
  (evp
    "| s |
     s := ReadStream on: #(1 2).
     s next. s next.
     ^ s atEnd")
  true)

(st-test "ReadStream next past end returns nil"
  (evp
    "| s |
     s := ReadStream on: #(1).
     s next.
     ^ s next")
  nil)

(st-test "ReadStream peek doesn't advance"
  (evp
    "| s |
     s := ReadStream on: #(7 8 9).
     ^ {s peek. s peek. s next}")
  (list 7 7 7))

(st-test "ReadStream position"
  (evp
    "| s |
     s := ReadStream on: #(1 2 3 4).
     s next. s next.
     ^ s position")
  2)

(st-test "ReadStream reset goes back to start"
  (evp
    "| s |
     s := ReadStream on: #(1 2 3).
     s next. s next. s next.
     s reset.
     ^ s next")
  1)

(st-test "ReadStream upToEnd"
  (evp
    "| s |
     s := ReadStream on: #(1 2 3 4 5).
     s next. s next.
     ^ s upToEnd")
  (list 3 4 5))

(st-test "ReadStream next: takes up to n"
  (evp
    "| s |
     s := ReadStream on: #(10 20 30 40 50).
     ^ s next: 3")
  (list 10 20 30))

(st-test "ReadStream skip:"
  (evp
    "| s |
     s := ReadStream on: #(1 2 3 4 5).
     s skip: 2.
     ^ s next")
  3)

;; ── 3. WriteStream basics ──
(st-test "WriteStream nextPut: + contents"
  (evp
    "| s |
     s := WriteStream on: (Array new: 0).
     s nextPut: 10.
     s nextPut: 20.
     s nextPut: 30.
     ^ s contents")
  (list 10 20 30))

(st-test "WriteStream nextPutAll:"
  (evp
    "| s |
     s := WriteStream on: (Array new: 0).
     s nextPutAll: #(1 2 3).
     ^ s contents")
  (list 1 2 3))

(st-test "WriteStream nextPut: returns the value"
  (evp "^ (WriteStream on: (Array new: 0)) nextPut: 42") 42)

(st-test "WriteStream position tracks writes"
  (evp
    "| s |
     s := WriteStream on: (Array new: 0).
     s nextPut: #a. s nextPut: #b.
     ^ s position")
  2)

;; ── 4. WriteStream with: pre-fills ──
(st-test "WriteStream with: starts at end"
  (evp
    "| s |
     s := WriteStream with: #(1 2 3).
     s nextPut: 99.
     ^ s contents")
  (list 1 2 3 99))

;; ── 5. ReadStream on:collection works on String at: ──
(st-test "ReadStream on String reads chars"
  (evp
    "| s |
     s := ReadStream on: 'abc'.
     ^ {s next. s next. s next}")
  (list "a" "b" "c"))

(st-test "ReadStream atEnd on String"
  (evp
    "| s |
     s := ReadStream on: 'ab'.
     s next. s next.
     ^ s atEnd")
  true)

;; ── 6. ReadWriteStream ──
(st-test "ReadWriteStream read after writes"
  (evp
    "| s |
     s := ReadWriteStream on: (Array new: 0).
     s nextPut: 1. s nextPut: 2. s nextPut: 3.
     s reset.
     ^ {s next. s next. s next}")
  (list 1 2 3))

(list st-test-pass st-test-fail)
