;; 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)