smalltalk: ANSI X3J20 validator subset + 62 tests -> 813/813
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled

This commit is contained in:
2026-04-25 14:48:47 +00:00
parent 446a0e7d68
commit 5d369daf2b
4 changed files with 166 additions and 6 deletions

View File

@@ -1,5 +1,5 @@
{
"date": "2026-04-25T14:10:14Z",
"date": "2026-04-25T14:44:32Z",
"programs": [
"eight-queens.st",
"fibonacci.st",
@@ -9,7 +9,7 @@
],
"program_count": 5,
"program_tests_passed": 39,
"all_tests_passed": 751,
"all_tests_total": 751,
"all_tests_passed": 813,
"all_tests_total": 813,
"exit_code": 0
}

View File

@@ -1,12 +1,12 @@
# Smalltalk-on-SX Scoreboard
_Last run: 2026-04-25T14:10:14Z_
_Last run: 2026-04-25T14:44:32Z_
## Totals
| Suite | Passing |
|-------|---------|
| All Smalltalk-on-SX tests | **751 / 751** |
| All Smalltalk-on-SX tests | **813 / 813** |
| Classic-corpus tests (`tests/programs.sx`) | **39** |
## Classic-corpus programs (`lib/smalltalk/tests/programs/`)
@@ -22,6 +22,7 @@ _Last run: 2026-04-25T14:10:14Z_
## Per-file test counts
```
OK lib/smalltalk/tests/ansi.sx 62 passed
OK lib/smalltalk/tests/blocks.sx 19 passed
OK lib/smalltalk/tests/cannot_return.sx 5 passed
OK lib/smalltalk/tests/collections.sx 29 passed

158
lib/smalltalk/tests/ansi.sx Normal file
View File

@@ -0,0 +1,158 @@
;; ANSI X3J20 Smalltalk validator — stretch subset.
;;
;; Targets the mandatory protocols documented in the standard; one test
;; case per ANSI §6.x category. Test methods are run through the SUnit
;; framework; one st-test row per Smalltalk method (mirrors tests/pharo.sx).
(set! st-test-pass 0)
(set! st-test-fail 0)
(set! st-test-fails (list))
(define
ansi-source
"TestCase subclass: #AnsiObjectTest instanceVariableNames: ''!
!AnsiObjectTest methodsFor: '6.10 Object'!
testIdentity self assert: 42 == 42!
testIdentityNotEq self deny: 'a' == 'b'!
testEqualityIsAlsoIdentityOnInts self assert: 7 = 7!
testNotEqual self assert: (1 ~= 2)!
testIsNilOnNil self assert: nil isNil!
testIsNilOnInt self deny: 1 isNil!
testNotNil self assert: 42 notNil!
testClass self assert: 42 class = SmallInteger!
testYourself
| x | x := 99.
self assert: x yourself equals: 99! !
TestCase subclass: #AnsiBooleanTest instanceVariableNames: ''!
!AnsiBooleanTest methodsFor: '6.11 Boolean'!
testNot self assert: true not equals: false!
testAndTT self assert: (true & true)!
testAndTF self deny: (true & false)!
testAndFT self deny: (false & true)!
testAndFF self deny: (false & false)!
testOrTT self assert: (true | true)!
testOrTF self assert: (true | false)!
testOrFT self assert: (false | true)!
testOrFF self deny: (false | false)!
testIfTrueTaken self assert: (true ifTrue: [1] ifFalse: [2]) equals: 1!
testIfFalseTaken self assert: (false ifTrue: [1] ifFalse: [2]) equals: 2!
testAndShort self assert: (false and: [1/0]) equals: false!
testOrShort self assert: (true or: [1/0]) equals: true! !
TestCase subclass: #AnsiIntegerTest instanceVariableNames: ''!
!AnsiIntegerTest methodsFor: '6.13 Integer'!
testFactorial self assert: 6 factorial equals: 720!
testGcd self assert: (12 gcd: 18) equals: 6!
testLcm self assert: (4 lcm: 6) equals: 12!
testEven self assert: 8 even!
testOdd self assert: 9 odd!
testNegated self assert: 5 negated equals: -5!
testAbs self assert: -7 abs equals: 7! !
!AnsiIntegerTest methodsFor: '6.12 Number arithmetic'!
testAdd self assert: 1 + 2 equals: 3!
testSub self assert: 10 - 4 equals: 6!
testMul self assert: 6 * 7 equals: 42!
testMin self assert: (3 min: 7) equals: 3!
testMax self assert: (3 max: 7) equals: 7!
testBetween self assert: (5 between: 1 and: 10)! !
TestCase subclass: #AnsiStringTest instanceVariableNames: ''!
!AnsiStringTest methodsFor: '6.17 String'!
testSize self assert: 'abcdef' size equals: 6!
testConcat self assert: ('foo' , 'bar') equals: 'foobar'!
testAt self assert: ('abcd' at: 3) equals: 'c'!
testCopyFromTo self assert: ('helloworld' copyFrom: 1 to: 5) equals: 'hello'!
testAsSymbol self assert: 'foo' asSymbol == #foo!
testIsEmpty self assert: '' isEmpty! !
TestCase subclass: #AnsiArrayTest instanceVariableNames: ''!
!AnsiArrayTest methodsFor: '6.18 Array'!
testSize self assert: #(1 2 3) size equals: 3!
testAt self assert: (#(10 20 30) at: 2) equals: 20!
testAtPut
| a |
a := Array new: 3.
a at: 1 put: 100.
self assert: (a at: 1) equals: 100!
testDo
| s |
s := 0.
#(1 2 3) do: [:e | s := s + e].
self assert: s equals: 6!
testCollect self assert: (#(1 2 3) collect: [:x | x + 10]) equals: #(11 12 13)!
testSelect self assert: (#(1 2 3 4) select: [:x | x even]) equals: #(2 4)!
testReject self assert: (#(1 2 3 4) reject: [:x | x even]) equals: #(1 3)!
testInject self assert: (#(1 2 3 4 5) inject: 0 into: [:a :b | a + b]) equals: 15!
testIncludes self assert: (#(1 2 3) includes: 2)!
testFirst self assert: #(7 8 9) first equals: 7!
testLast self assert: #(7 8 9) last equals: 9! !
TestCase subclass: #AnsiBlockTest instanceVariableNames: ''!
!AnsiBlockTest methodsFor: '6.19 BlockContext'!
testValue self assert: [42] value equals: 42!
testValueOne self assert: ([:x | x * 2] value: 21) equals: 42!
testValueTwo self assert: ([:a :b | a + b] value: 3 value: 4) equals: 7!
testNumArgs self assert: [:a :b | a] numArgs equals: 2!
testValueWithArguments
self assert: ([:a :b | a , b] valueWithArguments: #('foo' 'bar')) equals: 'foobar'!
testWhileTrue
| n |
n := 5.
[n > 0] whileTrue: [n := n - 1].
self assert: n equals: 0!
testEnsureRunsOnNormal
| log |
log := Array new: 0.
[log add: #body] ensure: [log add: #cleanup].
self assert: log size equals: 2!
testOnDoCatchesError
| r |
r := [Error signal: 'boom'] on: Error do: [:e | e messageText].
self assert: r equals: 'boom'! !
TestCase subclass: #AnsiSymbolTest instanceVariableNames: ''!
!AnsiSymbolTest methodsFor: '6.16 Symbol'!
testEqual self assert: #foo = #foo!
testIdentity self assert: #bar == #bar!
testNotEq self deny: #a == #b! !")
(smalltalk-load ansi-source)
(define
pharo-test-class
(fn
(cls-name)
(let ((selectors (sort (keys (get (st-class-get cls-name) :methods)))))
(for-each
(fn (sel)
(when
(and (>= (len sel) 4) (= (slice sel 0 4) "test"))
(let
((src (str "| s r | s := " cls-name " suiteForAll: #(#"
sel "). r := s run.
^ {(r passCount). (r failureCount). (r errorCount)}")))
(let ((result (smalltalk-eval-program src)))
(st-test
(str cls-name " >> " sel)
result
(list 1 0 0))))))
selectors))))
(pharo-test-class "AnsiObjectTest")
(pharo-test-class "AnsiBooleanTest")
(pharo-test-class "AnsiIntegerTest")
(pharo-test-class "AnsiStringTest")
(pharo-test-class "AnsiArrayTest")
(pharo-test-class "AnsiBlockTest")
(pharo-test-class "AnsiSymbolTest")
(list st-test-pass st-test-fail)

View File

@@ -97,7 +97,7 @@ Core mapping:
- [x] Port SUnit (`lib/smalltalk/sunit.sx`). Written in Smalltalk source via `smalltalk-load`. Provides `TestCase` (with `setUp` / `tearDown` / `assert:` / `assert:description:` / `assert:equals:` / `deny:` / `should:raise:` / `shouldnt:raise:` / `runCase` / class-side `selector:` and `suiteForAll:`), `TestSuite` (`init`, `addTest:`, `addAll:`, `tests`, `run`, `runTest:result:`), `TestResult` (`passes`/`failures`/`errors`, counts, `allPassed`, `summary` using `String>>format:`), `TestFailure` (Error subclass raised by assertion failures and caught by the runner). 19 tests in `lib/smalltalk/tests/sunit.sx` exercise pass/fail counts, mixed suites, setUp threading, and should:raise:. test.sh now loads `lib/smalltalk/sunit.sx` in the bootstrap chain (nested SX `(load …)` from a test file does not reliably propagate top-level forms).
- [x] Vendor a slice of Pharo `Kernel-Tests` and `Collections-Tests`. `lib/smalltalk/tests/pharo/kernel.st` (IntegerTest / StringTest / BooleanTest, ~50 methods) and `tests/pharo/collections.st` (ArrayTest / DictionaryTest / SetTest, ~35 methods) hold the canonical Smalltalk source. `lib/smalltalk/tests/pharo.sx` carries the same source as strings (the `(load …)`-from-tests-files limitation we hit during SUnit), runs each test method through SUnit, and emits one st-test row per Smalltalk method — 91 in total.
- [x] Drive the scoreboard up: aim for 200+ green tests. **751 green** at this point — past the target by 3.7x.
- [ ] Stretch: ANSI Smalltalk validator subset
- [x] Stretch: ANSI Smalltalk validator subset (`lib/smalltalk/tests/ansi.sx`). 62 tests organised by ANSI X3J20 §6.10 Object, §6.11 Boolean, §6.12 Number, §6.13 Integer, §6.16 Symbol, §6.17 String, §6.18 Array, §6.19 BlockContext. Each test runs through SUnit and emits one st-test row, mirroring the Pharo-slice harness.
### Phase 7 — speed (optional)
- [ ] Method-dictionary inline caching (already in CEK as a primitive; just wire selector cache)
@@ -108,6 +108,7 @@ Core mapping:
_Newest first. Agent appends on every commit._
- 2026-04-25: ANSI X3J20 validator subset + 62 tests (`lib/smalltalk/tests/ansi.sx`). One TestCase subclass per ANSI §6.x protocol; runs through SUnit. **Phase 6 complete.** 813/813 total.
- 2026-04-25: Pharo Kernel-Tests + Collections-Tests slice + 91 pharo-style tests (`tests/pharo/{kernel,collections}.st` + `tests/pharo.sx`). Each Smalltalk test method runs as its own SUnit case and counts as one st-test toward the scoreboard. 751/751 total — past the Phase 6 "200+ green tests" target.
- 2026-04-25: SUnit port (`lib/smalltalk/sunit.sx`, `lib/smalltalk/tests/sunit.sx`) — TestCase/TestSuite/TestResult/TestFailure all written in Smalltalk source via `smalltalk-load`. Full assert family + should:raise: + setUp/tearDown threading. 19 tests verify the framework. test.sh now bootstraps SUnit alongside runtime/eval. 660/660 total.
- 2026-04-25: String>>format: + universal printOn: + 18 tests (`lib/smalltalk/tests/printing.sx`). `format:` does Pharo {N}-substitution; `printOn:` routes through user `printString` and coerces to a String for iteration. Phase 5 complete. 638/638 total.