update examples. fix bugs
This commit is contained in:
+69
-105
@@ -4,6 +4,7 @@
|
||||
(:require [clojure.test :refer [deftest testing is are]]
|
||||
[clojure.string :as str]
|
||||
[tui.core :as tui]
|
||||
[tui.events :as ev]
|
||||
[tui.render :as render]
|
||||
[tui.input :as input]
|
||||
[tui.ansi :as ansi]))
|
||||
@@ -145,98 +146,65 @@
|
||||
;; =============================================================================
|
||||
|
||||
(deftest key-match-edge-cases-test
|
||||
(testing "empty string pattern"
|
||||
(is (not (input/key-match? [:key {:char \a}] ""))))
|
||||
(testing "nil event returns false"
|
||||
(is (not (ev/key= nil \q)))
|
||||
(is (not (ev/key= nil :enter))))
|
||||
|
||||
(testing "multi-char string pattern only matches first char"
|
||||
;; The current implementation only looks at first char
|
||||
(is (input/key-match? [:key {:char \q}] "quit")))
|
||||
(testing "non-key event returns false"
|
||||
(is (not (ev/key= {:type :timer-tick} \q)))
|
||||
(is (not (ev/key= {:type :http-result :status 200} :enter))))
|
||||
|
||||
(testing "nil message returns false"
|
||||
(is (not (input/key-match? nil "q")))
|
||||
(is (not (input/key-match? nil :enter))))
|
||||
|
||||
(testing "non-key message returns false"
|
||||
(is (not (input/key-match? [:tick 123] "q")))
|
||||
(is (not (input/key-match? [:http-success 200] :enter)))
|
||||
(is (not (input/key-match? "not a vector" "q"))))
|
||||
|
||||
(testing "unknown key message structure"
|
||||
(is (not (input/key-match? [:key {:unknown true}] "q")))
|
||||
(is (not (input/key-match? [:key {}] "q")))))
|
||||
|
||||
(deftest key-str-edge-cases-test
|
||||
(testing "nil message returns empty string"
|
||||
(is (= "" (input/key->str nil))))
|
||||
|
||||
(testing "non-key message returns string representation"
|
||||
;; Legacy format returns the second element as string
|
||||
(is (string? (input/key->str [:tick 123])))
|
||||
(is (string? (input/key->str [:custom :message]))))
|
||||
|
||||
(testing "key message with empty map"
|
||||
(is (= "" (input/key->str [:key {}]))))
|
||||
|
||||
(testing "ctrl and alt combined"
|
||||
;; This is an edge case - both modifiers
|
||||
(is (= "ctrl+alt+x" (input/key->str [:key {:ctrl true :alt true :char \x}])))))
|
||||
(testing "key event with missing key field"
|
||||
(is (not (ev/key= {:type :key} \q)))
|
||||
(is (not (ev/key= {:type :key :modifiers #{:ctrl}} \c #{:ctrl})))))
|
||||
|
||||
;; =============================================================================
|
||||
;; COMMAND EDGE CASES
|
||||
;; EVENT EDGE CASES
|
||||
;; =============================================================================
|
||||
|
||||
(deftest batch-edge-cases-test
|
||||
(testing "batch with all nils"
|
||||
(is (= [:batch] (tui/batch nil nil nil))))
|
||||
(is (nil? (ev/batch nil nil nil))))
|
||||
|
||||
(testing "batch with single command"
|
||||
(is (= [:batch tui/quit] (tui/batch tui/quit))))
|
||||
(testing "batch with single event"
|
||||
(let [event (ev/batch {:type :msg1})]
|
||||
(is (= :batch (:type event)))
|
||||
(is (= 1 (count (:events event))))))
|
||||
|
||||
(testing "batch with no arguments"
|
||||
(is (= [:batch] (tui/batch))))
|
||||
(is (nil? (ev/batch))))
|
||||
|
||||
(testing "batch with many commands"
|
||||
(let [cmd (tui/batch (tui/after 1 :t1) (tui/after 2 :t2) (tui/after 3 :t3) (tui/after 4 :t4) (tui/after 5 :t5))]
|
||||
(is (= 6 (count cmd))) ; :batch + 5 commands
|
||||
(is (= :batch (first cmd))))))
|
||||
(testing "batch with many events"
|
||||
(let [event (ev/batch {:type :t1} {:type :t2} {:type :t3} {:type :t4} {:type :t5})]
|
||||
(is (= 5 (count (:events event))))
|
||||
(is (= :batch (:type event))))))
|
||||
|
||||
(deftest sequentially-edge-cases-test
|
||||
(testing "sequentially with all nils"
|
||||
(is (= [:seq] (tui/sequentially nil nil nil))))
|
||||
(deftest sequential-edge-cases-test
|
||||
(testing "sequential with all nils"
|
||||
(is (nil? (ev/sequential nil nil nil))))
|
||||
|
||||
(testing "sequentially with single command"
|
||||
(is (= [:seq tui/quit] (tui/sequentially tui/quit))))
|
||||
(testing "sequential with single event"
|
||||
(let [event (ev/sequential {:type :msg1})]
|
||||
(is (= :sequential (:type event)))
|
||||
(is (= 1 (count (:events event))))))
|
||||
|
||||
(testing "sequentially with no arguments"
|
||||
(is (= [:seq] (tui/sequentially)))))
|
||||
(testing "sequential with no arguments"
|
||||
(is (nil? (ev/sequential)))))
|
||||
|
||||
(deftest after-edge-cases-test
|
||||
(testing "after with zero delay"
|
||||
(let [cmd (tui/after 0 :immediate)]
|
||||
(is (fn? cmd))
|
||||
;; Zero delay executes immediately
|
||||
(is (= :immediate (cmd)))))
|
||||
(deftest delayed-event-edge-cases-test
|
||||
(testing "delayed-event with zero delay"
|
||||
(let [event (ev/delayed-event 0 {:type :immediate})]
|
||||
(is (= :delayed-event (:type event)))
|
||||
(is (= 0 (:ms event)))))
|
||||
|
||||
(testing "after with various delays creates function"
|
||||
;; Don't invoke - just verify the function is created correctly
|
||||
(is (fn? (tui/after 1 :t1)))
|
||||
(is (fn? (tui/after 1000 :t2)))
|
||||
(is (fn? (tui/after 999999999 :t3))))
|
||||
(testing "delayed-event with various delays"
|
||||
(is (= 1 (:ms (ev/delayed-event 1 {:type :t1}))))
|
||||
(is (= 1000 (:ms (ev/delayed-event 1000 {:type :t2}))))
|
||||
(is (= 999999999 (:ms (ev/delayed-event 999999999 {:type :t3})))))
|
||||
|
||||
(testing "after with complex message"
|
||||
(let [cmd (tui/after 0 [:tick {:id 1 :data [1 2 3]}])]
|
||||
(is (= [:tick {:id 1 :data [1 2 3]}] (cmd))))))
|
||||
|
||||
(deftest send-msg-edge-cases-test
|
||||
(testing "send-msg with nil"
|
||||
(let [cmd (tui/send-msg nil)]
|
||||
(is (fn? cmd))
|
||||
(is (nil? (cmd)))))
|
||||
|
||||
(testing "send-msg with complex message"
|
||||
(let [msg {:type :complex :data [1 2 3] :nested {:a :b}}
|
||||
cmd (tui/send-msg msg)]
|
||||
(is (= msg (cmd))))))
|
||||
(testing "delayed-event with complex message"
|
||||
(let [event (ev/delayed-event 0 {:type :tick :id 1 :data [1 2 3]})]
|
||||
(is (= {:type :tick :id 1 :data [1 2 3]} (:event event))))))
|
||||
|
||||
;; =============================================================================
|
||||
;; ANSI EDGE CASES
|
||||
@@ -319,27 +287,24 @@
|
||||
;; UPDATE FUNCTION EDGE CASES
|
||||
;; =============================================================================
|
||||
|
||||
(deftest update-with-unknown-messages-test
|
||||
(testing "update function handles unknown messages gracefully"
|
||||
(let [update-fn (fn [model msg]
|
||||
(deftest update-with-unknown-events-test
|
||||
(testing "update function handles unknown events gracefully"
|
||||
(let [update-fn (fn [{:keys [model event]}]
|
||||
(cond
|
||||
(tui/key= msg "q") [model tui/quit]
|
||||
:else [model nil]))]
|
||||
(ev/key= event \q) {:model model :events [(ev/quit)]}
|
||||
:else {:model model}))]
|
||||
|
||||
;; Unknown key
|
||||
(let [[m cmd] (update-fn {:n 0} [:key {:char \x}])]
|
||||
(is (= {:n 0} m))
|
||||
(is (nil? cmd)))
|
||||
(let [{:keys [model]} (update-fn {:model {:n 0} :event {:type :key :key \x}})]
|
||||
(is (= {:n 0} model)))
|
||||
|
||||
;; Unknown message type
|
||||
(let [[m cmd] (update-fn {:n 0} [:unknown :message])]
|
||||
(is (= {:n 0} m))
|
||||
(is (nil? cmd)))
|
||||
;; Unknown event type
|
||||
(let [{:keys [model]} (update-fn {:model {:n 0} :event {:type :unknown :message "test"}})]
|
||||
(is (= {:n 0} model)))
|
||||
|
||||
;; Empty message
|
||||
(let [[m cmd] (update-fn {:n 0} [])]
|
||||
(is (= {:n 0} m))
|
||||
(is (nil? cmd))))))
|
||||
;; Event with no type
|
||||
(let [{:keys [model]} (update-fn {:model {:n 0} :event {}})]
|
||||
(is (= {:n 0} model))))))
|
||||
|
||||
(deftest model-with-complex-state-test
|
||||
(testing "model with nested data structures"
|
||||
@@ -348,23 +313,22 @@
|
||||
:nested {:deep {:value 42}}
|
||||
:selected #{}
|
||||
:history []}
|
||||
update-fn (fn [model msg]
|
||||
(if (tui/key= msg :up)
|
||||
[(-> model
|
||||
(update :count inc)
|
||||
(update :history conj (:count model)))
|
||||
nil]
|
||||
[model nil]))]
|
||||
update-fn (fn [{:keys [model event]}]
|
||||
(if (ev/key= event :up)
|
||||
{:model (-> model
|
||||
(update :count inc)
|
||||
(update :history conj (:count model)))}
|
||||
{:model model}))]
|
||||
|
||||
(let [[m1 _] (update-fn complex-model [:key :up])
|
||||
[m2 _] (update-fn m1 [:key :up])]
|
||||
(is (= 1 (:count m1)))
|
||||
(is (= [0] (:history m1)))
|
||||
(is (= 2 (:count m2)))
|
||||
(is (= [0 1] (:history m2)))
|
||||
(let [r1 (update-fn {:model complex-model :event {:type :key :key :up}})
|
||||
r2 (update-fn {:model (:model r1) :event {:type :key :key :up}})]
|
||||
(is (= 1 (:count (:model r1))))
|
||||
(is (= [0] (:history (:model r1))))
|
||||
(is (= 2 (:count (:model r2))))
|
||||
(is (= [0 1] (:history (:model r2))))
|
||||
;; Other fields unchanged
|
||||
(is (= ["a" "b" "c"] (:items m2)))
|
||||
(is (= 42 (get-in m2 [:nested :deep :value])))))))
|
||||
(is (= ["a" "b" "c"] (:items (:model r2))))
|
||||
(is (= 42 (get-in (:model r2) [:nested :deep :value])))))))
|
||||
|
||||
;; =============================================================================
|
||||
;; VIEW FUNCTION EDGE CASES
|
||||
|
||||
Reference in New Issue
Block a user