refactor
This commit is contained in:
+146
-30
@@ -4,16 +4,17 @@
|
||||
(:require [clojure.test :refer [deftest testing is]]
|
||||
[clojure.core.async :as async :refer [chan >!! <!! timeout alt!! close!]]
|
||||
[tui.core :as tui]
|
||||
[tui.events :as ev]
|
||||
[tui.render :as render]))
|
||||
|
||||
;; === Command Tests ===
|
||||
;; === Legacy Command Tests (Backward Compatibility) ===
|
||||
|
||||
(deftest quit-command-test
|
||||
(testing "quit command is correct vector"
|
||||
(testing "quit command is correct vector (legacy)"
|
||||
(is (= [:quit] tui/quit))))
|
||||
|
||||
(deftest after-command-test
|
||||
(testing "after creates a function command"
|
||||
(testing "after creates a function command (legacy)"
|
||||
(let [cmd (tui/after 0 :my-tick)]
|
||||
(is (fn? cmd))
|
||||
(is (= :my-tick (cmd)))))
|
||||
@@ -23,16 +24,15 @@
|
||||
(is (= :simple-msg ((tui/after 0 :simple-msg)))))
|
||||
|
||||
(testing "after with non-zero delay creates function"
|
||||
;; Don't invoke - these would sleep
|
||||
(is (fn? (tui/after 100 :tick)))
|
||||
(is (fn? (tui/after 1000 :tick)))))
|
||||
|
||||
(deftest batch-command-test
|
||||
(testing "batch combines commands"
|
||||
(testing "batch combines commands (legacy)"
|
||||
(let [cmd (tui/batch (tui/send-msg :msg1) tui/quit)]
|
||||
(is (vector? cmd))
|
||||
(is (= :batch (first cmd)))
|
||||
(is (= 3 (count cmd))) ; [:batch fn [:quit]]
|
||||
(is (= 3 (count cmd)))
|
||||
(is (= [:quit] (last cmd)))))
|
||||
|
||||
(testing "batch filters nil commands"
|
||||
@@ -41,7 +41,7 @@
|
||||
(is (= 2 (count cmd))))))
|
||||
|
||||
(deftest sequentially-command-test
|
||||
(testing "sequentially creates seq command"
|
||||
(testing "sequentially creates seq command (legacy)"
|
||||
(let [cmd (tui/sequentially (tui/send-msg :msg1) tui/quit)]
|
||||
(is (vector? cmd))
|
||||
(is (= :seq (first cmd)))
|
||||
@@ -54,24 +54,35 @@
|
||||
(is (= 2 (count cmd))))))
|
||||
|
||||
(deftest send-msg-command-test
|
||||
(testing "send-msg creates function that returns message"
|
||||
(testing "send-msg creates function that returns message (legacy)"
|
||||
(let [cmd (tui/send-msg {:type :custom :data 42})]
|
||||
(is (fn? cmd))
|
||||
(is (= {:type :custom :data 42} (cmd))))))
|
||||
|
||||
;; === Key Matching Tests ===
|
||||
;; === Legacy Key Matching Tests ===
|
||||
|
||||
(deftest key=-test
|
||||
(testing "key= delegates to input/key-match?"
|
||||
(deftest key=-legacy-test
|
||||
(testing "key= works with legacy format"
|
||||
(is (tui/key= [:key {:char \q}] "q"))
|
||||
(is (tui/key= [:key :enter] :enter))
|
||||
(is (tui/key= [:key {:ctrl true :char \c}] [:ctrl \c]))
|
||||
(is (not (tui/key= [:key {:char \a}] "b")))))
|
||||
|
||||
(deftest key=-new-format-test
|
||||
(testing "key= works with new format"
|
||||
(is (tui/key= {:type :key :key \q} "q"))
|
||||
(is (tui/key= {:type :key :key :enter} :enter))
|
||||
(is (tui/key= {:type :key :key \c :modifiers #{:ctrl}} [:ctrl \c]))
|
||||
(is (not (tui/key= {:type :key :key \a} "b")))))
|
||||
|
||||
(deftest key-str-test
|
||||
(testing "key-str converts key to string"
|
||||
(testing "key-str converts key to string (legacy)"
|
||||
(is (= "q" (tui/key-str [:key {:char \q}])))
|
||||
(is (= "enter" (tui/key-str [:key :enter])))))
|
||||
(is (= "enter" (tui/key-str [:key :enter]))))
|
||||
|
||||
(testing "key-str converts key to string (new format)"
|
||||
(is (= "q" (tui/key-str {:type :key :key \q})))
|
||||
(is (= "enter" (tui/key-str {:type :key :key :enter})))))
|
||||
|
||||
;; === Full Pipeline Tests ===
|
||||
|
||||
@@ -87,8 +98,36 @@
|
||||
(is (clojure.string/includes? rendered "Counter"))
|
||||
(is (clojure.string/includes? rendered "Count: 5")))))
|
||||
|
||||
(deftest update-function-contract-test
|
||||
(testing "update function returns [model cmd] tuple"
|
||||
;; === New API Update Function Tests ===
|
||||
|
||||
(deftest new-update-function-contract-test
|
||||
(testing "new update function returns {:model ... :events ...}"
|
||||
(let [update-fn (fn [{:keys [model event]}]
|
||||
(cond
|
||||
(ev/key= event \q) {:model model :events [(ev/quit)]}
|
||||
(ev/key= event :up) {:model (update model :n inc)}
|
||||
:else {:model model}))
|
||||
model {:n 0}]
|
||||
|
||||
;; Test quit returns event
|
||||
(let [{:keys [model events]} (update-fn {:model model :event {:type :key :key \q}})]
|
||||
(is (= {:n 0} model))
|
||||
(is (= [{:type :quit}] events)))
|
||||
|
||||
;; Test up returns updated model
|
||||
(let [{:keys [model events]} (update-fn {:model model :event {:type :key :key :up}})]
|
||||
(is (= {:n 1} model))
|
||||
(is (nil? events)))
|
||||
|
||||
;; Test unknown key returns model unchanged
|
||||
(let [{:keys [model events]} (update-fn {:model model :event {:type :key :key \x}})]
|
||||
(is (= {:n 0} model))
|
||||
(is (nil? events))))))
|
||||
|
||||
;; === Legacy Update Function Tests ===
|
||||
|
||||
(deftest legacy-update-function-contract-test
|
||||
(testing "legacy update function returns [model cmd] tuple"
|
||||
(let [update-fn (fn [model msg]
|
||||
(cond
|
||||
(tui/key= msg "q") [model tui/quit]
|
||||
@@ -111,20 +150,87 @@
|
||||
(is (= model new-model))
|
||||
(is (nil? cmd))))))
|
||||
|
||||
;; === Command Execution Tests ===
|
||||
;; These test the internal command execution logic
|
||||
;; === Event Execution Tests ===
|
||||
|
||||
(deftest execute-quit-command-test
|
||||
(testing "quit command puts :quit on channel"
|
||||
(deftest execute-quit-event-test
|
||||
(testing "quit event puts {:type :quit} on channel"
|
||||
(let [msg-chan (chan 1)]
|
||||
(#'tui/execute-event! {:type :quit} msg-chan)
|
||||
(let [result (alt!!
|
||||
msg-chan ([v] v)
|
||||
(timeout 100) :timeout)]
|
||||
(is (= {:type :quit} result)))
|
||||
(close! msg-chan))))
|
||||
|
||||
(deftest execute-delay-event-test
|
||||
(testing "delay event sends message after delay"
|
||||
(let [msg-chan (chan 1)
|
||||
event (ev/delay 50 {:type :delayed-msg})]
|
||||
(#'tui/execute-event! event msg-chan)
|
||||
;; Should not receive immediately
|
||||
(let [immediate (alt!!
|
||||
msg-chan ([v] v)
|
||||
(timeout 10) :timeout)]
|
||||
(is (= :timeout immediate)))
|
||||
;; Should receive after delay
|
||||
(let [delayed (alt!!
|
||||
msg-chan ([v] v)
|
||||
(timeout 200) :timeout)]
|
||||
(is (= {:type :delayed-msg} delayed)))
|
||||
(close! msg-chan))))
|
||||
|
||||
(deftest execute-batch-event-test
|
||||
(testing "batch executes multiple events"
|
||||
(let [msg-chan (chan 10)]
|
||||
(#'tui/execute-event! {:type :batch
|
||||
:events [{:type :msg1}
|
||||
{:type :msg2}]}
|
||||
msg-chan)
|
||||
;; Give time for dispatch
|
||||
(Thread/sleep 50)
|
||||
(let [results (loop [msgs []]
|
||||
(let [msg (alt!!
|
||||
msg-chan ([v] v)
|
||||
(timeout 10) nil)]
|
||||
(if msg
|
||||
(recur (conj msgs msg))
|
||||
msgs)))]
|
||||
(is (= #{{:type :msg1} {:type :msg2}} (set results))))
|
||||
(close! msg-chan))))
|
||||
|
||||
(deftest execute-unknown-event-test
|
||||
(testing "unknown event type is dispatched to update"
|
||||
(let [msg-chan (chan 1)]
|
||||
(#'tui/execute-event! {:type :custom-app-event :data 42} msg-chan)
|
||||
(let [result (alt!!
|
||||
msg-chan ([v] v)
|
||||
(timeout 100) :timeout)]
|
||||
(is (= {:type :custom-app-event :data 42} result)))
|
||||
(close! msg-chan))))
|
||||
|
||||
(deftest execute-nil-event-test
|
||||
(testing "nil event does nothing"
|
||||
(let [msg-chan (chan 1)]
|
||||
(#'tui/execute-event! nil msg-chan)
|
||||
(let [result (alt!!
|
||||
msg-chan ([v] v)
|
||||
(timeout 50) :timeout)]
|
||||
(is (= :timeout result)))
|
||||
(close! msg-chan))))
|
||||
|
||||
;; === Legacy Command Execution Tests ===
|
||||
|
||||
(deftest execute-quit-command-legacy-test
|
||||
(testing "quit command puts {:type :quit} on channel"
|
||||
(let [msg-chan (chan 1)]
|
||||
(#'tui/execute-cmd! [:quit] msg-chan)
|
||||
(let [result (alt!!
|
||||
msg-chan ([v] v)
|
||||
(timeout 100) :timeout)]
|
||||
(is (= [:quit] result)))
|
||||
(is (= {:type :quit} result)))
|
||||
(close! msg-chan))))
|
||||
|
||||
(deftest execute-after-command-test
|
||||
(deftest execute-after-command-legacy-test
|
||||
(testing "after command sends message after delay"
|
||||
(let [msg-chan (chan 1)
|
||||
cmd (tui/after 50 :delayed-msg)]
|
||||
@@ -141,7 +247,7 @@
|
||||
(is (= :delayed-msg delayed)))
|
||||
(close! msg-chan))))
|
||||
|
||||
(deftest execute-function-command-test
|
||||
(deftest execute-function-command-legacy-test
|
||||
(testing "function command executes and sends result"
|
||||
(let [msg-chan (chan 1)
|
||||
cmd (fn [] {:custom :message})]
|
||||
@@ -152,7 +258,7 @@
|
||||
(is (= {:custom :message} result)))
|
||||
(close! msg-chan))))
|
||||
|
||||
(deftest execute-batch-command-test
|
||||
(deftest execute-batch-command-legacy-test
|
||||
(testing "batch executes multiple commands"
|
||||
(let [msg-chan (chan 10)]
|
||||
(#'tui/execute-cmd! [:batch
|
||||
@@ -171,7 +277,7 @@
|
||||
(is (= #{:msg1 :msg2} (set results))))
|
||||
(close! msg-chan))))
|
||||
|
||||
(deftest execute-nil-command-test
|
||||
(deftest execute-nil-command-legacy-test
|
||||
(testing "nil command does nothing"
|
||||
(let [msg-chan (chan 1)]
|
||||
(#'tui/execute-cmd! nil msg-chan)
|
||||
@@ -184,12 +290,22 @@
|
||||
;; === Defapp Macro Tests ===
|
||||
|
||||
(deftest defapp-macro-test
|
||||
(testing "defapp creates app map"
|
||||
(tui/defapp test-app
|
||||
(testing "defapp creates app map (legacy)"
|
||||
(tui/defapp test-app-legacy
|
||||
:init {:count 0}
|
||||
:update (fn [m msg] [m nil])
|
||||
:view (fn [m] [:text "test"]))
|
||||
(is (map? test-app))
|
||||
(is (= {:count 0} (:init test-app)))
|
||||
(is (fn? (:update test-app)))
|
||||
(is (fn? (:view test-app)))))
|
||||
(is (map? test-app-legacy))
|
||||
(is (= {:count 0} (:init test-app-legacy)))
|
||||
(is (fn? (:update test-app-legacy)))
|
||||
(is (fn? (:view test-app-legacy))))
|
||||
|
||||
(testing "defapp creates app map (new)"
|
||||
(tui/defapp test-app-new
|
||||
:init {:count 0}
|
||||
:update (fn [{:keys [model event]}] {:model model})
|
||||
:view (fn [m size] [:text "test"]))
|
||||
(is (map? test-app-new))
|
||||
(is (= {:count 0} (:init test-app-new)))
|
||||
(is (fn? (:update test-app-new)))
|
||||
(is (fn? (:view test-app-new)))))
|
||||
|
||||
Reference in New Issue
Block a user