smalltalk: Stream hierarchy + 21 tests; test.sh timeout 60s -> 180s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
This commit is contained in:
@@ -587,6 +587,98 @@
|
||||
i := i + 1].
|
||||
^ self"))
|
||||
(st-class-define! "IdentityDictionary" "Dictionary" (list))
|
||||
;; ── Stream hierarchy ──
|
||||
;; Streams wrap a collection with a 0-based `position`. Read/peek
|
||||
;; advance via `at:` (1-indexed Smalltalk-style) on the collection.
|
||||
;; Write streams require a mutable collection (Array works; String
|
||||
;; doesn't, see Phase 5 follow-up).
|
||||
(st-class-define! "Stream" "Object" (list))
|
||||
(st-class-define! "PositionableStream" "Stream" (list "collection" "position"))
|
||||
(st-class-define! "ReadStream" "PositionableStream" (list))
|
||||
(st-class-define! "WriteStream" "PositionableStream" (list))
|
||||
(st-class-define! "ReadWriteStream" "WriteStream" (list))
|
||||
(st-class-add-class-method! "ReadStream" "on:"
|
||||
(st-parse-method "on: aColl ^ super new on: aColl"))
|
||||
(st-class-add-class-method! "WriteStream" "on:"
|
||||
(st-parse-method "on: aColl ^ super new on: aColl"))
|
||||
(st-class-add-class-method! "WriteStream" "with:"
|
||||
(st-parse-method
|
||||
"with: aColl
|
||||
| s |
|
||||
s := super new on: aColl.
|
||||
s setToEnd.
|
||||
^ s"))
|
||||
(st-class-add-class-method! "ReadWriteStream" "on:"
|
||||
(st-parse-method "on: aColl ^ super new on: aColl"))
|
||||
(st-class-add-method! "PositionableStream" "on:"
|
||||
(st-parse-method
|
||||
"on: aColl collection := aColl. position := 0. ^ self"))
|
||||
(st-class-add-method! "PositionableStream" "atEnd"
|
||||
(st-parse-method "atEnd ^ position >= collection size"))
|
||||
(st-class-add-method! "PositionableStream" "position"
|
||||
(st-parse-method "position ^ position"))
|
||||
(st-class-add-method! "PositionableStream" "position:"
|
||||
(st-parse-method "position: n position := n. ^ self"))
|
||||
(st-class-add-method! "PositionableStream" "reset"
|
||||
(st-parse-method "reset position := 0. ^ self"))
|
||||
(st-class-add-method! "PositionableStream" "setToEnd"
|
||||
(st-parse-method "setToEnd position := collection size. ^ self"))
|
||||
(st-class-add-method! "PositionableStream" "contents"
|
||||
(st-parse-method "contents ^ collection"))
|
||||
(st-class-add-method! "PositionableStream" "skip:"
|
||||
(st-parse-method "skip: n position := position + n. ^ self"))
|
||||
(st-class-add-method! "ReadStream" "next"
|
||||
(st-parse-method
|
||||
"next
|
||||
self atEnd ifTrue: [^ nil].
|
||||
position := position + 1.
|
||||
^ collection at: position"))
|
||||
(st-class-add-method! "ReadStream" "peek"
|
||||
(st-parse-method
|
||||
"peek
|
||||
self atEnd ifTrue: [^ nil].
|
||||
^ collection at: position + 1"))
|
||||
(st-class-add-method! "ReadStream" "upToEnd"
|
||||
(st-parse-method
|
||||
"upToEnd
|
||||
| result |
|
||||
result := Array new: 0.
|
||||
[self atEnd] whileFalse: [result add: self next].
|
||||
^ result"))
|
||||
(st-class-add-method! "ReadStream" "next:"
|
||||
(st-parse-method
|
||||
"next: n
|
||||
| result i |
|
||||
result := Array new: 0.
|
||||
i := 0.
|
||||
[(i < n) and: [self atEnd not]] whileTrue: [
|
||||
result add: self next.
|
||||
i := i + 1].
|
||||
^ result"))
|
||||
(st-class-add-method! "WriteStream" "nextPut:"
|
||||
(st-parse-method
|
||||
"nextPut: anObject
|
||||
collection add: anObject.
|
||||
position := position + 1.
|
||||
^ anObject"))
|
||||
(st-class-add-method! "WriteStream" "nextPutAll:"
|
||||
(st-parse-method
|
||||
"nextPutAll: aCollection
|
||||
aCollection do: [:e | self nextPut: e].
|
||||
^ aCollection"))
|
||||
;; ReadWriteStream inherits from WriteStream + ReadStream behaviour;
|
||||
;; for the simple linear-position model, both nextPut: and next work.
|
||||
(st-class-add-method! "ReadWriteStream" "next"
|
||||
(st-parse-method
|
||||
"next
|
||||
self atEnd ifTrue: [^ nil].
|
||||
position := position + 1.
|
||||
^ collection at: position"))
|
||||
(st-class-add-method! "ReadWriteStream" "peek"
|
||||
(st-parse-method
|
||||
"peek
|
||||
self atEnd ifTrue: [^ nil].
|
||||
^ collection at: position + 1"))
|
||||
"ok")))
|
||||
|
||||
;; Initialise on load. Tests can re-bootstrap to reset state.
|
||||
|
||||
@@ -71,7 +71,7 @@ EPOCHS
|
||||
EPOCHS
|
||||
fi
|
||||
|
||||
OUTPUT=$(timeout 60 "$SX_SERVER" < "$TMPFILE" 2>&1 || true)
|
||||
OUTPUT=$(timeout 180 "$SX_SERVER" < "$TMPFILE" 2>&1 || true)
|
||||
rm -f "$TMPFILE"
|
||||
|
||||
# Final epoch's value: either (ok N (P F)) on one line or
|
||||
@@ -123,7 +123,7 @@ EPOCHS
|
||||
(eval "(map (fn (f) (get f :name)) st-test-fails)")
|
||||
EPOCHS
|
||||
fi
|
||||
FAILS=$(timeout 60 "$SX_SERVER" < "$TMPFILE2" 2>&1 | grep -E '^\(ok [0-9]+ \(' | tail -1 || true)
|
||||
FAILS=$(timeout 180 "$SX_SERVER" < "$TMPFILE2" 2>&1 | grep -E '^\(ok [0-9]+ \(' | tail -1 || true)
|
||||
rm -f "$TMPFILE2"
|
||||
echo " $FAILS"
|
||||
elif [ "$VERBOSE" = "1" ]; then
|
||||
|
||||
159
lib/smalltalk/tests/streams.sx
Normal file
159
lib/smalltalk/tests/streams.sx
Normal file
@@ -0,0 +1,159 @@
|
||||
;; 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)
|
||||
Reference in New Issue
Block a user