Unit tests for input model

This commit is contained in:
alwx 2017-07-25 23:29:23 +02:00 committed by Roman Volosovskyi
parent fc59f8d7f1
commit abafa3308a
2 changed files with 192 additions and 49 deletions

View File

@ -22,12 +22,9 @@
(aget emoji-map "char") (aget emoji-map "char")
original))))) original)))))
(defn text-ends-with-space? (defn text-ends-with-space? [text]
"Returns true if the last symbol of `text` is space" (and (not (nil? text))
[text] (str/ends-with? text const/spacing-char)))
(when text
(= (str/last-index-of text const/spacing-char)
(dec (count text)))))
(defn starts-as-command? (defn starts-as-command?
"Returns true if `text` may be treated as a command. "Returns true if `text` may be treated as a command.
@ -50,12 +47,13 @@
{:keys [contacts requests]} (get-in db [:chats chat-id])] {:keys [contacts requests]} (get-in db [:chats chat-id])]
(->> contacts (->> contacts
(map (fn [{:keys [identity]}] (map (fn [{:keys [identity]}]
(let [{:keys [commands responses]} (get-in db [:contacts/contacts identity])] (let [{:keys [commands responses]} (get-in db [:contacts/contacts identity])]
(let [commands' (mapv (fn [[k v]] [k [v :any]]) (merge global-commands commands)) (let [commands' (mapv (fn [[k v]] [k [v :any]]) (merge global-commands commands))
responses' (mapv (fn [{:keys [message-id type]}] responses' (mapv (fn [{:keys [message-id type]}]
[type [(get responses type) message-id]]) (when-let [response (get responses type)]
requests)] [type [response message-id]]))
(into commands' responses'))))) requests)]
(into commands' responses')))))
(reduce (fn [m cur] (into (or m {}) cur))) (reduce (fn [m cur] (into (or m {}) cur)))
(into {})))) (into {}))))
@ -71,30 +69,31 @@
All the complex logic inside this function aims to support wrapped arguments." All the complex logic inside this function aims to support wrapped arguments."
[command-text] [command-text]
(let [space? (text-ends-with-space? command-text) (when command-text
command-text (if space? (let [space? (text-ends-with-space? command-text)
(str command-text ".") command-text (if space?
command-text) (str command-text ".")
command-text-normalized (if command-text command-text)
(str/replace (str/trim command-text) #" +" " ") command-text-normalized (if command-text
command-text) (str/replace (str/trim command-text) #" +" " ")
splitted (cond-> (str/split command-text-normalized const/spacing-char) command-text)
space? (drop-last))] splitted (cond-> (str/split command-text-normalized const/spacing-char)
(->> splitted space? (drop-last))]
(reduce (fn [[list command-started?] arg] (->> splitted
(let [quotes-count (count (filter #(= % const/arg-wrapping-char) arg)) (reduce (fn [[list command-started?] arg]
has-quote? (and (= quotes-count 1) (let [quotes-count (count (filter #(= % const/arg-wrapping-char) arg))
(str/index-of arg const/arg-wrapping-char)) has-quote? (and (= quotes-count 1)
arg (str/replace arg (re-pattern const/arg-wrapping-char) "") (str/index-of arg const/arg-wrapping-char))
new-list (if command-started? arg (str/replace arg (re-pattern const/arg-wrapping-char) "")
(let [index (dec (count list))] new-list (if command-started?
(update list index str const/spacing-char arg)) (let [index (dec (count list))]
(conj list arg)) (update list index str const/spacing-char arg))
command-continues? (or (and command-started? (not has-quote?)) (conj list arg))
(and (not command-started?) has-quote?))] command-continues? (or (and command-started? (not has-quote?))
[new-list command-continues?])) (and (not command-started?) has-quote?))]
[[] false]) [new-list command-continues?]))
(first)))) [[] false])
(first)))))
(defn join-command-args [args] (defn join-command-args [args]
"Transforms a list of args to a string. The opposite of `split-command-args`. "Transforms a list of args to a string. The opposite of `split-command-args`.
@ -108,13 +107,14 @@
Input: ['/send' 'Complex name with space in between' '1.0'] Input: ['/send' 'Complex name with space in between' '1.0']
Output: '/send \"Complex name with space in between\" 1.0'" Output: '/send \"Complex name with space in between\" 1.0'"
(->> args (when args
(map (fn [arg] (->> args
(let [arg (str/replace arg (re-pattern const/arg-wrapping-char) "")] (map (fn [arg]
(if (not (str/index-of arg const/spacing-char)) (let [arg (str/replace arg (re-pattern const/arg-wrapping-char) "")]
arg (if (not (str/index-of arg const/spacing-char))
(str const/arg-wrapping-char arg const/arg-wrapping-char))))) arg
(str/join const/spacing-char))) (str const/arg-wrapping-char arg const/arg-wrapping-char)))))
(str/join const/spacing-char))))
(defn selected-chat-command (defn selected-chat-command
"Returns a map containing `:command`, `:metadata` and `:args` keys. "Returns a map containing `:command`, `:metadata` and `:args` keys.
@ -154,7 +154,7 @@
(defn current-chat-argument-position (defn current-chat-argument-position
"Returns the position of current argument. It's just an integer number from -1 to infinity. "Returns the position of current argument. It's just an integer number from -1 to infinity.
-1 (`*no-argument-error*`) means error. It can happen if there is no selected command or selection." -1 (`*no-argument-error*`) means error. It can happen if there is no selected command or selection."
[{:keys [args] :as command} input-text selection seq-arguments] [command input-text selection seq-arguments]
(if command (if command
(if (get-in command [:command :sequential-params]) (if (get-in command [:command :sequential-params])
(count seq-arguments) (count seq-arguments)
@ -226,6 +226,7 @@
(->> args (->> args
(map-indexed (fn [i value] (map-indexed (fn [i value]
[(keyword (get-in params [i :name])) value])) [(keyword (get-in params [i :name])) value]))
(remove #(nil? (first %)))
(into {})))) (into {}))))
(defn command-dependent-context-params (defn command-dependent-context-params

View File

@ -1,8 +1,150 @@
(ns status-im.test.chat.models.input (ns status-im.test.chat.models.input
(:require [cljs.test :refer-macros [deftest is]] (:require [cljs.test :refer-macros [deftest is]]
[status-im.chat.models.input :as in])) [status-im.chat.models.input :as input]))
(deftest test-split-command-args (def fake-db
(is (= [""] (in/split-command-args nil))) {:global-commands {:command1 {:name "global-command1"}}
(is (= ["@browse" "google.com"] (in/split-command-args "@browse google.com"))) :chats {"test1" {:contacts [{:identity "0x1"}]
(is (= ["@browse" "google.com"] (in/split-command-args " @browse google.com ")))) :requests nil
:seq-arguments ["arg1" "arg2"]}
"test2" {:contacts [{:identity "0x1"}
{:identity "0x2"}]
:requests [{:message-id "id1" :type :request1}]}
"test3" {:contacts [{:identity "0x1"}]
:requests [{:message-id "id1" :type :request1}]}
"test4" {:contacts [{:identity "0x1"}
{:identity "0x2"}]
:requests [{:message-id "id2" :type :request2}]
:input-metadata {:meta-k "meta-v"}}}
:contacts/contacts {"0x1" {:commands {:command2 {:name "command2"}}
:responses nil}
"0x2" {:commands {:command3 {:name "command3"}}
:responses {:request1 {:name "request1"}}}}})
(deftest text->emoji
(is (nil? (input/text->emoji nil)))
(is (= "" (input/text->emoji "")))
(is (= "test" (input/text->emoji "test")))
(is (= "word1 \uD83D\uDC4D word2" (input/text->emoji "word1 :+1: word2"))))
(deftest starts-as-command?
(is (false? (input/starts-as-command? nil)))
(is (false? (input/text-ends-with-space? "")))
(is (false? (input/text-ends-with-space? "word1 word2 word3")))
(is (true? (input/text-ends-with-space? "word1 word2 "))))
(deftest possible-chat-actions
(is (= (input/possible-chat-actions fake-db "non-existent-chat") {}))
(is (= (input/possible-chat-actions fake-db "test1")
{:command1 [{:name "global-command1"} :any]
:command2 [{:name "command2"} :any]}))
(is (= (input/possible-chat-actions fake-db "test1")
{:command1 [{:name "global-command1"} :any]
:command2 [{:name "command2"} :any]}))
(is (= (input/possible-chat-actions fake-db "test2")
{:command1 [{:name "global-command1"} :any]
:command2 [{:name "command2"} :any]
:command3 [{:name "command3"} :any]
:request1 [{:name "request1"} "id1"]}))
(is (= (input/possible-chat-actions fake-db "test3")
{:command1 [{:name "global-command1"} :any]
:command2 [{:name "command2"} :any]}))
(is (= (input/possible-chat-actions fake-db "test4")
{:command1 [{:name "global-command1"} :any]
:command2 [{:name "command2"} :any]
:command3 [{:name "command3"} :any]})))
(deftest split-command-args
(is (nil? (input/split-command-args nil)))
(is (= [""] (input/split-command-args "")))
(is (= ["@browse" "google.com"] (input/split-command-args "@browse google.com")))
(is (= ["@browse" "google.com"] (input/split-command-args " @browse google.com ")))
(is (= ["/send" "1.0" "John Doe"] (input/split-command-args "/send 1.0 \"John Doe\"")))
(is (= ["/send" "1.0" "John Doe"] (input/split-command-args "/send 1.0 \"John Doe\" "))))
(deftest join-command-args
(is (nil? (input/join-command-args nil)))
(is (= "" (input/join-command-args [""])))
(is (= "/send 1.0 \"John Doe\"" (input/join-command-args ["/send" "1.0" "John Doe"]))))
(deftest selected-chat-command
(is (= (input/selected-chat-command fake-db "test1" "/global-command1")
{:command {:name "global-command1"} :metadata nil :args ["arg1" "arg2"]}))
(is (= (input/selected-chat-command fake-db "test2" "/global-command1")
{:command {:name "global-command1"} :metadata nil :args []}))
(is (nil? (input/selected-chat-command fake-db "test1" "/command3")))
(is (= (input/selected-chat-command fake-db "test1" "/command2")
{:command {:name "command2"} :metadata nil :args ["arg1" "arg2"]}))
(is (= (input/selected-chat-command fake-db "test2" "/request1 arg1")
{:command {:name "request1"} :metadata {:to-message-id "id1"} :args ["arg1"]}))
(is (= (input/selected-chat-command fake-db "test4" "/command2 arg1")
{:command {:name "command2"} :metadata {:meta-k "meta-v"} :args ["arg1"]})))
(deftest current-chat-argument-position
(is (= (input/current-chat-argument-position
{:name "command1"} "/command1 arg1 arg2 " 0 nil) -1))
(is (= (input/current-chat-argument-position
{:name "command1"} "/command1 argument1 arg2 " 9 nil) -1))
(is (= (input/current-chat-argument-position
{:name "command1"} "/command1 argument1 arg2 " 10 nil) 0))
(is (= (input/current-chat-argument-position
{:name "command1"} "/command1 argument1 arg2 " 19 nil) 0))
(is (= (input/current-chat-argument-position
{:name "command1"} "/command1 argument1 arg2 " 20 nil) 1))
(is (= (input/current-chat-argument-position
{:name "command2"} "/command2 \"a r g u m e n t 1\" argument2" 30 nil) 1))
(is (= (input/current-chat-argument-position
{:name "command3" :command {:sequential-params true}} "/command3" 0 ["test1" "test2"]) 2)))
(deftest argument-position
"Doesn't require a separate test because it simply calls `current-chat-argument-position")
(deftest command-completion
(is (= (input/command-completion {:args ["p1" "p2"]
:command {:params [{:optional false} {:optional false}]}})
:complete))
(is (= (input/command-completion {:args ["p1"]
:command {:params [{:optional false} {:optional false}]}})
:less-than-needed))
(is (= (input/command-completion {:args ["p1" "p2" "p3"]
:command {:params [{:optional false} {:optional false}]}})
:more-than-needed))
(is (= (input/command-completion {:args ["p1" "p2"]
:command {:params [{:optional false} {:optional false} {:optional true}]}})
:complete))
(is (= (input/command-completion {:args ["p1" "p2" "p3"]
:command {:params [{:optional false} {:optional false} {:optional true}]}})
:complete))
(is (= (input/command-completion {:args ["p1" "p2" "p3" "p4"]
:command {:params [{:optional false} {:optional false} {:optional true}]}})
:more-than-needed))
(is (= (input/command-completion {:command {:params [{:optional false}]}})
:less-than-needed))
(is (= (input/command-completion {:command {}})
:complete))
(is (= (input/command-completion nil)
:no-command)))
(deftest args->params
(is (= {} (input/args->params nil)))
(is (= {} (input/args->params {})))
(is (= {} (input/args->params {:args ["1.0"]})))
(is (= {:amount "1.0"}
(input/args->params {:command {:params [{:name "amount"}]}
:args ["1.0"]})))
(is (= {:amount "1.0"}
(input/args->params {:command {:params [{:name "amount"}]}
:args ["1.0" "2.0" "3.0"]})))
(is (= {:amount "1.0"}
(input/args->params {:command {:params [{:name "amount"} {:name "recipient"}]}
:args ["1.0"]})))
(is (= {:amount "1.0" :recipient "John Doe"}
(input/args->params {:command {:params [{:name "amount"} {:name "recipient"}]}
:args ["1.0" "John Doe"]}))))
(deftest command-dependent-context-params
(is (= {} (input/command-dependent-context-params "any" {:name "any"})))
(is (= {} (input/command-dependent-context-params "console" {:name "any"}))))
(deftest modified-db-after-change
"Just a combination of db modifications. Can be skipped now")