mirror of
https://github.com/unclebob/more-speech.git
synced 2024-09-30 18:40:47 +00:00
194 lines
7.0 KiB
Clojure
194 lines
7.0 KiB
Clojure
(ns more-speech.ui.header-window-spec
|
|
(:require [speclj.core :refer :all]
|
|
[more-speech.ui.text-window :refer [text-window-controls
|
|
setup-text-frame]]
|
|
[more-speech.ui.header-window :refer :all]
|
|
[more-speech.ui.widget :refer [widget setup-widget]]
|
|
[more-speech.ui.graphics :as g]
|
|
[more-speech.ui.config :as config]
|
|
[more-speech.ui.cursor :as cursor]
|
|
[clojure.spec.alpha :as s]))
|
|
|
|
(defrecord mock-graphics []
|
|
g/graphics
|
|
(line-height [_graphics]
|
|
20)
|
|
)
|
|
|
|
(defrecord mock-controls []
|
|
text-window-controls
|
|
(get-element-height [_c _state]
|
|
2))
|
|
|
|
(defrecord mock-widget []
|
|
widget)
|
|
|
|
(declare state frame
|
|
text-event nicknames)
|
|
|
|
(describe "article frame"
|
|
(with state {:application
|
|
{:graphics (->mock-graphics)}})
|
|
(with frame {:x 0 :y 0 :w 500 :h 500 :controls (->mock-controls)})
|
|
(context "setup"
|
|
(it "determines number of article headers fit in the frame"
|
|
(let [frame (setup-text-frame @state @frame)]
|
|
(should= 250 (:n-elements frame)))
|
|
)
|
|
)
|
|
|
|
(context "update"
|
|
(with text-event {:pubkey 42
|
|
:created-at 1000
|
|
:content "the content"
|
|
:references [1]
|
|
:indent 1})
|
|
(with nicknames {42 "name"})
|
|
|
|
(it "converts a text event to a header."
|
|
(should= {:id nil,
|
|
:group "",
|
|
:author "name",
|
|
:subject "?",
|
|
:time 1000,
|
|
:body "the content",
|
|
:thread-count 1,
|
|
:indent 1}
|
|
(event->header @text-event @nicknames)))
|
|
|
|
(it "creates buttons for threads"
|
|
(let [headers [{:id 1 :thread-count 1 :indent 0}
|
|
{:id 2 :thread-count 1 :indent 1}
|
|
{:id 3 :thread-count 1 :indent 0}
|
|
{:id 4 :thread-count 0 :indent 0}]
|
|
open-thread #{1}
|
|
state (assoc-in @state [:application :open-thread] open-thread)
|
|
button-creator (make-button-creator state @frame)
|
|
buttons (create-thread-buttons button-creator headers)
|
|
header-height (+ config/header-top-margin
|
|
config/header-bottom-margin
|
|
(* config/header-lines 20))]
|
|
(should= [1 3] (map :id buttons))
|
|
(should= [draw-minus draw-plus]
|
|
(map :draw buttons))
|
|
(should= [true true] (map #(satisfies? widget %) buttons))
|
|
(should=
|
|
[config/header-top-margin
|
|
(+ config/header-top-margin (* 2 header-height))]
|
|
(map :y buttons)))
|
|
)
|
|
(it "adds thread buttons to the frame"
|
|
(let [frame (add-thread-buttons {:path [:frame]} [{:id 111} {:id 222}])]
|
|
(should= 111 (get-in frame ["T1" :id]))
|
|
(should= 222 (get-in frame ["T2" :id]))
|
|
(should= [:frame "T1"] (get-in frame ["T1" :path]))
|
|
(should= [:frame "T2"] (get-in frame ["T2" :path]))))
|
|
|
|
(it "creates buttons for header selection"
|
|
(let [headers [{:id 1}
|
|
{:id 2}]
|
|
button-creator (make-button-creator @state @frame)
|
|
buttons (create-selection-buttons button-creator headers)
|
|
header-height (+ config/header-top-margin
|
|
config/header-bottom-margin
|
|
(* config/header-lines 20))]
|
|
(should= [1 2] (map :id buttons))
|
|
(should= [true true] (map #(satisfies? widget %) buttons))
|
|
(should=
|
|
[config/header-top-margin
|
|
(+ config/header-top-margin header-height)]
|
|
(map :y buttons))
|
|
(should= 20 (:x (first buttons)))
|
|
(should= 40 (:h (first buttons)))
|
|
(should= 480 (:w (first buttons)))))
|
|
|
|
(it "adds selection buttons to the frame"
|
|
(let [frame (add-selection-buttons {:path [:frame]} [{:id 111} {:id 222}])]
|
|
(should= 111 (get-in frame ["S1" :id]))
|
|
(should= 222 (get-in frame ["S2" :id]))
|
|
(should= [:frame "S1"] (get-in frame ["S1" :path]))
|
|
(should= [:frame "S2"] (get-in frame ["S2" :path]))))
|
|
)
|
|
|
|
(context "Formatting Headers"
|
|
(it "abbreviates authors"
|
|
(should= "short" (abbreviate-author "short"))
|
|
(should= "a very long autho..."
|
|
(abbreviate-author "a very long author name")))
|
|
|
|
|
|
(it "abbreviates bodies"
|
|
(should= "short" (abbreviate-body "short"))
|
|
(let [abbreviated (abbreviate-body (apply str (repeat 200 "*")))]
|
|
(should= "***" (.substring abbreviated 0 3))
|
|
(should= "..." (.substring abbreviated (- (count abbreviated) 3)))))
|
|
|
|
|
|
(let [article {:group "comp.lang.c++"
|
|
:author "Bob"
|
|
:time 1642683327
|
|
:subject "Subject"
|
|
:body "My Message to you."
|
|
:thread-count 15}]
|
|
(it "conforms to spec."
|
|
(should (s/valid? ::article article)))
|
|
|
|
(it "is properly formatted"
|
|
(let [markup (markup-header article)]
|
|
(should (vector? markup))
|
|
(should (every? cursor/valid-markup-token? markup))))))
|
|
|
|
(context "threading of events"
|
|
(it "does not thread if open events that have no references"
|
|
(let [event1 {:id 1}
|
|
event2 {:id 2}
|
|
event-map {1 event1
|
|
2 event2}
|
|
events [1 2]
|
|
open-events #{1 2}
|
|
threaded-events (thread-events events event-map open-events)]
|
|
(should= [1 2] (map :id threaded-events))
|
|
(should= [0 0] (map :indent threaded-events)))
|
|
)
|
|
|
|
(it "does not thread events that have references but are not open"
|
|
(let [event1 {:id 1 :references [3]}
|
|
event2 {:id 2}
|
|
event3 {:id 3}
|
|
event-map {1 event1
|
|
2 event2
|
|
3 event3}
|
|
events [1 2 3]
|
|
open-events #{}
|
|
threaded-events (thread-events events event-map open-events)]
|
|
(should= [1 2 3] (map :id threaded-events))
|
|
(should= [0 0 0] (map :indent threaded-events))))
|
|
|
|
(it "threads events that have references and are open"
|
|
(let [event1 {:id 1 :references [3]}
|
|
event2 {:id 2}
|
|
event3 {:id 3}
|
|
event-map {1 event1
|
|
2 event2
|
|
3 event3}
|
|
events [1 2 3]
|
|
open-events #{1}
|
|
threaded-events (thread-events events event-map open-events)]
|
|
(should= [1 3 2] (map :id threaded-events))
|
|
(should= [0 1 0] (map :indent threaded-events))))
|
|
|
|
(it "treats all articles threaded below an open article as open"
|
|
(let [event1 {:id 1 :references [2]}
|
|
event2 {:id 2 :references [3]}
|
|
event3 {:id 3}
|
|
event-map {1 event1
|
|
2 event2
|
|
3 event3}
|
|
events [1 2 3]
|
|
open-events #{1}
|
|
threaded-events (thread-events events event-map open-events)]
|
|
(should= [1 2 3] (map :id threaded-events))
|
|
(should= [0 1 2] (map :indent threaded-events))))
|
|
)
|
|
)
|