7

How can I wrap a string in an input-stream in such a way that I can test the function bellow?

(defn parse-body [body]
    (cheshire/parse-stream  (clojure.java.io/reader body) true))

(deftest test-parse-body
    (testing "read body"
        (let [body "{\"age\": 28}"]  ;; must wrap string
            (is (= (parse-body body) {:age 28}))
            )))
user983716
  • 1,992
  • 1
  • 22
  • 32
  • 3
    The accepted answer is good and answers your title question, but know that `clojure.java.io/reader` accepts any (char-based) `java.io.Reader`, and so the detour to (byte-based) `java.io.InputStream` and character encoding is unnecessary. Instead, simply wrap the string in a [`java.io.StringReader`](http://docs.oracle.com/javase/8/docs/api/java/io/StringReader.html): `(java.io.StringReader. body)`. – glts Jul 09 '16 at 21:18

1 Answers1

14

It is straightforward to construct an InputStream from a String using host interop, by converting to a byte-array first:

(defn string->stream
  ([s] (string->stream s "UTF-8"))
  ([s encoding]
   (-> s
       (.getBytes encoding)
       (java.io.ByteArrayInputStream.))))

As another stream and byte interop example, here's a function that returns a vector of the bytes produced when encoding a String to a given format:

(defn show-bytes
  [s encoding]
  (let [buf (java.io.ByteArrayOutputStream.)
        stream (string->stream s encoding)
        ;; worst case, 8 bytes per char?
        data (byte-array (* (count s) 8))
        size (.read stream data 0 (count data))]
    (.write buf data 0 size)
    (.flush buf)
    (apply vector-of :byte (.toByteArray buf))))

+user=> (string->stream "hello")
#object[java.io.ByteArrayInputStream 0x39b43d60 "java.io.ByteArrayInputStream@39b43d60"]
+user=> (isa? (class *1) java.io.InputStream)
true
+user=> (show-bytes "hello" "UTF-8")
[104 101 108 108 111]
+user=> (show-bytes "hello" "UTF-32")
[0 0 0 104 0 0 0 101 0 0 0 108 0 0 0 108 0 0 0 111]
noisesmith
  • 20,076
  • 2
  • 41
  • 49