;; Tests for mutable hash tables (Phase 10) (defsuite "hash-table" (deftest "make-hash-table returns a hash table" (assert (hash-table? (make-hash-table)))) (deftest "hash-table? false for dict" (assert= false (hash-table? {:a 1}))) (deftest "hash-table? false for nil" (assert= false (hash-table? nil))) (deftest "hash-table? false for list" (assert= false (hash-table? (list 1 2)))) (deftest "empty table has size 0" (assert= 0 (hash-table-size (make-hash-table)))) (deftest "size after one set" (let ((ht (make-hash-table))) (hash-table-set! ht "a" 1) (assert= 1 (hash-table-size ht)))) (deftest "size after multiple sets" (let ((ht (make-hash-table))) (hash-table-set! ht "a" 1) (hash-table-set! ht "b" 2) (hash-table-set! ht "c" 3) (assert= 3 (hash-table-size ht)))) (deftest "set same key does not grow size" (let ((ht (make-hash-table))) (hash-table-set! ht "a" 1) (hash-table-set! ht "a" 2) (assert= 1 (hash-table-size ht)))) (deftest "ref returns set value" (let ((ht (make-hash-table))) (hash-table-set! ht "k" 42) (assert= 42 (hash-table-ref ht "k")))) (deftest "ref returns updated value after overwrite" (let ((ht (make-hash-table))) (hash-table-set! ht "k" 1) (hash-table-set! ht "k" 99) (assert= 99 (hash-table-ref ht "k")))) (deftest "ref with default returns default for missing key" (assert= "fallback" (hash-table-ref (make-hash-table) "missing" "fallback"))) (deftest "ref with default returns value when key exists" (let ((ht (make-hash-table))) (hash-table-set! ht "x" 7) (assert= 7 (hash-table-ref ht "x" 0)))) (deftest "keyword keys work" (let ((ht (make-hash-table))) (hash-table-set! ht :foo "bar") (assert= "bar" (hash-table-ref ht :foo)))) (deftest "number keys work" (let ((ht (make-hash-table))) (hash-table-set! ht 0 "zero") (assert= "zero" (hash-table-ref ht 0)))) (deftest "delete removes key" (let ((ht (make-hash-table))) (hash-table-set! ht "x" 1) (hash-table-delete! ht "x") (assert= "gone" (hash-table-ref ht "x" "gone")))) (deftest "delete reduces size" (let ((ht (make-hash-table))) (hash-table-set! ht "a" 1) (hash-table-set! ht "b" 2) (hash-table-delete! ht "a") (assert= 1 (hash-table-size ht)))) (deftest "delete missing key is no-op" (let ((ht (make-hash-table))) (hash-table-delete! ht "absent") (assert= 0 (hash-table-size ht)))) (deftest "keys of empty table is empty" (assert (empty? (hash-table-keys (make-hash-table))))) (deftest "keys has correct count" (let ((ht (make-hash-table))) (hash-table-set! ht "a" 1) (hash-table-set! ht "b" 2) (assert= 2 (len (hash-table-keys ht))))) (deftest "values has correct count" (let ((ht (make-hash-table))) (hash-table-set! ht "a" 10) (hash-table-set! ht "b" 20) (assert= 2 (len (hash-table-values ht))))) (deftest "alist of empty table is empty" (assert (empty? (hash-table->alist (make-hash-table))))) (deftest "alist has correct length" (let ((ht (make-hash-table))) (hash-table-set! ht "x" 1) (hash-table-set! ht "y" 2) (assert= 2 (len (hash-table->alist ht))))) (deftest "for-each visits all entries" (let ((ht (make-hash-table)) (count 0)) (hash-table-set! ht "a" 1) (hash-table-set! ht "b" 2) (hash-table-set! ht "c" 3) (hash-table-for-each ht (fn (k v) (set! count (+ count 1)))) (assert= 3 count))) (deftest "for-each sums values" (let ((ht (make-hash-table)) (total 0)) (hash-table-set! ht "a" 10) (hash-table-set! ht "b" 20) (hash-table-set! ht "c" 30) (hash-table-for-each ht (fn (k v) (set! total (+ total v)))) (assert= 60 total))) (deftest "merge copies entries from src to dst" (let ((dst (make-hash-table)) (src (make-hash-table))) (hash-table-set! src "x" 1) (hash-table-set! src "y" 2) (hash-table-merge! dst src) (assert= 2 (hash-table-size dst)))) (deftest "merge overwrites existing keys in dst" (let ((dst (make-hash-table)) (src (make-hash-table))) (hash-table-set! dst "k" "old") (hash-table-set! src "k" "new") (hash-table-merge! dst src) (assert= "new" (hash-table-ref dst "k")))) (deftest "merge does not modify src" (let ((dst (make-hash-table)) (src (make-hash-table))) (hash-table-set! src "a" 1) (hash-table-merge! dst src) (assert= 1 (hash-table-size src)))) (deftest "type-of returns hash-table" (assert= "hash-table" (type-of (make-hash-table)))))