* add cheshire.factory namespace This will allow bb users to change jackson factory options when using cheshire. Took inspiration from other bb lib impls that dealt with dynamic vars. Brought over cheshire tests, disabling tests for cheshire/jvm features not included in bb. Closes #1806 * turf debug stuff * turf commented code accidentally left in
This commit is contained in:
parent
3db67a5574
commit
689148b99c
8 changed files with 967 additions and 12 deletions
|
|
@ -7,6 +7,10 @@ A preview of the next release can be installed from
|
||||||
|
|
||||||
[Babashka](https://github.com/babashka/babashka): Native, fast starting Clojure interpreter for scripting
|
[Babashka](https://github.com/babashka/babashka): Native, fast starting Clojure interpreter for scripting
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
- [#1806](https://github.com/babashka/babashka/issues/1806): Add `cheshire.factory` namespace ([@lread](https://github.com/lread))
|
||||||
|
|
||||||
## 1.12.198 (2024-04-17)
|
## 1.12.198 (2024-04-17)
|
||||||
|
|
||||||
- Bump GraalVM to `24`
|
- Bump GraalVM to `24`
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ borkdude/missing.test.assertions,https://github.com/borkdude/missing.test.assert
|
||||||
borkdude/rewrite-edn,https://github.com/borkdude/rewrite-edn
|
borkdude/rewrite-edn,https://github.com/borkdude/rewrite-edn
|
||||||
camel-snake-kebab/camel-snake-kebab,https://github.com/clj-commons/camel-snake-kebab
|
camel-snake-kebab/camel-snake-kebab,https://github.com/clj-commons/camel-snake-kebab
|
||||||
cc.qbits/auspex,https://github.com/mpenet/auspex
|
cc.qbits/auspex,https://github.com/mpenet/auspex
|
||||||
|
cheshire/cheshire,https://github.com/dakrone/cheshire
|
||||||
circleci/bond,https://github.com/circleci/bond
|
circleci/bond,https://github.com/circleci/bond
|
||||||
cli-matic/cli-matic,https://github.com/l3nz/cli-matic.git
|
cli-matic/cli-matic,https://github.com/l3nz/cli-matic.git
|
||||||
clj-commons/clj-yaml,https://github.com/clj-commons/clj-yaml
|
clj-commons/clj-yaml,https://github.com/clj-commons/clj-yaml
|
||||||
|
|
|
||||||
|
|
|
@ -1,25 +1,120 @@
|
||||||
(ns babashka.impl.cheshire
|
(ns babashka.impl.cheshire
|
||||||
{:no-doc true}
|
{:no-doc true}
|
||||||
(:require [cheshire.core :as json]
|
(:require [cheshire.core :as json]
|
||||||
|
[cheshire.factory :as fact]
|
||||||
[sci.core :as sci :refer [copy-var]]))
|
[sci.core :as sci :refer [copy-var]]))
|
||||||
|
|
||||||
(def tns (sci/create-ns 'cheshire.core nil))
|
(def tns (sci/create-ns 'cheshire.core nil))
|
||||||
|
(def fns (sci/create-ns 'cheshire.factory nil))
|
||||||
|
|
||||||
|
(def json-factory (sci/new-dynamic-var '*json-factory* nil {:ns fns}))
|
||||||
|
|
||||||
|
;; wrap cheshire fns to support `*json-factory*` dynamic var
|
||||||
|
|
||||||
|
(defn generate-string
|
||||||
|
([obj]
|
||||||
|
(binding [fact/*json-factory* @json-factory]
|
||||||
|
(json/generate-string obj)))
|
||||||
|
([obj opt-map]
|
||||||
|
(binding [fact/*json-factory* @json-factory]
|
||||||
|
(json/generate-string obj opt-map))))
|
||||||
|
|
||||||
|
(defn generate-stream
|
||||||
|
([obj writer]
|
||||||
|
(binding [fact/*json-factory* @json-factory]
|
||||||
|
(json/generate-stream obj writer)))
|
||||||
|
([obj writer opt-map]
|
||||||
|
(binding [fact/*json-factory* @json-factory]
|
||||||
|
(json/generate-stream obj writer opt-map))))
|
||||||
|
|
||||||
|
(defn parse-string
|
||||||
|
([string]
|
||||||
|
(when string
|
||||||
|
(binding [fact/*json-factory* @json-factory]
|
||||||
|
(json/parse-string string))))
|
||||||
|
([string key-fn]
|
||||||
|
(when string
|
||||||
|
(binding [fact/*json-factory* @json-factory]
|
||||||
|
(json/parse-string string key-fn))))
|
||||||
|
([^String string key-fn array-coerce-fn]
|
||||||
|
(when string
|
||||||
|
(binding [fact/*json-factory* @json-factory]
|
||||||
|
(json/parse-string string key-fn array-coerce-fn)))))
|
||||||
|
|
||||||
|
(defn parse-string-strict
|
||||||
|
([string]
|
||||||
|
(when string
|
||||||
|
(binding [fact/*json-factory* @json-factory]
|
||||||
|
(json/parse-string-strict string))))
|
||||||
|
([string key-fn]
|
||||||
|
(when string
|
||||||
|
(binding [fact/*json-factory* @json-factory]
|
||||||
|
(json/parse-string-strict string key-fn))))
|
||||||
|
([^String string key-fn array-coerce-fn]
|
||||||
|
(when string
|
||||||
|
(binding [fact/*json-factory* @json-factory]
|
||||||
|
(json/parse-string-strict string key-fn array-coerce-fn)))))
|
||||||
|
|
||||||
|
(defn parse-stream
|
||||||
|
([rdr]
|
||||||
|
(when rdr
|
||||||
|
(binding [fact/*json-factory* @json-factory]
|
||||||
|
(json/parse-stream rdr))))
|
||||||
|
([rdr key-fn]
|
||||||
|
(when rdr
|
||||||
|
(binding [fact/*json-factory* @json-factory]
|
||||||
|
(json/parse-stream rdr key-fn))))
|
||||||
|
([rdr key-fn array-coerce-fn]
|
||||||
|
(when rdr
|
||||||
|
(binding [fact/*json-factory* @json-factory]
|
||||||
|
(json/parse-stream rdr key-fn array-coerce-fn)))))
|
||||||
|
|
||||||
|
(defn parse-stream-strict
|
||||||
|
([rdr]
|
||||||
|
(when rdr
|
||||||
|
(binding [fact/*json-factory* @json-factory]
|
||||||
|
(json/parse-stream-strict rdr))))
|
||||||
|
([rdr key-fn]
|
||||||
|
(when rdr
|
||||||
|
(binding [fact/*json-factory* @json-factory]
|
||||||
|
(json/parse-stream-strict rdr key-fn))))
|
||||||
|
([rdr key-fn array-coerce-fn]
|
||||||
|
(when rdr
|
||||||
|
(binding [fact/*json-factory* @json-factory]
|
||||||
|
(json/parse-stream-strict rdr key-fn array-coerce-fn)))))
|
||||||
|
|
||||||
|
(defn parsed-seq
|
||||||
|
([reader]
|
||||||
|
(binding [fact/*json-factory* @json-factory]
|
||||||
|
(json/parsed-seq reader)))
|
||||||
|
([reader key-fn]
|
||||||
|
(binding [fact/*json-factory* @json-factory]
|
||||||
|
(json/parsed-seq reader key-fn)))
|
||||||
|
([reader key-fn array-coerce-fn]
|
||||||
|
(binding [fact/*json-factory* @json-factory]
|
||||||
|
(json/parsed-seq reader key-fn array-coerce-fn))))
|
||||||
|
|
||||||
(def cheshire-core-namespace
|
(def cheshire-core-namespace
|
||||||
{'encode (copy-var json/encode tns)
|
{'encode (copy-var generate-string tns)
|
||||||
'generate-string (copy-var json/generate-string tns)
|
'generate-string (copy-var generate-string tns)
|
||||||
'encode-stream (copy-var json/encode-stream tns)
|
'encode-stream (copy-var generate-stream tns)
|
||||||
'generate-stream (copy-var json/generate-stream tns)
|
'generate-stream (copy-var generate-stream tns)
|
||||||
;;'encode-smile (copy-var json/encode-smile tns)
|
;;'encode-smile (copy-var json/encode-smile tns)
|
||||||
;;'generate-smile (copy-var json/generate-smile tns)
|
;;'generate-smile (copy-var json/generate-smile tns)
|
||||||
'decode (copy-var json/decode tns)
|
'decode (copy-var parse-string tns)
|
||||||
'parse-string (copy-var json/parse-string tns)
|
'parse-string (copy-var parse-string tns)
|
||||||
'parse-string-strict (copy-var json/parse-string-strict tns)
|
'parse-string-strict (copy-var parse-string-strict tns)
|
||||||
;;'parse-smile (copy-var json/parse-smile tns)
|
;;'parse-smile (copy-var json/parse-smile tns)
|
||||||
'parse-stream (copy-var json/parse-stream tns)
|
'parse-stream (copy-var parse-stream tns)
|
||||||
'parse-stream-strict (copy-var json/parse-stream-strict tns)
|
'parse-stream-strict (copy-var parse-stream-strict tns)
|
||||||
'parsed-seq (copy-var json/parsed-seq tns)
|
'parsed-seq (copy-var parsed-seq tns)
|
||||||
;;'parsed-smile-seq (copy-var json/parsed-smile-seq tns)
|
;;'parsed-smile-seq (copy-var json/parsed-smile-seq tns)
|
||||||
;;'decode-smile (copy-var json/decode-smile tns)
|
;;'decode-smile (copy-var json/decode-smile tns)
|
||||||
'default-pretty-print-options (copy-var json/default-pretty-print-options tns)
|
'default-pretty-print-options (copy-var json/default-pretty-print-options tns)
|
||||||
'create-pretty-printer (copy-var json/create-pretty-printer tns)})
|
'create-pretty-printer (copy-var json/create-pretty-printer tns)})
|
||||||
|
|
||||||
|
(def cheshire-factory-namespace
|
||||||
|
{'*json-factory* json-factory
|
||||||
|
'default-factory-options (copy-var fact/default-factory-options fns)
|
||||||
|
'json-factory (copy-var fact/json-factory fns)
|
||||||
|
'make-json-factory (copy-var fact/make-json-factory fns)})
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
[babashka.deps :as bdeps]
|
[babashka.deps :as bdeps]
|
||||||
[babashka.fs :as fs]
|
[babashka.fs :as fs]
|
||||||
[babashka.impl.bencode :refer [bencode-namespace]]
|
[babashka.impl.bencode :refer [bencode-namespace]]
|
||||||
[babashka.impl.cheshire :refer [cheshire-core-namespace]]
|
[babashka.impl.cheshire :refer [cheshire-core-namespace cheshire-factory-namespace]]
|
||||||
[babashka.impl.classes :as classes :refer [classes-namespace]]
|
[babashka.impl.classes :as classes :refer [classes-namespace]]
|
||||||
[babashka.impl.classpath :as cp :refer [classpath-namespace]]
|
[babashka.impl.classpath :as cp :refer [classpath-namespace]]
|
||||||
[babashka.impl.cli :as cli]
|
[babashka.impl.cli :as cli]
|
||||||
|
|
@ -379,6 +379,7 @@ Use bb run --help to show this help output.
|
||||||
'babashka.signal signal-ns
|
'babashka.signal signal-ns
|
||||||
'clojure.java.io io-namespace
|
'clojure.java.io io-namespace
|
||||||
'cheshire.core cheshire-core-namespace
|
'cheshire.core cheshire-core-namespace
|
||||||
|
'cheshire.factory cheshire-factory-namespace
|
||||||
'clojure.data data/data-namespace
|
'clojure.data data/data-namespace
|
||||||
'clojure.instant instant/instant-namespace
|
'clojure.instant instant/instant-namespace
|
||||||
'clojure.stacktrace stacktrace-namespace
|
'clojure.stacktrace stacktrace-namespace
|
||||||
|
|
|
||||||
|
|
@ -200,4 +200,5 @@
|
||||||
hickory.test.hiccup-utils
|
hickory.test.hiccup-utils
|
||||||
hickory.test.render
|
hickory.test.render
|
||||||
hickory.test.select
|
hickory.test.select
|
||||||
hickory.test.zip]}}
|
hickory.test.zip]}
|
||||||
|
cheshire/cheshire {:git-url "https://github.com/dakrone/cheshire", :test-namespaces [cheshire.test.core], :manually-added true}}
|
||||||
|
|
|
||||||
793
test-resources/lib_tests/cheshire/test/core.clj
Normal file
793
test-resources/lib_tests/cheshire/test/core.clj
Normal file
|
|
@ -0,0 +1,793 @@
|
||||||
|
(ns cheshire.test.core
|
||||||
|
(:require [clojure.test :refer [deftest testing is are]]
|
||||||
|
[clojure.java.io :as io]
|
||||||
|
[clojure.string :as str]
|
||||||
|
[cheshire.core :as json]
|
||||||
|
;; BB-TEST-PATCH: bb does not include cheshire.exact
|
||||||
|
#_[cheshire.exact :as json-exact]
|
||||||
|
;; BB-TEST-PATCH: bb does not include cheshire.gen
|
||||||
|
#_[cheshire.generate :as gen]
|
||||||
|
[cheshire.factory :as fact]
|
||||||
|
;; BB-TEST-PATCH: bb does not include cheshire.parse
|
||||||
|
#_[cheshire.parse :as parse])
|
||||||
|
(:import ;; BB-TEST-PATCH: tests adjusted to check for general Exception instead of specific jackson exceptions
|
||||||
|
#_(com.fasterxml.jackson.core JsonGenerationException
|
||||||
|
JsonParseException)
|
||||||
|
#_(com.fasterxml.jackson.core.exc StreamConstraintsException)
|
||||||
|
(java.io StringReader StringWriter
|
||||||
|
BufferedReader BufferedWriter
|
||||||
|
IOException)
|
||||||
|
;; BB-TEST-PATCH: bb does not support creating java.sql.Timestamps
|
||||||
|
#_(java.sql Timestamp)
|
||||||
|
(java.util Date UUID)))
|
||||||
|
|
||||||
|
(defn- str-of-len
|
||||||
|
([len]
|
||||||
|
(str-of-len len "x"))
|
||||||
|
([len val]
|
||||||
|
(apply str (repeat len val))))
|
||||||
|
|
||||||
|
(defn- nested-map [depth]
|
||||||
|
(reduce (fn [acc n] {(str n) acc})
|
||||||
|
{"0" "foo"}
|
||||||
|
(range 1 depth)))
|
||||||
|
|
||||||
|
(defn- encode-stream->str [obj opts]
|
||||||
|
(let [sw (StringWriter.)
|
||||||
|
bw (BufferedWriter. sw)]
|
||||||
|
(json/generate-stream obj bw opts)
|
||||||
|
(.toString sw)))
|
||||||
|
|
||||||
|
(def test-obj {"int" 3 "long" (long -2147483647) "boolean" true
|
||||||
|
"LongObj" (Long/parseLong "2147483647") "double" 1.23
|
||||||
|
"nil" nil "string" "string" "vec" [1 2 3] "map" {"a" "b"}
|
||||||
|
"list" (list "a" "b") "short" (short 21) "byte" (byte 3)})
|
||||||
|
|
||||||
|
(deftest t-ratio
|
||||||
|
(let [n 1/2]
|
||||||
|
(is (= (double n) (:num (json/decode (json/encode {:num n}) true))))))
|
||||||
|
|
||||||
|
(deftest t-long-wrap-around
|
||||||
|
(is (= 2147483648 (json/decode (json/encode 2147483648)))))
|
||||||
|
|
||||||
|
(deftest t-bigint
|
||||||
|
(let [n 9223372036854775808]
|
||||||
|
(is (= n (:num (json/decode (json/encode {:num n}) true))))))
|
||||||
|
|
||||||
|
(deftest t-biginteger
|
||||||
|
(let [n (BigInteger. "42")]
|
||||||
|
(is (= n (:num (json/decode (json/encode {:num n}) true))))))
|
||||||
|
|
||||||
|
(deftest t-bigdecimal
|
||||||
|
(let [n (BigDecimal. "42.5")]
|
||||||
|
(is (= (.doubleValue n) (:num (json/decode (json/encode {:num n}) true))))
|
||||||
|
;; BB-TEST-PATCH:
|
||||||
|
#_(binding [parse/*use-bigdecimals?* true]
|
||||||
|
(is (= n (:num (json/decode (json/encode {:num n}) true)))))))
|
||||||
|
|
||||||
|
(deftest test-string-round-trip
|
||||||
|
(is (= test-obj (json/decode (json/encode test-obj)))))
|
||||||
|
|
||||||
|
(deftest test-generate-accepts-float
|
||||||
|
(is (= "3.14" (json/encode 3.14))))
|
||||||
|
|
||||||
|
(deftest test-keyword-encode
|
||||||
|
(is (= {"key" "val"}
|
||||||
|
(json/decode (json/encode {:key "val"})))))
|
||||||
|
|
||||||
|
(deftest test-generate-set
|
||||||
|
(is (= {"set" ["a" "b"]}
|
||||||
|
(json/decode (json/encode {"set" #{"a" "b"}})))))
|
||||||
|
|
||||||
|
(deftest test-generate-empty-set
|
||||||
|
(is (= {"set" []}
|
||||||
|
(json/decode (json/encode {"set" #{}})))))
|
||||||
|
|
||||||
|
(deftest test-generate-empty-array
|
||||||
|
(is (= {"array" []}
|
||||||
|
(json/decode (json/encode {"array" []})))))
|
||||||
|
|
||||||
|
(deftest test-key-coercion
|
||||||
|
(is (= {"foo" "bar" "1" "bat" "2" "bang" "3" "biz"}
|
||||||
|
(json/decode
|
||||||
|
(json/encode
|
||||||
|
{:foo "bar" 1 "bat" (long 2) "bang" (bigint 3) "biz"})))))
|
||||||
|
|
||||||
|
(deftest test-keywords
|
||||||
|
(is (= {:foo "bar" :bat 1}
|
||||||
|
(json/decode (json/encode {:foo "bar" :bat 1}) true))))
|
||||||
|
|
||||||
|
(deftest test-symbols
|
||||||
|
(is (= {"foo" "clojure.core/map"}
|
||||||
|
(json/decode (json/encode {"foo" 'clojure.core/map})))))
|
||||||
|
|
||||||
|
(deftest test-accepts-java-map
|
||||||
|
(is (= {"foo" 1}
|
||||||
|
(json/decode
|
||||||
|
(json/encode (doto (java.util.HashMap.) (.put "foo" 1)))))))
|
||||||
|
|
||||||
|
(deftest test-accepts-java-list
|
||||||
|
(is (= [1 2 3]
|
||||||
|
(json/decode (json/encode (doto (java.util.ArrayList. 3)
|
||||||
|
(.add 1)
|
||||||
|
(.add 2)
|
||||||
|
(.add 3)))))))
|
||||||
|
|
||||||
|
(deftest test-accepts-java-set
|
||||||
|
(is (= {"set" [1 2 3]}
|
||||||
|
(json/decode (json/encode {"set" (doto (java.util.HashSet. 3)
|
||||||
|
(.add 1)
|
||||||
|
(.add 2)
|
||||||
|
(.add 3))})))))
|
||||||
|
|
||||||
|
(deftest test-accepts-empty-java-set
|
||||||
|
(is (= {"set" []}
|
||||||
|
(json/decode (json/encode {"set" (java.util.HashSet. 3)})))))
|
||||||
|
|
||||||
|
(deftest test-nil
|
||||||
|
(is (nil? (json/decode nil true))))
|
||||||
|
|
||||||
|
(deftest test-parsed-seq
|
||||||
|
(let [br (BufferedReader. (StringReader. "1\n2\n3\n"))]
|
||||||
|
(is (= (list 1 2 3) (json/parsed-seq br)))))
|
||||||
|
|
||||||
|
;; BB-TEST-PATCH: bb does not support smile
|
||||||
|
#_(deftest test-smile-round-trip
|
||||||
|
(is (= test-obj (json/parse-smile (json/generate-smile test-obj)))))
|
||||||
|
|
||||||
|
(def bin-obj {"byte-array" (byte-array (map byte [1 2 3]))})
|
||||||
|
|
||||||
|
;; BB-TEST-PATCH: bb does not support smile/cbor
|
||||||
|
#_(deftest test-round-trip-binary
|
||||||
|
(doseq [[p g] {json/parse-string json/generate-string
|
||||||
|
json/parse-smile json/generate-smile
|
||||||
|
json/parse-cbor json/generate-cbor}]
|
||||||
|
(is (let [roundtripped (p (g bin-obj))]
|
||||||
|
;; test value equality
|
||||||
|
(is (= (->> bin-obj (get "byte-array") seq)
|
||||||
|
(->> roundtripped (get "byte-array") seq)))))))
|
||||||
|
|
||||||
|
;; BB-TEST-PATCH: bb does not support smile
|
||||||
|
#_(deftest test-smile-factory
|
||||||
|
(binding [fact/*smile-factory* (fact/make-smile-factory {})]
|
||||||
|
(is (= {"a" 1} (-> {:a 1}
|
||||||
|
json/generate-smile
|
||||||
|
json/parse-smile)))))
|
||||||
|
|
||||||
|
;; BB-TEST-PATCH: bb does not support smile/cbor
|
||||||
|
#_(deftest test-smile-duplicate-detection
|
||||||
|
(let [smile-data (byte-array [0x3a 0x29 0x0a 0x01 ;; smile header
|
||||||
|
0xFa ;; object start
|
||||||
|
0x80 0x61 ;; key a
|
||||||
|
0xC2 ;; value 1
|
||||||
|
0x80 0x61 ;; key a (again)
|
||||||
|
0xC4 ;; value 2
|
||||||
|
0xFB ;; object end
|
||||||
|
])]
|
||||||
|
(binding [fact/*smile-factory* (fact/make-smile-factory {:strict-duplicate-detection false})]
|
||||||
|
(is (= {"a" 2} (json/parse-smile smile-data))))
|
||||||
|
(binding [fact/*smile-factory* (fact/make-smile-factory {:strict-duplicate-detection true})]
|
||||||
|
(is (thrown? JsonParseException (json/parse-smile smile-data))))))
|
||||||
|
|
||||||
|
;; BB-TEST-PATCH: bb does not support cbor
|
||||||
|
#_(deftest test-cbor-factory
|
||||||
|
(binding [fact/*cbor-factory* (fact/make-cbor-factory {})]
|
||||||
|
(is (= {"a" 1} (-> {:a 1}
|
||||||
|
json/generate-cbor
|
||||||
|
json/parse-cbor)))))
|
||||||
|
|
||||||
|
;; BB-TEST-PATCH: bb does not support cbor
|
||||||
|
#_(deftest test-cbor-duplicate-detection
|
||||||
|
(let [cbor-data (byte-array [0xbf ;; object begin
|
||||||
|
0x61 0x61 ;; key a
|
||||||
|
0x01 ;; value 1
|
||||||
|
0x61 0x61 ;; key a (again)
|
||||||
|
0x02 ;; value 2
|
||||||
|
0xff ;; object end
|
||||||
|
])]
|
||||||
|
(binding [fact/*cbor-factory* (fact/make-cbor-factory {:strict-duplicate-detection false})]
|
||||||
|
(is (= {"a" 2} (json/parse-cbor cbor-data))))
|
||||||
|
(binding [fact/*cbor-factory* (fact/make-cbor-factory {:strict-duplicate-detection true})]
|
||||||
|
(is (thrown? JsonParseException (json/parse-cbor cbor-data))))))
|
||||||
|
|
||||||
|
(deftest test-aliases
|
||||||
|
(is (= {"foo" "bar" "1" "bat" "2" "bang" "3" "biz"}
|
||||||
|
(json/decode
|
||||||
|
(json/encode
|
||||||
|
{:foo "bar" 1 "bat" (long 2) "bang" (bigint 3) "biz"})))))
|
||||||
|
|
||||||
|
(deftest test-date
|
||||||
|
(is (= {"foo" "1970-01-01T00:00:00Z"}
|
||||||
|
(json/decode (json/encode {:foo (Date. (long 0))}))))
|
||||||
|
(is (= {"foo" "1970-01-01"}
|
||||||
|
(json/decode (json/encode {:foo (Date. (long 0))}
|
||||||
|
{:date-format "yyyy-MM-dd"})))
|
||||||
|
"encode with given date format"))
|
||||||
|
|
||||||
|
;; BB-TEST-PATCH: bb does not support creating java.sql.Timestamps
|
||||||
|
#_(deftest test-sql-timestamp
|
||||||
|
(is (= {"foo" "1970-01-01T00:00:00Z"}
|
||||||
|
(json/decode (json/encode {:foo (Timestamp. (long 0))}))))
|
||||||
|
(is (= {"foo" "1970-01-01"}
|
||||||
|
(json/decode (json/encode {:foo (Timestamp. (long 0))}
|
||||||
|
{:date-format "yyyy-MM-dd"})))
|
||||||
|
"encode with given date format"))
|
||||||
|
|
||||||
|
(deftest test-uuid
|
||||||
|
(let [id (UUID/randomUUID)
|
||||||
|
id-str (str id)]
|
||||||
|
(is (= {"foo" id-str} (json/decode (json/encode {:foo id}))))))
|
||||||
|
|
||||||
|
(deftest test-char-literal
|
||||||
|
(is (= "{\"foo\":\"a\"}" (json/encode {:foo \a}))))
|
||||||
|
|
||||||
|
(deftest test-streams
|
||||||
|
(testing "parse-stream"
|
||||||
|
(are [parsed parse parsee] (= parsed
|
||||||
|
(parse (BufferedReader. (StringReader. parsee))))
|
||||||
|
{"foo" "bar"} json/parse-stream "{\"foo\":\"bar\"}\n"
|
||||||
|
{"foo" "bar"} json/parse-stream-strict "{\"foo\":\"bar\"}\n")
|
||||||
|
|
||||||
|
(are [parsed parse parsee] (= parsed
|
||||||
|
(with-open [rdr (StringReader. parsee)]
|
||||||
|
(parse rdr true)))
|
||||||
|
{(keyword "foo baz") "bar"} json/parse-stream "{\"foo baz\":\"bar\"}\n"
|
||||||
|
{(keyword "foo baz") "bar"} json/parse-stream-strict "{\"foo baz\":\"bar\"}\n"))
|
||||||
|
|
||||||
|
(testing "generate-stream"
|
||||||
|
(let [sw (StringWriter.)
|
||||||
|
bw (BufferedWriter. sw)]
|
||||||
|
(json/generate-stream {"foo" "bar"} bw)
|
||||||
|
(is (= "{\"foo\":\"bar\"}" (.toString sw))))))
|
||||||
|
|
||||||
|
;; BB-TEST-PATCH: bb does not include with-writer
|
||||||
|
#_(deftest serial-writing
|
||||||
|
(is (= "[\"foo\",\"bar\"]"
|
||||||
|
(.toString
|
||||||
|
(json/with-writer [(StringWriter.) nil]
|
||||||
|
(json/write [] :start)
|
||||||
|
(json/write "foo")
|
||||||
|
(json/write "bar")
|
||||||
|
(json/write [] :end)))))
|
||||||
|
(is (= "[1,[2,3],4]"
|
||||||
|
(.toString
|
||||||
|
(json/with-writer [(StringWriter.) nil]
|
||||||
|
(json/write [1 [2]] :start-inner)
|
||||||
|
(json/write 3)
|
||||||
|
(json/write [] :end)
|
||||||
|
(json/write 4)
|
||||||
|
(json/write [] :end)))))
|
||||||
|
(is (= "{\"a\":1,\"b\":2,\"c\":3}"
|
||||||
|
(.toString
|
||||||
|
(json/with-writer [(StringWriter.) nil]
|
||||||
|
(json/write {:a 1} :start)
|
||||||
|
(json/write {:b 2} :bare)
|
||||||
|
(json/write {:c 3} :end)))))
|
||||||
|
(is (= (str "[\"start\",\"continue\",[\"implicitly-nested\"],"
|
||||||
|
"[\"explicitly-nested\"],\"flatten\",\"end\"]")
|
||||||
|
(.toString
|
||||||
|
(json/with-writer [(StringWriter.) nil]
|
||||||
|
(json/write ["start"] :start)
|
||||||
|
(json/write "continue")
|
||||||
|
(json/write ["implicitly-nested"])
|
||||||
|
(json/write ["explicitly-nested"] :all)
|
||||||
|
(json/write ["flatten"] :bare)
|
||||||
|
(json/write ["end"] :end)))))
|
||||||
|
(is (= "{\"head\":\"head info\",\"data\":[1,2,3],\"tail\":\"tail info\"}"
|
||||||
|
(.toString
|
||||||
|
(json/with-writer [(StringWriter.) nil]
|
||||||
|
(json/write {:head "head info" :data []} :start-inner)
|
||||||
|
(json/write 1)
|
||||||
|
(json/write 2)
|
||||||
|
(json/write 3)
|
||||||
|
(json/write [] :end)
|
||||||
|
(json/write {:tail "tail info"} :end))))))
|
||||||
|
|
||||||
|
;; BB-TEST-PATCH: modified so that json files could be found
|
||||||
|
(deftest test-multiple-objs-in-file
|
||||||
|
(is (= {"one" 1, "foo" "bar"}
|
||||||
|
(first (json/parsed-seq (io/reader (io/resource "cheshire/test/multi.json"))))))
|
||||||
|
(is (= {"two" 2, "foo" "bar"}
|
||||||
|
(second (json/parsed-seq (io/reader (io/resource "cheshire/test/multi.json"))))))
|
||||||
|
(with-open [r (io/reader (io/resource "cheshire/test/multi.json"))]
|
||||||
|
(is (= [{"one" 1, "foo" "bar"} {"two" 2, "foo" "bar"}]
|
||||||
|
(json/parsed-seq r)))))
|
||||||
|
|
||||||
|
(deftest test-jsondotorg-pass1
|
||||||
|
(let [;; BB-TEST-PATCH: modified so that json files could be found
|
||||||
|
string (slurp (io/resource "cheshire/test/pass1.json"))
|
||||||
|
decoded-json (json/decode string)
|
||||||
|
encoded-json (json/encode decoded-json)
|
||||||
|
re-decoded-json (json/decode encoded-json)]
|
||||||
|
(is (= decoded-json re-decoded-json))))
|
||||||
|
|
||||||
|
(deftest test-namespaced-keywords
|
||||||
|
(is (= "{\"foo\":\"user/bar\"}"
|
||||||
|
(json/encode {:foo :user/bar})))
|
||||||
|
(is (= {:foo/bar "baz/eggplant"}
|
||||||
|
(json/decode (json/encode {:foo/bar :baz/eggplant}) true))))
|
||||||
|
|
||||||
|
(deftest test-array-coerce-fn
|
||||||
|
(is (= {"set" #{"a" "b"} "array" ["a" "b"] "map" {"a" 1}}
|
||||||
|
(json/decode
|
||||||
|
(json/encode {"set" #{"a" "b"} "array" ["a" "b"] "map" {"a" 1}}) false
|
||||||
|
(fn [field-name] (if (= "set" field-name) #{} []))))))
|
||||||
|
|
||||||
|
(deftest t-symbol-encoding-for-non-resolvable-symbols
|
||||||
|
(is (= "{\"bar\":\"clojure.core/pam\",\"foo\":\"clojure.core/map\"}"
|
||||||
|
(json/encode (sorted-map :foo 'clojure.core/map :bar 'clojure.core/pam))))
|
||||||
|
(is (= "{\"bar\":\"clojure.core/pam\",\"foo\":\"foo.bar/baz\"}"
|
||||||
|
(json/encode (sorted-map :foo 'foo.bar/baz :bar 'clojure.core/pam)))))
|
||||||
|
|
||||||
|
(deftest t-bindable-factories-auto-close-source
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:auto-close-source false})]
|
||||||
|
(let [br (BufferedReader. (StringReader. "123"))]
|
||||||
|
(is (= 123 (json/parse-stream br)))
|
||||||
|
(is (= -1 (.read br)))))
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:auto-close-source true})]
|
||||||
|
(let [br (BufferedReader. (StringReader. "123"))]
|
||||||
|
(is (= 123 (json/parse-stream br)))
|
||||||
|
(is (thrown? IOException (.read br))))))
|
||||||
|
|
||||||
|
(deftest t-bindable-factories-allow-comments
|
||||||
|
(let [s "{\"a\": /* comment */ 1, // comment\n \"b\": 2}"]
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:allow-comments true})]
|
||||||
|
(is (= {"a" 1 "b" 2} (json/decode s))))
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:allow-comments false})]
|
||||||
|
;; BB-TEST-PATCH: Generalized exception check
|
||||||
|
(is (thrown? #_JsonParseException Exception (json/decode s))))))
|
||||||
|
|
||||||
|
(deftest t-bindable-factories-allow-unquoted-field-names
|
||||||
|
(let [s "{a: 1, b: 2}"]
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:allow-unquoted-field-names true})]
|
||||||
|
(is (= {"a" 1 "b" 2} (json/decode s))))
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:allow-unquoted-field-names false})]
|
||||||
|
;; BB-TEST-PATCH: Generalized exception check
|
||||||
|
(is (thrown? #_JsonParseException Exception (json/decode s))))))
|
||||||
|
|
||||||
|
(deftest t-bindable-factories-allow-single-quotes
|
||||||
|
(doseq [s ["{'a': \"one\", 'b': \"two\"}"
|
||||||
|
"{\"a\": 'one', \"b\": 'two'}"
|
||||||
|
"{'a': 'one', 'b': 'two'}"]]
|
||||||
|
(testing s
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:allow-single-quotes true})]
|
||||||
|
(is (= {"a" "one" "b" "two"} (json/decode s))))
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:allow-single-quotes false})]
|
||||||
|
;; BB-TEST-PATCH: Generalized exception check
|
||||||
|
(is (thrown? #_JsonParseException Exception (json/decode s)))))))
|
||||||
|
|
||||||
|
(deftest t-bindable-factories-allow-unquoted-control-chars
|
||||||
|
(let [s "{\"a\": \"one\ntwo\"}"]
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:allow-unquoted-control-chars true})]
|
||||||
|
(is (= {"a" "one\ntwo"} (json/decode s))))
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:allow-unquoted-control-chars false})]
|
||||||
|
;; BB-TEST-PATCH: Generalized exception check
|
||||||
|
(is (thrown? #_JsonParseException Exception (json/decode s))))))
|
||||||
|
|
||||||
|
(deftest t-bindable-factories-allow-backslash-escaping-any-char
|
||||||
|
(let [s "{\"a\": 00000000001}"]
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:allow-numeric-leading-zeros true})]
|
||||||
|
(is (= {"a" 1} (json/decode s))))
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:allow-numeric-leading-zeros false})]
|
||||||
|
;; BB-TEST-PATCH: Generalized exception check
|
||||||
|
(is (thrown? #_JsonParseException Exception (json/decode s))))))
|
||||||
|
|
||||||
|
(deftest t-bindable-factories-allow-numeric-leading-zeros
|
||||||
|
(let [s "{\"a\": \"\\o\\n\\e\"}"]
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:allow-backslash-escaping true})]
|
||||||
|
(is (= {"a" "o\ne"} (json/decode s))))
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:allow-backslash-escaping false})]
|
||||||
|
;; BB-TEST-PATCH: Generalized exception check
|
||||||
|
(is (thrown? #_JsonParseException Exception (json/decode s))))))
|
||||||
|
|
||||||
|
(deftest t-bindable-factories-non-numeric-numbers
|
||||||
|
(let [s "{\"foo\":NaN}"]
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:allow-non-numeric-numbers true})]
|
||||||
|
(is (= (type Double/NaN)
|
||||||
|
(type (:foo (json/decode s true))))))
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:allow-non-numeric-numbers false})]
|
||||||
|
;; BB-TEST-PATCH: Generalized exception check
|
||||||
|
(is (thrown? #_JsonParseException Exception (json/decode s true))))))
|
||||||
|
|
||||||
|
(deftest t-bindable-factories-optimization-opts
|
||||||
|
(let [s "{\"a\": \"foo\"}"]
|
||||||
|
(doseq [opts [{:intern-field-names true}
|
||||||
|
{:intern-field-names false}
|
||||||
|
{:canonicalize-field-names true}
|
||||||
|
{:canonicalize-field-names false}]]
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory opts)]
|
||||||
|
(is (= {"a" "foo"} (json/decode s)))))))
|
||||||
|
|
||||||
|
(deftest t-bindable-factories-escape-non-ascii
|
||||||
|
;; includes testing legacy fn opt of same name can override factory
|
||||||
|
(let [edn {:foo "It costs £100"}
|
||||||
|
expected-esc "{\"foo\":\"It costs \\u00A3100\"}"
|
||||||
|
expected-no-esc "{\"foo\":\"It costs £100\"}"
|
||||||
|
opt-esc {:escape-non-ascii true}
|
||||||
|
opt-no-esc {:escape-non-ascii false}]
|
||||||
|
(testing "default factory"
|
||||||
|
(doseq [[fn-opts expected]
|
||||||
|
[[{} expected-no-esc]
|
||||||
|
[opt-esc expected-esc]
|
||||||
|
[opt-no-esc expected-no-esc]]]
|
||||||
|
(testing fn-opts
|
||||||
|
(is (= expected (json/encode edn fn-opts) (encode-stream->str edn fn-opts))))))
|
||||||
|
(testing (str "factory: " opt-esc)
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory opt-esc)]
|
||||||
|
(doseq [[fn-opts expected]
|
||||||
|
[[{} expected-esc]
|
||||||
|
[opt-esc expected-esc]
|
||||||
|
[opt-no-esc expected-no-esc]]]
|
||||||
|
(testing (str "fn: " fn-opts)
|
||||||
|
(is (= expected (json/encode edn fn-opts) (encode-stream->str edn fn-opts)))))))
|
||||||
|
(testing (str "factory: " opt-no-esc)
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory opt-no-esc)]
|
||||||
|
(doseq [[fn-opts expected]
|
||||||
|
[[{} expected-no-esc]
|
||||||
|
[opt-esc expected-esc]
|
||||||
|
[opt-no-esc expected-no-esc]]]
|
||||||
|
(testing (str "fn: " fn-opts)
|
||||||
|
(is (= expected (json/encode edn fn-opts) (encode-stream->str edn fn-opts)))))))))
|
||||||
|
|
||||||
|
(deftest t-bindable-factories-quoteless
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:quote-field-names true})]
|
||||||
|
(is (= "{\"a\":\"foo\"}" (json/encode {:a "foo"}))))
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:quote-field-names false})]
|
||||||
|
(is (= "{a:\"foo\"}" (json/encode {:a "foo"})))))
|
||||||
|
|
||||||
|
(deftest t-bindable-factories-strict-duplicate-detection
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:strict-duplicate-detection true})]
|
||||||
|
;; BB-TEST-PATCH: Generalized exception check
|
||||||
|
(is (thrown? #_ JsonParseException Exception
|
||||||
|
(json/decode "{\"a\": 1, \"b\": 2, \"a\": 3}"))))
|
||||||
|
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:strict-duplicate-detection false})]
|
||||||
|
(is (= {"a" 3 "b" 2}
|
||||||
|
(json/decode "{\"a\": 1, \"b\": 2, \"a\": 3}")))))
|
||||||
|
|
||||||
|
(deftest t-bindable-factories-max-input-document-length
|
||||||
|
(let [edn {"a" (apply str (repeat 10000 "x"))}
|
||||||
|
sample-data (json/encode edn)]
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:max-input-document-length (count sample-data)})]
|
||||||
|
(is (= edn (json/decode sample-data))))
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
;; as per Jackson docs, limit is inexact, so dividing input length by 2 should do the trick
|
||||||
|
{:max-input-document-length (/ (count sample-data) 2)})]
|
||||||
|
(is (thrown-with-msg?
|
||||||
|
;; BB-TEST-PATCH: Generalized exception check
|
||||||
|
#_StreamConstraintsException Exception #"(?i)document length .* exceeds"
|
||||||
|
(json/decode sample-data))))))
|
||||||
|
|
||||||
|
(deftest t-bindable-factories-max-input-token-count
|
||||||
|
;; A token is a single unit of input, such as a number, a string, an object start or end, or an array start or end.
|
||||||
|
(let [edn {"1" 2 "3" 4}
|
||||||
|
sample-data (json/encode edn)]
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:max-input-token-count 6})]
|
||||||
|
(is (= edn (json/decode sample-data))))
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:max-input-token-count 5})]
|
||||||
|
(is (thrown-with-msg?
|
||||||
|
;; BB-TEST-PATCH: Generalized exception check
|
||||||
|
#_StreamConstraintsException Exception #"(?i)token count .* exceeds"
|
||||||
|
(json/decode sample-data))))))
|
||||||
|
|
||||||
|
(deftest t-bindable-factories-max-input-name-length
|
||||||
|
(let [k "somekey"
|
||||||
|
edn {k 1}
|
||||||
|
sample-data (json/encode edn)]
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:max-input-name-length (count k)})]
|
||||||
|
(is (= edn (json/decode sample-data))))
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:max-input-name-length (dec (count k))})]
|
||||||
|
(is (thrown-with-msg?
|
||||||
|
;; BB-TEST-PATCH: Generalized exception check
|
||||||
|
#_StreamConstraintsException Exception #"(?i)name .* exceeds"
|
||||||
|
(json/decode sample-data)))))
|
||||||
|
(let [default-limit (:max-input-name-length fact/default-factory-options)]
|
||||||
|
(let [k (str-of-len default-limit)
|
||||||
|
edn {k 1}
|
||||||
|
sample-data (json/encode edn)]
|
||||||
|
(is (= edn (json/decode sample-data))))
|
||||||
|
(let [k (str-of-len (inc default-limit))
|
||||||
|
sample-data (json/encode {k 1})]
|
||||||
|
(is (thrown-with-msg?
|
||||||
|
;; BB-TEST-PATCH: Generalized exception check
|
||||||
|
#_StreamConstraintsException Exception #"(?i)name .* exceeds"
|
||||||
|
(json/decode sample-data))))))
|
||||||
|
|
||||||
|
(deftest t-bindable-factories-input-nesting-depth
|
||||||
|
(let [edn (nested-map 100)
|
||||||
|
sample-data (json/encode edn)]
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:max-input-nesting-depth 100})]
|
||||||
|
(is (= edn (json/decode sample-data))))
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:max-input-nesting-depth 99})]
|
||||||
|
(is (thrown-with-msg?
|
||||||
|
;; BB-TEST-PATCH: Generalized exception check
|
||||||
|
#_StreamConstraintsException Exception #"(?i)nesting depth .* exceeds"
|
||||||
|
(json/decode sample-data))))))
|
||||||
|
|
||||||
|
(deftest t-bindable-factories-max-input-number-length
|
||||||
|
(let [num 123456789
|
||||||
|
edn {"foo" num}
|
||||||
|
sample-data (json/encode edn)]
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:max-input-number-length (-> num str count)})]
|
||||||
|
(is (= edn (json/decode sample-data))))
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:max-input-number-length (-> num str count dec)})]
|
||||||
|
(is (thrown-with-msg?
|
||||||
|
;; BB-TEST-PATCH: Generalized exception check
|
||||||
|
#_StreamConstraintsException Exception #"(?i)number value length .* exceeds"
|
||||||
|
(json/decode sample-data)))))
|
||||||
|
(let [default-limit (:max-input-number-length fact/default-factory-options)]
|
||||||
|
(let [num (bigint (str-of-len default-limit 2))
|
||||||
|
edn {"foo" num}
|
||||||
|
sample-data (json/encode edn)]
|
||||||
|
(is (= edn (json/decode sample-data))))
|
||||||
|
(let [num (bigint (str-of-len (inc default-limit) 2))
|
||||||
|
sample-data (json/encode {"foo" num})]
|
||||||
|
(is (thrown-with-msg?
|
||||||
|
;; BB-TEST-PATCH: Generalized exception check
|
||||||
|
#_StreamConstraintsException Exception #"(?i)number value length .* exceeds"
|
||||||
|
(json/decode sample-data))))))
|
||||||
|
|
||||||
|
(deftest t-bindable-factories-max-input-string-length
|
||||||
|
(let [big-string (str-of-len 40000000)
|
||||||
|
edn {"big-string" big-string}
|
||||||
|
sample-data (json/encode edn)]
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:max-input-string-length (count big-string)})]
|
||||||
|
(is (= edn (json/decode sample-data))))
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:max-input-string-length (dec (count big-string))})]
|
||||||
|
(is (thrown-with-msg?
|
||||||
|
;; BB-TEST-PATCH: Generalized exception check
|
||||||
|
#_StreamConstraintsException Exception #"(?i)string value length .* exceeds"
|
||||||
|
(json/decode sample-data)))))
|
||||||
|
(let [default-limit (:max-input-string-length fact/default-factory-options)]
|
||||||
|
(let [big-string (str-of-len default-limit)
|
||||||
|
edn {"big-string" big-string}
|
||||||
|
sample-data (json/encode edn)]
|
||||||
|
(is (= edn (json/decode sample-data))))
|
||||||
|
(let [big-string (str-of-len (inc default-limit))
|
||||||
|
sample-data (json/encode {"big-string" big-string})]
|
||||||
|
(is (thrown-with-msg?
|
||||||
|
;; BB-TEST-PATCH: Generalized exception check
|
||||||
|
#_StreamConstraintsException Exception #"(?i)string value length .* exceeds"
|
||||||
|
(json/decode sample-data))))))
|
||||||
|
|
||||||
|
(deftest t-bindable-factories-max-output-nesting-depth
|
||||||
|
(let [edn (nested-map 100)]
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:max-output-nesting-depth 100})]
|
||||||
|
(is (.contains (json/encode edn) "\"99\"")))
|
||||||
|
(binding [fact/*json-factory* (fact/make-json-factory
|
||||||
|
{:max-output-nesting-depth 99})]
|
||||||
|
(is (thrown-with-msg?
|
||||||
|
;; BB-TEST-PATCH: Generalized exception check
|
||||||
|
#_StreamConstraintsException Exception #"(?i)nesting depth .* exceeds"
|
||||||
|
(json/encode edn))))))
|
||||||
|
|
||||||
|
(deftest t-persistent-queue
|
||||||
|
(let [q (conj clojure.lang.PersistentQueue/EMPTY 1 2 3)]
|
||||||
|
(is (= q (json/decode (json/encode q))))))
|
||||||
|
|
||||||
|
(deftest t-pretty-print
|
||||||
|
(is (= (str/join (System/lineSeparator)
|
||||||
|
["{"
|
||||||
|
" \"bar\" : [ {"
|
||||||
|
" \"baz\" : 2"
|
||||||
|
" }, \"quux\", [ 1, 2, 3 ] ],"
|
||||||
|
" \"foo\" : 1"
|
||||||
|
"}"])
|
||||||
|
(json/encode (sorted-map :foo 1 :bar [{:baz 2} :quux [1 2 3]])
|
||||||
|
{:pretty true}))))
|
||||||
|
|
||||||
|
(deftest t-pretty-print-custom-linebreak
|
||||||
|
(is (= (str/join "foo"
|
||||||
|
["{"
|
||||||
|
" \"bar\" : [ {"
|
||||||
|
" \"baz\" : 2"
|
||||||
|
" }, \"quux\", [ 1, 2, 3 ] ],"
|
||||||
|
" \"foo\" : 1"
|
||||||
|
"}"])
|
||||||
|
(json/encode (sorted-map :foo 1 :bar [{:baz 2} :quux [1 2 3]])
|
||||||
|
{:pretty {:line-break "foo"}}))))
|
||||||
|
|
||||||
|
(deftest t-pretty-print-illegal-argument
|
||||||
|
; just expecting this not to throw
|
||||||
|
(json/encode {:foo "bar"}
|
||||||
|
{:pretty []})
|
||||||
|
(json/encode {:foo "bar"}
|
||||||
|
{:pretty nil}))
|
||||||
|
|
||||||
|
(deftest t-custom-pretty-print-with-defaults
|
||||||
|
(let [test-obj (sorted-map :foo 1 :bar {:baz [{:ulu "mulu"} {:moot "foo"} 3]} :quux :blub)
|
||||||
|
pretty-str-default (json/encode test-obj {:pretty true})
|
||||||
|
pretty-str-custom (json/encode test-obj {:pretty {}})]
|
||||||
|
(is (= pretty-str-default pretty-str-custom))
|
||||||
|
(when-not (= pretty-str-default pretty-str-custom)
|
||||||
|
; print for easy comparison
|
||||||
|
(println "; default pretty print")
|
||||||
|
(println pretty-str-default)
|
||||||
|
(println "; custom pretty print with default options")
|
||||||
|
(println pretty-str-custom))))
|
||||||
|
|
||||||
|
(deftest t-custom-pretty-print-with-non-defaults
|
||||||
|
(let [test-obj (sorted-map :foo 1 :bar {:baz [{:ulu "mulu"} {:moot "foo"} 3]} :quux :blub)
|
||||||
|
test-opts {:pretty {:indentation 4
|
||||||
|
:indent-arrays? false
|
||||||
|
:before-array-values ""
|
||||||
|
:after-array-values ""
|
||||||
|
:object-field-value-separator ": "}}
|
||||||
|
expected (str/join (System/lineSeparator)
|
||||||
|
["{"
|
||||||
|
" \"bar\": {"
|
||||||
|
" \"baz\": [{"
|
||||||
|
" \"ulu\": \"mulu\""
|
||||||
|
" }, {"
|
||||||
|
" \"moot\": \"foo\""
|
||||||
|
" }, 3]"
|
||||||
|
" },"
|
||||||
|
" \"foo\": 1,"
|
||||||
|
" \"quux\": \"blub\""
|
||||||
|
"}"])
|
||||||
|
pretty-str (json/encode test-obj test-opts)]
|
||||||
|
|
||||||
|
; just to be easy on the eyes in case of error
|
||||||
|
(when-not (= expected pretty-str)
|
||||||
|
(println "; pretty print with options - actual")
|
||||||
|
(println pretty-str)
|
||||||
|
(println "; pretty print with options - expected")
|
||||||
|
(println expected))
|
||||||
|
(is (= expected pretty-str))))
|
||||||
|
|
||||||
|
(deftest t-custom-pretty-print-with-noident-objects
|
||||||
|
(let [test-obj [{:foo 1 :bar 2} {:foo 3 :bar 4}]
|
||||||
|
test-opts {:pretty {:indent-objects? false}}
|
||||||
|
expected (str "[ { \"foo\" : 1, \"bar\" : 2 }, "
|
||||||
|
"{ \"foo\" : 3, \"bar\" : 4 } ]")
|
||||||
|
pretty-str (json/encode test-obj test-opts)]
|
||||||
|
; just to be easy on the eyes in case of error
|
||||||
|
(when-not (= expected pretty-str)
|
||||||
|
(println "; pretty print with options - actual")
|
||||||
|
(println pretty-str)
|
||||||
|
(println "; pretty print with options - expected")
|
||||||
|
(println expected))
|
||||||
|
(is (= expected pretty-str))))
|
||||||
|
|
||||||
|
(deftest t-custom-keyword-fn
|
||||||
|
(is (= {:FOO "bar"} (json/decode "{\"foo\": \"bar\"}"
|
||||||
|
(fn [k] (keyword (.toUpperCase k))))))
|
||||||
|
(is (= {"foo" "bar"} (json/decode "{\"foo\": \"bar\"}" nil)))
|
||||||
|
(is (= {"foo" "bar"} (json/decode "{\"foo\": \"bar\"}" false)))
|
||||||
|
(is (= {:foo "bar"} (json/decode "{\"foo\": \"bar\"}" true))))
|
||||||
|
|
||||||
|
(deftest t-custom-encode-key-fn
|
||||||
|
(is (= "{\"FOO\":\"bar\"}"
|
||||||
|
(json/encode {:foo :bar}
|
||||||
|
{:key-fn (fn [k] (.toUpperCase (name k)))}))))
|
||||||
|
|
||||||
|
;; BB-TEST-PATCH: bb does nto include cheshire.generate ns
|
||||||
|
#_(deftest test-add-remove-encoder
|
||||||
|
(gen/remove-encoder java.net.URL)
|
||||||
|
(gen/add-encoder java.net.URL gen/encode-str)
|
||||||
|
(is (= "\"http://foo.com\""
|
||||||
|
(json/encode (java.net.URL. "http://foo.com"))))
|
||||||
|
(gen/remove-encoder java.net.URL)
|
||||||
|
(is (thrown? JsonGenerationException
|
||||||
|
(json/encode (java.net.URL. "http://foo.com")))))
|
||||||
|
|
||||||
|
#_(defprotocol TestP
|
||||||
|
(foo [this] "foo method"))
|
||||||
|
|
||||||
|
#_(defrecord TestR [state])
|
||||||
|
|
||||||
|
#_(extend TestR
|
||||||
|
TestP
|
||||||
|
{:foo (constantly "bar")})
|
||||||
|
|
||||||
|
#_(deftest t-custom-protocol-encoder
|
||||||
|
(let [rec (TestR. :quux)]
|
||||||
|
(is (= {:state "quux"} (json/decode (json/encode rec) true)))
|
||||||
|
(gen/add-encoder cheshire.test.core.TestR
|
||||||
|
(fn [obj jg]
|
||||||
|
(.writeString jg (foo obj))))
|
||||||
|
(is (= "bar" (json/decode (json/encode rec))))
|
||||||
|
(gen/remove-encoder cheshire.test.core.TestR)
|
||||||
|
(is (= {:state "quux"} (json/decode (json/encode rec) true)))))
|
||||||
|
|
||||||
|
#_(defprotocol CTestP
|
||||||
|
(thing [this] "thing method"))
|
||||||
|
#_(defrecord CTestR [state])
|
||||||
|
#_(extend CTestR
|
||||||
|
CTestP
|
||||||
|
{:thing (constantly "thing")})
|
||||||
|
|
||||||
|
#_(deftest t-custom-helpers
|
||||||
|
(let [thing (CTestR. :state)
|
||||||
|
remove #(gen/remove-encoder CTestR)]
|
||||||
|
(gen/add-encoder CTestR (fn [_obj jg] (gen/encode-nil nil jg)))
|
||||||
|
(is (= nil (json/decode (json/encode thing) true)))
|
||||||
|
(remove)
|
||||||
|
(gen/add-encoder CTestR (fn [_obj jg] (gen/encode-str "foo" jg)))
|
||||||
|
(is (= "foo" (json/decode (json/encode thing) true)))
|
||||||
|
(remove)
|
||||||
|
(gen/add-encoder CTestR (fn [_obj jg] (gen/encode-number 5 jg)))
|
||||||
|
(is (= 5 (json/decode (json/encode thing) true)))
|
||||||
|
(remove)
|
||||||
|
(gen/add-encoder CTestR (fn [_obj jg] (gen/encode-long 4 jg)))
|
||||||
|
(is (= 4 (json/decode (json/encode thing) true)))
|
||||||
|
(remove)
|
||||||
|
(gen/add-encoder CTestR (fn [_obj jg] (gen/encode-int 3 jg)))
|
||||||
|
(is (= 3 (json/decode (json/encode thing) true)))
|
||||||
|
(remove)
|
||||||
|
(gen/add-encoder CTestR (fn [_obj jg] (gen/encode-ratio 1/2 jg)))
|
||||||
|
(is (= 0.5 (json/decode (json/encode thing) true)))
|
||||||
|
(remove)
|
||||||
|
(gen/add-encoder CTestR (fn [_obj jg] (gen/encode-seq [:foo :bar] jg)))
|
||||||
|
(is (= ["foo" "bar"] (json/decode (json/encode thing) true)))
|
||||||
|
(remove)
|
||||||
|
(gen/add-encoder CTestR (fn [_obj jg] (gen/encode-date (Date. (long 0)) jg)))
|
||||||
|
(binding [gen/*date-format* "yyyy-MM-dd'T'HH:mm:ss'Z'"]
|
||||||
|
(is (= "1970-01-01T00:00:00Z" (json/decode (json/encode thing) true))))
|
||||||
|
(remove)
|
||||||
|
(gen/add-encoder CTestR (fn [_obj jg] (gen/encode-bool true jg)))
|
||||||
|
(is (= true (json/decode (json/encode thing) true)))
|
||||||
|
(remove)
|
||||||
|
(gen/add-encoder CTestR (fn [_obj jg] (gen/encode-named :foo jg)))
|
||||||
|
(is (= "foo" (json/decode (json/encode thing) true)))
|
||||||
|
(remove)
|
||||||
|
(gen/add-encoder CTestR (fn [_obj jg] (gen/encode-map {:foo "bar"} jg)))
|
||||||
|
(is (= {:foo "bar"} (json/decode (json/encode thing) true)))
|
||||||
|
(remove)
|
||||||
|
(gen/add-encoder CTestR (fn [_obj jg] (gen/encode-symbol 'foo jg)))
|
||||||
|
(is (= "foo" (json/decode (json/encode thing) true)))
|
||||||
|
(remove)))
|
||||||
|
|
||||||
|
(deftest t-float-encoding
|
||||||
|
(is (= "{\"foo\":0.01}" (json/encode {:foo (float 0.01)}))))
|
||||||
|
|
||||||
|
(deftest t-non-const-bools
|
||||||
|
(is (= {:a 1} (json/decode "{\"a\": 1}" (Boolean. true)))))
|
||||||
|
|
||||||
|
;; BB-TEST-PATCH: bb does not include cheshire.exact ns
|
||||||
|
#_(deftest t-invalid-json
|
||||||
|
(let [invalid-json-message "Invalid JSON, expected exactly one parseable object but multiple objects were found"]
|
||||||
|
(are [x y] (= x (try
|
||||||
|
y
|
||||||
|
(catch Exception e
|
||||||
|
(.getMessage e))))
|
||||||
|
invalid-json-message (json-exact/decode "{\"foo\": 1}asdf")
|
||||||
|
invalid-json-message (json-exact/decode "{\"foo\": 123}null")
|
||||||
|
invalid-json-message (json-exact/decode "\"hello\" : 123}")
|
||||||
|
{"foo" 1} (json/decode "{\"foo\": 1}")
|
||||||
|
invalid-json-message (json-exact/decode-strict "{\"foo\": 1}asdf")
|
||||||
|
invalid-json-message (json-exact/decode-strict "{\"foo\": 123}null")
|
||||||
|
invalid-json-message (json-exact/decode-strict "\"hello\" : 123}")
|
||||||
|
{"foo" 1} (json/decode-strict "{\"foo\": 1}"))))
|
||||||
2
test-resources/lib_tests/cheshire/test/multi.json
Normal file
2
test-resources/lib_tests/cheshire/test/multi.json
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
{"one":1,"foo":"bar"}
|
||||||
|
{"two":2,"foo":"bar"}
|
||||||
58
test-resources/lib_tests/cheshire/test/pass1.json
Normal file
58
test-resources/lib_tests/cheshire/test/pass1.json
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
[
|
||||||
|
"JSON Test Pattern pass1",
|
||||||
|
{"object with 1 member":["array with 1 element"]},
|
||||||
|
{},
|
||||||
|
[],
|
||||||
|
-42,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
{
|
||||||
|
"integer": 1234567890,
|
||||||
|
"real": -9876.543210,
|
||||||
|
"e": 0.123456789e-12,
|
||||||
|
"E": 1.234567890E+34,
|
||||||
|
"": 23456789012E66,
|
||||||
|
"zero": 0,
|
||||||
|
"one": 1,
|
||||||
|
"space": " ",
|
||||||
|
"quote": "\"",
|
||||||
|
"backslash": "\\",
|
||||||
|
"controls": "\b\f\n\r\t",
|
||||||
|
"slash": "/ & \/",
|
||||||
|
"alpha": "abcdefghijklmnopqrstuvwyz",
|
||||||
|
"ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
|
||||||
|
"digit": "0123456789",
|
||||||
|
"0123456789": "digit",
|
||||||
|
"special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
|
||||||
|
"hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
|
||||||
|
"true": true,
|
||||||
|
"false": false,
|
||||||
|
"null": null,
|
||||||
|
"array":[ ],
|
||||||
|
"object":{ },
|
||||||
|
"address": "50 St. James Street",
|
||||||
|
"url": "http://www.JSON.org/",
|
||||||
|
"comment": "// /* <!-- --",
|
||||||
|
"# -- --> */": " ",
|
||||||
|
" s p a c e d " :[1,2 , 3
|
||||||
|
|
||||||
|
,
|
||||||
|
|
||||||
|
4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7],
|
||||||
|
"jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
|
||||||
|
"quotes": "" \u0022 %22 0x22 034 "",
|
||||||
|
"\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
|
||||||
|
: "A key can be any string"
|
||||||
|
},
|
||||||
|
0.5 ,98.6
|
||||||
|
,
|
||||||
|
99.44
|
||||||
|
,
|
||||||
|
|
||||||
|
1066,
|
||||||
|
1e1,
|
||||||
|
0.1e1,
|
||||||
|
1e-1,
|
||||||
|
1e00,2e+00,2e-00
|
||||||
|
,"rosebud"]
|
||||||
Loading…
Reference in a new issue