1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
|
(ns nrepl.middleware.print-test
"Tests for the print middleware. This does not depend on, or use the `eval`
middleware. Instead, it sends the values to be printed directly in the
`:value` slot, and uses an echo handler to send it back via the printing
transport.
These tests are transport agnostic, and do not deal with sessions, session
IDs, and message IDs"
(:refer-clojure :exclude [print])
(:require [clojure.test :refer [deftest is testing]]
[nrepl.core :refer [combine-responses]]
[nrepl.middleware.print :as print]
[nrepl.transport :as t])
(:import [java.io Writer]))
(defn echo-handler
[{:keys [transport] :as msg}]
(t/send transport (select-keys msg (::print/keys msg))))
(defn test-transport
"This transport just collects messages sent into an atom"
[queue]
(t/fn-transport
nil
#(swap! queue conj %)))
(defmacro testing-print
"Macro for print tests. Exposes a function `handle`, which takes a msg.
the `:value` in the message will be printed, using whatever extra print
arguments supplied."
{:style/indent 1}
[doc & body]
`(testing ~doc
(let [~'handle (fn [msg#]
(let [print-handler# (print/wrap-print echo-handler)
resps# (atom [])
resp-transport# (test-transport resps#)]
(print-handler# (assoc msg#
:transport resp-transport#
::print/keys (or (get msg# ::print/keys)
#{:value})))
(doall @resps#)))]
~@body)))
(defn custom-printer
[value ^Writer writer opts]
(.write writer (format "<foo %s %s>" value (or (:sub opts) "..."))))
(deftest value-printing
(testing-print "bad symbol should fall back to default printer"
(is (= [{:status #{::print/error}
::print/error "Couldn't resolve var my.missing.ns/printer"}
{:value "42"}]
(handle {:value 42
::print/keys #{:value}
::print/print 'my.missing.ns/printer}))))
(testing-print "custom printing function symbol should be used"
(is (= [{:value "<foo true ...>"}]
(handle {::print/keys #{:value}
:value true
::print/print `custom-printer}))))
(testing-print "empty print options are ignored"
(is (= [{:value "<foo 42 ...>"}]
(handle {:value 42
::print/print `custom-printer
::print/keys #{:value}
::print/options {}}))))
(testing-print "options should be passed to printer"
(is (= [{:value "<foo 3 bar>"}]
(handle {:value 3
::print/print `custom-printer
::print/keys #{:value}
::print/options {:sub "bar"}})))))
(deftest override-value-printing
(testing-print "custom ::print/keys"
(is (= [{:out "[1 2 3 4 5]"}]
(handle {:value "value"
:out [1 2 3 4 5]
::print/keys [:out]}))))
(testing-print "empty ::print/keys"
(is (= [{}]
(handle {:value [1 2 3 4 5]
::print/keys []})))))
(deftest streamed-printing
(testing-print "value response arrives before ns response"
(let [responses (handle {:value (range 10)
::print/stream? 1})]
(is (= [{:value "(0 1 2 3 4 5 6 7 8 9)"} {}]
responses))))
(testing-print "large output should be streamed"
(let [[resp1 resp2 resp3]
(handle {:value (range 512)
::print/stream? 1})]
(is (-> resp1
^String (:value)
(.startsWith "(0 1 2 3")))
(is (= {} (dissoc resp1 :value)))
(is (-> resp2
^String (:value)
(.endsWith "510 511)")))
(is (= {} (dissoc resp2 :value)))
(is (= {} resp3))))
(testing-print "respects buffer-size option"
(is (= [{:value "(0 1 2 3"}
{:value " 4 5 6 7"}
{:value " 8 9 10 "}
{:value "11 12 13"}
{:value " 14 15)"}
{}]
(handle {:value (range 16)
::print/stream? 1
::print/buffer-size 8}))))
(testing-print "works with custom printer"
(let [[resp1 resp2 resp3] (handle {:value (range 512)
::print/stream? 1
::print/print `custom-printer})]
(is (-> resp1
^String (:value)
(.startsWith "<foo (0 1 2 3")))
(is (= {} (dissoc resp1 :value)))
(is (-> resp2
^String (:value)
(.endsWith "510 511) ...>")))
(is (= {} (dissoc resp2 :value)))
(is (= {} resp3))))
(testing-print "works with custom printer and print-options"
(let [[resp1 resp2 resp3] (handle {:value (range 512)
::print/stream? 1
::print/print `custom-printer
::print/options {:sub "bar"}})]
(is (-> resp1
^String (:value)
(.startsWith "<foo (0 1 2 3")))
(is (= {} (dissoc resp1 :value)))
(is (-> resp2
^String (:value)
(.endsWith "510 511) bar>")))
(is (= {} (dissoc resp2 :value)))
(is (= {} resp3)))))
(deftest multiple-keys
(testing-print "respects buffer-size option"
(is (= [{:value "(0 1 2 3"}
{:value " 4 5 6)"}
{:out "(6 5 4 3"}
{:out " 2 1 0)"}
{}]
(handle {:value (range 7)
:out (reverse (range 7))
::print/stream? 1
::print/buffer-size 8
::print/keys [:value :out]})))))
(deftest print-quota
(testing-print "quota option respected"
(is (= [{:value "(0 1 2 3"
:status #{::print/truncated}
::print/truncated-keys [:value]}]
(handle {:value (range 512)
::print/quota 8}))))
(testing-print "works with streamed printing"
(is (= [{:value "(0 1 2 3"}
{:status #{::print/truncated}}
{}]
(handle {:value (range 512)
::print/stream? 1
::print/quota 8}))))
(testing-print "works with custom printer"
(is (= [{:value "<foo (0 "
:status #{::print/truncated}
::print/truncated-keys [:value]}]
(handle {:value (range 512)
::print/print `custom-printer
::print/quota 8}))))
(testing-print "works with custom printer and streamed printing"
(is (= [{:value "<foo (0 "}
{:status #{::print/truncated}}
{}]
(handle {:value (range 512)
::print/print `custom-printer
::print/stream? 1
::print/quota 8})))))
(defn custom-printer-2
[value ^Writer writer]
(.write writer (format "<bar %s>" value)))
;; These tests used to the `session-print-configuration` tests from `core-test`.
;; here, we are simply testing the use of dynamic vars to configure printing
;; behaviour, thus are not going via the `session` middleware to do that.
(deftest dynamic-var-print-configuration
(testing-print "setting *print-fn* works"
(is (= [{:value "<bar (0 1 2 3 4 5 6 7 8 9)>"}]
(binding [print/*print-fn* custom-printer-2]
(handle {:value (range 10)})))))
(testing-print "request can still override *print-fn*"
(is (= [{:value "<foo (0 1 2 3 4 5 6 7 8 9) ...>"}]
(binding [print/*print-fn* custom-printer-2]
(handle {:value (range 10)
::print/print `custom-printer})))))
(testing-print "setting stream options works"
(is (= [{:value "<bar (0 "}
{:value "1 2 3 4 "}
{:value "5 6 7 8 "}
{:value "9)>"}
{}]
(binding [print/*print-fn* custom-printer-2
print/*stream?* true
print/*buffer-size* 8]
(handle {:value (range 10)})))))
(testing-print "request can still override stream options"
(is (= [{:value "<bar (0 1 2 3 4 5 6 7 8 9)>"}]
(binding [print/*print-fn* custom-printer-2
print/*stream?* true
print/*buffer-size* 8]
(handle {:value (range 10)
::print/stream? nil}))))
(is (= [{:value "<bar (0 1 2 3 4 "}
{:value "5 6 7 8 9)>"}
{}]
(binding [print/*print-fn* custom-printer-2
print/*stream?* true
print/*buffer-size* 8]
(handle {:value (range 10)
::print/buffer-size 16})))))
(testing-print "setting *quota* works"
(is (= [{:value "<bar (0 "
:status #{:nrepl.middleware.print/truncated}
::print/truncated-keys [:value]}]
(binding [print/*print-fn* custom-printer-2
print/*quota* 8]
(handle {:value (range 512)})))))
(testing-print "request can still override *quota*"
(is (= [{:value "<bar (0 1 2 3 4 "
:status #{:nrepl.middleware.print/truncated}
::print/truncated-keys [:value]}]
(binding [print/*print-fn* custom-printer-2
print/*quota* 8]
(handle {:value (range 512)
::print/quota 16}))))))
|