171 lines
6.3 KiB
Plaintext
171 lines
6.3 KiB
Plaintext
;; Erlang runtime tests — scheduler + process-record primitives.
|
|
|
|
(define er-rt-test-count 0)
|
|
(define er-rt-test-pass 0)
|
|
(define er-rt-test-fails (list))
|
|
|
|
(define
|
|
er-rt-test
|
|
(fn
|
|
(name actual expected)
|
|
(set! er-rt-test-count (+ er-rt-test-count 1))
|
|
(if
|
|
(= actual expected)
|
|
(set! er-rt-test-pass (+ er-rt-test-pass 1))
|
|
(append! er-rt-test-fails {:actual actual :expected expected :name name}))))
|
|
|
|
;; ── queue ─────────────────────────────────────────────────────────
|
|
(er-rt-test "queue empty len" (er-q-len (er-q-new)) 0)
|
|
(er-rt-test "queue empty?" (er-q-empty? (er-q-new)) true)
|
|
|
|
(define q1 (er-q-new))
|
|
(er-q-push! q1 "a")
|
|
(er-q-push! q1 "b")
|
|
(er-q-push! q1 "c")
|
|
(er-rt-test "queue push len" (er-q-len q1) 3)
|
|
(er-rt-test "queue empty? after push" (er-q-empty? q1) false)
|
|
(er-rt-test "queue peek" (er-q-peek q1) "a")
|
|
(er-rt-test "queue pop 1" (er-q-pop! q1) "a")
|
|
(er-rt-test "queue pop 2" (er-q-pop! q1) "b")
|
|
(er-rt-test "queue len after pops" (er-q-len q1) 1)
|
|
(er-rt-test "queue pop 3" (er-q-pop! q1) "c")
|
|
(er-rt-test "queue empty again" (er-q-empty? q1) true)
|
|
(er-rt-test "queue pop empty" (er-q-pop! q1) nil)
|
|
|
|
;; Queue FIFO under interleaved push/pop
|
|
(define q2 (er-q-new))
|
|
(er-q-push! q2 1)
|
|
(er-q-push! q2 2)
|
|
(er-q-pop! q2)
|
|
(er-q-push! q2 3)
|
|
(er-rt-test "queue interleave peek" (er-q-peek q2) 2)
|
|
(er-rt-test "queue to-list" (er-q-to-list q2) (list 2 3))
|
|
|
|
;; ── scheduler init ─────────────────────────────────────────────
|
|
(er-sched-init!)
|
|
(er-rt-test "sched process count 0" (er-sched-process-count) 0)
|
|
(er-rt-test "sched runnable count 0" (er-sched-runnable-count) 0)
|
|
(er-rt-test "sched current nil" (er-sched-current-pid) nil)
|
|
|
|
;; ── pid allocation ─────────────────────────────────────────────
|
|
(define pa (er-pid-new!))
|
|
(define pb (er-pid-new!))
|
|
(er-rt-test "pid tag" (get pa :tag) "pid")
|
|
(er-rt-test "pid ids distinct" (= (er-pid-id pa) (er-pid-id pb)) false)
|
|
(er-rt-test "pid? true" (er-pid? pa) true)
|
|
(er-rt-test "pid? false" (er-pid? 42) false)
|
|
(er-rt-test
|
|
"pid-equal same"
|
|
(er-pid-equal? pa (er-mk-pid (er-pid-id pa)))
|
|
true)
|
|
(er-rt-test "pid-equal diff" (er-pid-equal? pa pb) false)
|
|
|
|
;; ── process lifecycle ──────────────────────────────────────────
|
|
(er-sched-init!)
|
|
(define p1 (er-proc-new! {}))
|
|
(define p2 (er-proc-new! {}))
|
|
(er-rt-test "proc count 2" (er-sched-process-count) 2)
|
|
(er-rt-test "runnable count 2" (er-sched-runnable-count) 2)
|
|
(er-rt-test
|
|
"proc state runnable"
|
|
(er-proc-field (get p1 :pid) :state)
|
|
"runnable")
|
|
(er-rt-test
|
|
"proc mailbox empty"
|
|
(er-proc-mailbox-size (get p1 :pid))
|
|
0)
|
|
(er-rt-test
|
|
"proc lookup"
|
|
(er-pid-equal? (get (er-proc-get (get p1 :pid)) :pid) (get p1 :pid))
|
|
true)
|
|
(er-rt-test "proc exists" (er-proc-exists? (get p1 :pid)) true)
|
|
(er-rt-test
|
|
"proc no-such-pid"
|
|
(er-proc-exists? (er-mk-pid 9999))
|
|
false)
|
|
|
|
;; runnable queue dequeue order
|
|
(er-rt-test
|
|
"dequeue first"
|
|
(er-pid-equal? (er-sched-next-runnable!) (get p1 :pid))
|
|
true)
|
|
(er-rt-test
|
|
"dequeue second"
|
|
(er-pid-equal? (er-sched-next-runnable!) (get p2 :pid))
|
|
true)
|
|
(er-rt-test "dequeue empty" (er-sched-next-runnable!) nil)
|
|
|
|
;; current-pid get/set
|
|
(er-sched-set-current! (get p1 :pid))
|
|
(er-rt-test
|
|
"current pid set"
|
|
(er-pid-equal? (er-sched-current-pid) (get p1 :pid))
|
|
true)
|
|
|
|
;; ── mailbox push ──────────────────────────────────────────────
|
|
(er-proc-mailbox-push! (get p1 :pid) {:tag "atom" :name "ping"})
|
|
(er-proc-mailbox-push! (get p1 :pid) 42)
|
|
(er-rt-test "mailbox size 2" (er-proc-mailbox-size (get p1 :pid)) 2)
|
|
|
|
;; ── field update ──────────────────────────────────────────────
|
|
(er-proc-set! (get p1 :pid) :state "waiting")
|
|
(er-rt-test
|
|
"proc state waiting"
|
|
(er-proc-field (get p1 :pid) :state)
|
|
"waiting")
|
|
(er-proc-set! (get p1 :pid) :trap-exit true)
|
|
(er-rt-test
|
|
"proc trap-exit"
|
|
(er-proc-field (get p1 :pid) :trap-exit)
|
|
true)
|
|
|
|
;; ── fresh scheduler ends in clean state ───────────────────────
|
|
(er-sched-init!)
|
|
(er-rt-test
|
|
"sched init resets count"
|
|
(er-sched-process-count)
|
|
0)
|
|
(er-rt-test
|
|
"sched init resets queue"
|
|
(er-sched-runnable-count)
|
|
0)
|
|
(er-rt-test
|
|
"sched init resets current"
|
|
(er-sched-current-pid)
|
|
nil)
|
|
|
|
|
|
|
|
;; ── Phase 7: module-version slots ───────────────────────────────
|
|
(er-modules-reset!)
|
|
|
|
(define er-rt-slot1 (er-mk-module-slot (er-env-new) nil 1))
|
|
(er-rt-test "slot tag" (get er-rt-slot1 :tag) "module")
|
|
(er-rt-test "slot version" (er-module-version er-rt-slot1) 1)
|
|
(er-rt-test "slot old nil" (er-module-old-env er-rt-slot1) nil)
|
|
(er-rt-test "slot current not nil" (= (er-module-current-env er-rt-slot1) nil) false)
|
|
|
|
(erlang-load-module "-module(hr1). a() -> 1.")
|
|
(define er-rt-reg (er-modules-get))
|
|
(er-rt-test "registry has hr1" (dict-has? er-rt-reg "hr1") true)
|
|
(er-rt-test "v1 on first load" (er-module-version (get er-rt-reg "hr1")) 1)
|
|
(er-rt-test "v1 old is nil" (er-module-old-env (get er-rt-reg "hr1")) nil)
|
|
(er-rt-test "v1 current not nil" (= (er-module-current-env (get er-rt-reg "hr1")) nil) false)
|
|
|
|
(define er-rt-env-v1 (er-module-current-env (get er-rt-reg "hr1")))
|
|
(erlang-load-module "-module(hr1). a() -> 2.")
|
|
(er-rt-test "v2 on second load" (er-module-version (get er-rt-reg "hr1")) 2)
|
|
(er-rt-test "v2 old is v1 env" (er-module-old-env (get er-rt-reg "hr1")) er-rt-env-v1)
|
|
(er-rt-test "v2 current is new" (= (er-module-current-env (get er-rt-reg "hr1")) er-rt-env-v1) false)
|
|
|
|
(erlang-load-module "-module(hr1). a() -> 3.")
|
|
(er-rt-test "v3 on third load" (er-module-version (get er-rt-reg "hr1")) 3)
|
|
|
|
(er-modules-reset!)
|
|
(er-rt-test "registry-reset clears" (dict-has? (er-modules-get) "hr1") false)
|
|
|
|
|
|
(define
|
|
er-rt-test-summary
|
|
(str "runtime " er-rt-test-pass "/" er-rt-test-count))
|