(import :std/test
        :std/iter
        :gerbil/runtime/table)
(export raw-table-test gc-table-test)

(def raw-table-test
  (test-suite "raw-table"
    (test-case "basic ops"
      (let (h (make-raw-table #f eq-hash eq?))
        (for ((k '(a b c d e f g))
              (v (in-naturals)))
          (raw-table-set! h k v)
          (check (raw-table-ref h k #f) => v))
        (for ((k '(a b c d e f g))
              (v (in-naturals)))
          (check (raw-table-ref h k #f) => v))
        (for (k '(a b c d e f g))
          (raw-table-delete! h k)
          (check (raw-table-ref h k #f) => #f))))
    (test-case "rehashing"
      (let (h (make-raw-table #f eq-hash eq?))
        (for (x (iota 200))
          (raw-table-set! h x x))
        (for (x (iota 200))
          (check (raw-table-ref h x #f) => x))))
    (test-case "put/remove 1"
      (let (h (make-raw-table #f eq-hash eq?))
        (for (x (iota 200))
          (raw-table-set! h x x))
        (for (x (iota 200))
          (check (raw-table-ref h x #f) => x))
        (for (x (iota 100))
          (raw-table-delete! h x))
        (for (x (iota 100 100))
          (check (raw-table-ref h x #f) => x))
        (for (x (iota 100))
          (raw-table-set! h x x))
        (for (x (iota 200))
          (check (raw-table-ref h x #f) => x))))
    (test-case "put/remove 2"
      (let (h (make-raw-table #f eq-hash eq?))
        (for (x (iota 200))
          (raw-table-set! h x x)
          (raw-table-delete! h x))
        (for (x (iota 200))
          (raw-table-set! h x x))
        (for (x (iota 200))
          (check (raw-table-ref h x #f) => x))))))

(def gc-table-test
  (test-suite "gc-table"
    (test-case "basic ops"
      (let (h (make-gc-table #f))
        (for ((k '(a b c d e f g))
              (v (in-naturals)))
          (gc-table-set! h k v)
          (check (gc-table-ref h k #f) => v))
        (for ((k '(a b c d e f g))
              (v (in-naturals)))
          (check (gc-table-ref h k #f) => v))
        (for (k '(a b c d e f g))
          (gc-table-delete! h k)
          (check (gc-table-ref h k #f) => #f))))
    (test-case "rehashing"
      (let (h (make-gc-table #f))
        (for (x (iota 200))
          (gc-table-set! h x x))
        (for (x (iota 200))
          (check (gc-table-ref h x #f) => x))))
    (test-case "put/remove 1"
      (let (h (make-gc-table #f))
        (for (x (iota 200))
          (gc-table-set! h x x))
        (for (x (iota 200))
          (check (gc-table-ref h x #f) => x))
        (for (x (iota 100))
          (gc-table-delete! h x))
        (for (x (iota 100 100))
          (check (gc-table-ref h x #f) => x))
        (for (x (iota 100))
          (gc-table-set! h x x))
        (for (x (iota 200))
          (check (gc-table-ref h x #f) => x))))
    (test-case "put/remove 2"
      (let (h (make-gc-table #f))
        (for (x (iota 200))
          (gc-table-set! h x x)
          (gc-table-delete! h x))
        (for (x (iota 200))
          (gc-table-set! h x x))
        (for (x (iota 200))
          (check (gc-table-ref h x #f) => x))))))
