(define-library (sx harness-reactive)
  (export assert-signal-value assert-signal-has-subscribers assert-signal-no-subscribers assert-signal-subscriber-count simulate-signal-set! simulate-signal-swap! assert-computed-dep-count assert-computed-depends-on count-effect-runs make-test-signal assert-batch-coalesces)
  (begin

(define
  assert-signal-value
  :effects ()
  (fn
    ((sig :as any) expected)
    (let
      ((actual (deref sig)))
      (assert=
        actual
        expected
        (str "Expected signal value " expected ", got " actual)))))

(define
  assert-signal-has-subscribers
  :effects ()
  (fn
    ((sig :as any))
    (assert
      (> (len (signal-subscribers sig)) 0)
      "Expected signal to have subscribers")))

(define
  assert-signal-no-subscribers
  :effects ()
  (fn
    ((sig :as any))
    (assert
      (= (len (signal-subscribers sig)) 0)
      "Expected signal to have no subscribers")))

(define
  assert-signal-subscriber-count
  :effects ()
  (fn
    ((sig :as any) (n :as number))
    (let
      ((actual (len (signal-subscribers sig))))
      (assert= actual n (str "Expected " n " subscribers, got " actual)))))

(define
  simulate-signal-set!
  :effects (mutation)
  (fn ((sig :as any) value) (reset! sig value)))

(define
  simulate-signal-swap!
  :effects (mutation)
  (fn ((sig :as any) (f :as lambda)) (swap! sig f)))

(define
  assert-computed-dep-count
  :effects ()
  (fn
    ((sig :as any) (n :as number))
    (let
      ((actual (len (signal-deps sig))))
      (assert= actual n (str "Expected " n " deps, got " actual)))))

(define
  assert-computed-depends-on
  :effects ()
  (fn
    ((computed-sig :as any) (dep-sig :as any))
    (assert
      (contains? (signal-deps computed-sig) dep-sig)
      "Expected computed to depend on the given signal")))

(define
  count-effect-runs
  :effects (mutation)
  (fn
    ((thunk :as lambda))
    (let
      ((count (signal 0)))
      (effect (fn () (deref count)))
      (let
        ((run-count 0)
          (tracker
            (effect
              (fn () (set! run-count (+ run-count 1)) (cek-call thunk nil)))))
        run-count))))

(define
  make-test-signal
  :effects (mutation)
  (fn
    (initial-value)
    (let
      ((sig (signal initial-value)) (history (list)))
      (effect (fn () (append! history (deref sig))))
      {:signal sig :history history})))

(define
  assert-batch-coalesces
  :effects (mutation)
  (fn
    ((thunk :as lambda) (expected-notify-count :as number))
    (let
      ((notify-count 0) (sig (signal 0)))
      (effect (fn () (deref sig) (set! notify-count (+ notify-count 1))))
      (set! notify-count 0)
      (batch thunk)
      (assert=
        notify-count
        expected-notify-count
        (str
          "Expected "
          expected-notify-count
          " notifications, got "
          notify-count)))))


))

;; Re-export to global env
(import (sx harness-reactive))
