Last active
August 12, 2020 11:10
-
-
Save vemv/7d9489cee6745b55f637e64fb95d4113 to your computer and use it in GitHub Desktop.
json-libs-equivalence-test
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns json-libs-equivalence-test | |
"Includes code derived from: | |
https://github.com/metosin/jsonista/blob/211306f04bb15d7232b536cf6c6d8ecfeae0512d/LICENSE | |
https://github.com/dakrone/cheshire/blob/4525b23da1c17decba363202402a8a195d21705f/LICENSE" | |
(:require | |
[cheshire.core :as cheshire] | |
[clojure.data.json] | |
[clojure.java.io :as io] | |
[clojure.test :refer [are deftest is testing]] | |
[jsonista.core :as jsonista] | |
[nedap.speced.def :as speced]) | |
(:import | |
(clojure.lang PersistentVector LazySeq) | |
(java.sql Timestamp) | |
(java.time Instant LocalDateTime LocalTime ZoneOffset) | |
(java.util Date UUID) | |
(java.util.zip GZIPInputStream))) | |
(def read-fns | |
[jsonista/read-value | |
cheshire/parse-string | |
cheshire/parse-string-strict | |
clojure.data.json/read-str]) | |
(def write-fns | |
[jsonista/write-value-as-string | |
cheshire/generate-string | |
clojure.data.json/write-str]) | |
(defn read+write-combinations [exclude-clojure-data-json?] | |
(cond->> read-fns | |
exclude-clojure-data-json? drop-last | |
true (mapcat (fn [x] | |
(cond->> write-fns | |
exclude-clojure-data-json? drop-last | |
true (map (fn [y] | |
[x y]))))))) | |
(speced/defn read+write= [^string? x, ^string? y] | |
(->> (for [[read-fn write-fn] (read+write-combinations false)] | |
(->> [x y] | |
(map (fn [a] | |
(-> a read-fn write-fn))) | |
(apply =))) | |
(every? true?))) | |
(speced/defn write+read= [^map? x, ^boolean? exclude-clojure-data-json?] | |
(->> (for [[read-fn write-fn] (read+write-combinations exclude-clojure-data-json?)] | |
(->> [x] | |
(map (fn [a] | |
(-> a write-fn read-fn))))) | |
(apply =))) | |
(def data | |
{:numbers {:integer (int 1) | |
:long (long 2) | |
:double (double 1.2) | |
:float (float 3.14) | |
:big-integer (biginteger 3) | |
:big-decimal (bigdec 4) | |
:ratio 3/4 | |
:short (short 5) | |
:byte (byte 6) | |
:big-int (bigint 7)} | |
:boolean true | |
:string "string" | |
:character \c | |
:keyword :keyword | |
:q-keyword :qualified/:keyword | |
:set #{1 2 3} | |
:queue (conj (clojure.lang.PersistentQueue/EMPTY) 1 2 3) | |
:list (list 1 2 3) | |
:bytes (.getBytes "bytes") | |
:uuid (UUID/fromString "fbe5a1e8-6c91-42f6-8147-6cde3188fd25") | |
:symbol 'symbol | |
:java-set (doto (java.util.HashSet.) (.add 1) (.add 2) (.add 3)) | |
:java-map (doto (java.util.HashMap.) (.put :foo "bar")) | |
:java-list (doto (java.util.ArrayList.) (.add 1) (.add 2) (.add 3)) | |
:dates {:date (Date. 0) | |
:timestamp (Timestamp. 0) | |
:instant (Instant/ofEpochMilli 0) | |
:local-time (LocalTime/ofNanoOfDay 0) | |
:local-date-time (LocalDateTime/ofEpochSecond 0 0 ZoneOffset/UTC)}}) | |
(def big-test-obj | |
;; https://github.com/dakrone/cheshire/blob/4525b23da1c17decba363202402a8a195d21705f/test/all_month.geojson.gz | |
(-> "all_month.geojson.gz" | |
io/resource | |
io/input-stream | |
GZIPInputStream. | |
slurp)) | |
(deftest roundrobin | |
(let [without-java-time #(update % :dates dissoc :instant :local-time :local-date-time)] | |
(testing "Cheshire reads+writes identically to jsonista" | |
(let [data (-> data without-java-time)] | |
(is (read+write= (cheshire/generate-string data) | |
(jsonista/write-value-as-string data))) | |
(is (read+write= (cheshire/generate-string data) | |
(jsonista/write-value-as-string data))) | |
(is (write+read= data true)))) | |
(testing "clojure.data.json reads+writes analogously to jsonista and Cheshire" | |
(let [data (-> data | |
without-java-time | |
;; All these throw exceptions in c.d.j (except for :q-keyword - c.j.d drops the namespace): | |
(dissoc :uuid :character :bytes :q-keyword) | |
;; All these throw exceptions in c.d.j: | |
(update :dates dissoc :date :timestamp))] | |
(is (read+write= (clojure.data.json/write-str data) | |
(jsonista/write-value-as-string data))) | |
(is (read+write= (clojure.data.json/write-str data) | |
(cheshire/generate-string data))) | |
(is (write+read= data false)))) | |
(testing "A big object is read identically by all libs" | |
(is (->> read-fns | |
(map (fn [f] | |
(f big-test-obj))) | |
(apply =)))))) | |
(deftest top-level-array | |
(testing "Only `#'cheshire/parse-string` (and not `#'cheshire/parse-string-strict`, nor the other libs) | |
parse top-level arrays lazily" | |
(are [f expected] (testing f | |
(is (instance? expected | |
(f "[1, 2, 3]"))) | |
true) | |
jsonista/read-value PersistentVector | |
cheshire/parse-string LazySeq | |
cheshire/parse-string-strict PersistentVector | |
clojure.data.json/read-str PersistentVector))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment