(ns tui.events-test "Unit tests for event constructors and key matching." (:require [clojure.test :refer [deftest testing is]] [tui.events :as ev])) ;; === Event Constructor Tests === (deftest quit-test (testing "quit returns quit event" (is (= {:type :quit} (ev/quit))))) (deftest delayed-event-test (testing "delayed-event creates delayed-event event" (is (= {:type :delayed-event :ms 1000 :event {:type :tick}} (ev/delayed-event 1000 {:type :tick})))) (testing "delayed-event with different ms values" (is (= 0 (:ms (ev/delayed-event 0 {:type :x})))) (is (= 5000 (:ms (ev/delayed-event 5000 {:type :x})))))) (deftest shell-test (testing "shell creates shell event with vector cmd" (is (= {:type :shell :cmd ["git" "status"] :event {:type :result}} (ev/shell ["git" "status"] {:type :result})))) (testing "shell preserves event data" (let [event {:type :git-result :file "foo.txt"}] (is (= event (:event (ev/shell ["git" "diff"] event))))))) (deftest batch-test (testing "batch creates batch event" (let [e1 {:type :a} e2 {:type :b} result (ev/batch e1 e2)] (is (= :batch (:type result))) (is (= [e1 e2] (:events result))))) (testing "batch filters nil events" (let [result (ev/batch nil {:type :a} nil {:type :b} nil)] (is (= [{:type :a} {:type :b}] (:events result))))) (testing "batch returns nil for all-nil events" (is (nil? (ev/batch nil nil nil)))) (testing "batch returns nil for no events" (is (nil? (ev/batch))))) (deftest sequential-test (testing "sequential creates sequential event" (let [e1 {:type :a} e2 {:type :b} result (ev/sequential e1 e2)] (is (= :sequential (:type result))) (is (= [e1 e2] (:events result))))) (testing "sequential filters nil events" (let [result (ev/sequential nil {:type :a} nil {:type :b} nil)] (is (= [{:type :a} {:type :b}] (:events result))))) (testing "sequential returns nil for all-nil events" (is (nil? (ev/sequential nil nil nil)))) (testing "sequential returns nil for no events" (is (nil? (ev/sequential))))) (deftest debounce-test (testing "debounce creates debounce event" (is (= {:type :debounce :id :search :ms 300 :event {:type :search-query}} (ev/debounce :search 300 {:type :search-query})))) (testing "debounce with different ids" (is (= :resize (:id (ev/debounce :resize 100 {:type :x})))) (is (= :input (:id (ev/debounce :input 50 {:type :x})))))) ;; === Key Matching Tests === (deftest key=-basic-test (testing "matches plain character" (is (ev/key= {:type :key :key \q} \q)) (is (ev/key= {:type :key :key \a} \a)) (is (ev/key= {:type :key :key \1} \1))) (testing "does not match different character" (is (not (ev/key= {:type :key :key \q} \a))) (is (not (ev/key= {:type :key :key \x} \y))))) (deftest key=-special-keys-test (testing "matches special keys" (is (ev/key= {:type :key :key :enter} :enter)) (is (ev/key= {:type :key :key :escape} :escape)) (is (ev/key= {:type :key :key :up} :up)) (is (ev/key= {:type :key :key :f1} :f1))) (testing "does not match wrong special keys" (is (not (ev/key= {:type :key :key :up} :down))) (is (not (ev/key= {:type :key :key :enter} :escape))))) (deftest key=-with-modifiers-test (testing "matches key with exact modifiers" (is (ev/key= {:type :key :key \c :modifiers #{:ctrl}} \c #{:ctrl})) (is (ev/key= {:type :key :key \z :modifiers #{:ctrl :shift}} \z #{:ctrl :shift})) (is (ev/key= {:type :key :key \a :modifiers #{:shift}} \a #{:shift}))) (testing "does not match with wrong modifiers" (is (not (ev/key= {:type :key :key \c :modifiers #{:ctrl}} \c #{:alt}))) (is (not (ev/key= {:type :key :key \c :modifiers #{:ctrl :shift}} \c #{:ctrl})))) (testing "does not match when modifiers present but not specified" (is (not (ev/key= {:type :key :key \c :modifiers #{:ctrl}} \c))) (is (not (ev/key= {:type :key :key \a :modifiers #{:shift}} \a)))) (testing "does not match when modifiers specified but not present" (is (not (ev/key= {:type :key :key \c} \c #{:ctrl}))))) (deftest key=-non-key-events-test (testing "returns false for non-key events" (is (not (ev/key= {:type :quit} \q))) (is (not (ev/key= {:type :tick} :enter))) (is (not (ev/key= nil \a))))) ;; === Composition Tests === (deftest composed-events-test (testing "can compose multiple event constructors" (let [result (ev/batch (ev/shell ["git" "status"] {:type :status}) (ev/delayed-event 1000 {:type :refresh}))] (is (= :batch (:type result))) (is (= 2 (count (:events result)))) (is (= :shell (:type (first (:events result))))) (is (= :delayed-event (:type (second (:events result))))))) (testing "can nest batch in sequential" (let [result (ev/sequential {:type :start} (ev/batch (ev/shell ["git" "add" "."] {:type :added}) (ev/shell ["git" "status"] {:type :status})))] (is (= :sequential (:type result))) (is (= :batch (:type (second (:events result))))))))