2013-06-12 17:00:29 +00:00
|
|
|
(ns taoensso.nippy.tests.main
|
2014-02-28 14:01:20 +00:00
|
|
|
(:require [clojure.test.check :as check]
|
|
|
|
|
[clojure.test.check.generators :as check-gen]
|
|
|
|
|
[clojure.test.check.properties :as check-props]
|
2014-01-21 08:37:19 +00:00
|
|
|
[expectations :as test :refer :all]
|
2013-06-13 05:12:28 +00:00
|
|
|
[taoensso.nippy :as nippy :refer (freeze thaw)]
|
2013-10-19 05:49:45 +00:00
|
|
|
[taoensso.nippy.benchmarks :as benchmarks]))
|
2013-06-12 17:00:29 +00:00
|
|
|
|
2014-02-23 11:52:50 +00:00
|
|
|
(comment (test/run-tests '[taoensso.nippy.tests.main]))
|
|
|
|
|
|
2014-01-21 07:33:35 +00:00
|
|
|
(def test-data nippy/stress-data-comparable)
|
2013-06-26 07:44:27 +00:00
|
|
|
(defn- before-run {:expectations-options :before-run} [])
|
|
|
|
|
(defn- after-run {:expectations-options :after-run} [])
|
|
|
|
|
|
2014-01-21 08:37:19 +00:00
|
|
|
;;;; Core
|
|
|
|
|
|
2015-09-28 07:28:47 +00:00
|
|
|
(expect (do (println (str "Clojure version: " *clojure-version*)) true))
|
|
|
|
|
|
2013-06-13 10:32:10 +00:00
|
|
|
(expect test-data ((comp thaw freeze) test-data))
|
2014-04-05 11:30:28 +00:00
|
|
|
(expect test-data ((comp #(thaw % {})
|
2014-04-05 09:56:16 +00:00
|
|
|
#(freeze % {:legacy-mode true}))
|
|
|
|
|
test-data))
|
2013-06-13 10:32:10 +00:00
|
|
|
(expect test-data ((comp #(thaw % {:password [:salted "p"]})
|
|
|
|
|
#(freeze % {:password [:salted "p"]}))
|
|
|
|
|
test-data))
|
2014-04-05 11:30:28 +00:00
|
|
|
(expect test-data ((comp #(thaw % {:compressor nippy/lzma2-compressor})
|
|
|
|
|
#(freeze % {:compressor nippy/lzma2-compressor}))
|
2013-10-19 05:49:45 +00:00
|
|
|
test-data))
|
2014-04-05 11:30:28 +00:00
|
|
|
(expect test-data ((comp #(thaw % {:compressor nippy/lzma2-compressor
|
2013-10-19 05:49:45 +00:00
|
|
|
:password [:salted "p"]})
|
2014-04-05 11:30:28 +00:00
|
|
|
#(freeze % {:compressor nippy/lzma2-compressor
|
2013-10-19 05:49:45 +00:00
|
|
|
:password [:salted "p"]}))
|
|
|
|
|
test-data))
|
2014-04-05 11:30:28 +00:00
|
|
|
(expect test-data ((comp #(thaw % {:compressor nippy/lz4-compressor})
|
|
|
|
|
#(freeze % {:compressor nippy/lz4hc-compressor}))
|
|
|
|
|
test-data))
|
2013-06-13 05:12:28 +00:00
|
|
|
|
2014-02-16 11:49:33 +00:00
|
|
|
(expect ; Try roundtrip anything that simple-check can dream up
|
2014-02-28 14:01:20 +00:00
|
|
|
(:result (check/quick-check 80 ; Time is n-non-linear
|
|
|
|
|
(check-props/for-all [val check-gen/any]
|
2015-09-14 07:37:10 +00:00
|
|
|
(= val (thaw (freeze val)))))))
|
2014-02-16 11:49:33 +00:00
|
|
|
|
2015-09-14 07:37:10 +00:00
|
|
|
;;; These can sometimes crash the JVM
|
|
|
|
|
;; (expect Exception (thaw (freeze test-data {:password "malformed"})))
|
|
|
|
|
;; (expect Exception (thaw (freeze test-data {:password [:salted "p"]})))
|
|
|
|
|
;; (expect Exception (thaw (freeze test-data {:password [:salted "p"]})
|
|
|
|
|
;; {:compressor nil}))
|
2013-06-16 10:10:19 +00:00
|
|
|
|
2013-06-13 05:12:28 +00:00
|
|
|
(expect ; Snappy lib compatibility (for legacy versions of Nippy)
|
|
|
|
|
(let [^bytes raw-ba (freeze test-data {:compressor nil})
|
|
|
|
|
^bytes xerial-ba (org.xerial.snappy.Snappy/compress raw-ba)
|
|
|
|
|
^bytes iq80-ba (org.iq80.snappy.Snappy/compress raw-ba)]
|
|
|
|
|
(= (thaw raw-ba)
|
|
|
|
|
(thaw (org.xerial.snappy.Snappy/uncompress xerial-ba))
|
|
|
|
|
(thaw (org.xerial.snappy.Snappy/uncompress iq80-ba))
|
|
|
|
|
(thaw (org.iq80.snappy.Snappy/uncompress iq80-ba 0 (alength iq80-ba)))
|
|
|
|
|
(thaw (org.iq80.snappy.Snappy/uncompress xerial-ba 0 (alength xerial-ba))))))
|
|
|
|
|
|
2014-01-21 08:37:19 +00:00
|
|
|
;;;; Custom types & records
|
2013-08-06 16:56:43 +00:00
|
|
|
|
2013-10-24 06:33:54 +00:00
|
|
|
;;; Extend to custom Type
|
2013-08-02 07:41:59 +00:00
|
|
|
(defrecord MyType [data])
|
2014-07-04 13:05:18 +00:00
|
|
|
(expect Exception (do (nippy/extend-freeze MyType 1 [x s] (.writeUTF s (:data x)))
|
|
|
|
|
(thaw (freeze (->MyType "val")))))
|
2013-08-07 09:16:35 +00:00
|
|
|
(expect (do (nippy/extend-thaw 1 [s] (->MyType (.readUTF s)))
|
|
|
|
|
(let [type (->MyType "val")] (= type (thaw (freeze type))))))
|
|
|
|
|
|
2013-10-24 06:33:54 +00:00
|
|
|
;;; Extend to custom Record
|
|
|
|
|
(defrecord MyRec [data])
|
2014-07-04 13:05:18 +00:00
|
|
|
(expect (do (nippy/extend-freeze MyRec 2 [x s] (.writeUTF s (str "foo-" (:data x))))
|
2013-08-07 09:16:35 +00:00
|
|
|
(nippy/extend-thaw 2 [s] (->MyRec (.readUTF s)))
|
2014-07-04 13:05:18 +00:00
|
|
|
(= (->MyRec "foo-val") (thaw (freeze (->MyRec "val"))))))
|
|
|
|
|
|
|
|
|
|
;;; Keyword (prefixed) extensions
|
|
|
|
|
(expect
|
|
|
|
|
(do (nippy/extend-freeze MyType :nippy-tests/MyType [x s] (.writeUTF s (:data x)))
|
|
|
|
|
(nippy/extend-thaw :nippy-tests/MyType [s] (->MyType (.readUTF s)))
|
|
|
|
|
(let [type (->MyType "val")] (= type (thaw (freeze type))))))
|
2013-07-29 08:22:31 +00:00
|
|
|
|
2014-01-21 08:37:19 +00:00
|
|
|
;;;; Stable binary representation of vals ; EXPERIMENTAL
|
|
|
|
|
|
2015-09-14 07:37:10 +00:00
|
|
|
(expect (seq (freeze test-data))
|
|
|
|
|
(seq (freeze test-data))) ; f(x)=f(y) | x=y
|
2014-01-21 08:37:19 +00:00
|
|
|
|
|
|
|
|
;;; As above, but try multiple times (catch protocol interface races):
|
|
|
|
|
(expect #(every? true? %)
|
2015-09-14 07:37:10 +00:00
|
|
|
(repeatedly 1000 (fn [] (= (seq (freeze test-data))
|
|
|
|
|
(seq (freeze test-data))))))
|
2014-01-21 08:37:19 +00:00
|
|
|
|
2015-09-14 07:37:10 +00:00
|
|
|
(expect (seq (-> test-data freeze)) ; f(x)=f(f-1(f(x)))
|
|
|
|
|
(seq (-> test-data freeze thaw freeze)))
|
2014-01-21 08:37:19 +00:00
|
|
|
|
|
|
|
|
;;; As above, but with repeated refreeze (catch protocol interface races):
|
2015-09-14 07:37:10 +00:00
|
|
|
(expect (= (seq (freeze test-data))
|
2014-01-21 08:37:19 +00:00
|
|
|
(seq (reduce (fn [frozen _] (freeze (thaw frozen)))
|
|
|
|
|
(freeze test-data) (range 1000)))))
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
|
|
|
(defn qc-prop-bijection [& [n]]
|
|
|
|
|
(let [bin->val (atom {})
|
|
|
|
|
val->bin (atom {})]
|
|
|
|
|
(merge
|
2014-02-28 14:01:20 +00:00
|
|
|
(check/quick-check (or n 1)
|
|
|
|
|
(check-props/for-all [val check-gen/any #_check-gen/any-printable]
|
2014-01-21 08:37:19 +00:00
|
|
|
(let [;; Nb need `seq` for Clojure hash equality:
|
|
|
|
|
bin (hash (seq (freeze val)))]
|
|
|
|
|
(and
|
|
|
|
|
(if (contains? val->bin val)
|
|
|
|
|
(= (get val->bin val) bin) ; x=y => f(x)=f(y) by clj=
|
|
|
|
|
(do (swap! val->bin assoc val bin)
|
|
|
|
|
true))
|
|
|
|
|
|
|
|
|
|
(if (contains? bin->val bin)
|
|
|
|
|
(= (get bin->val bin) val) ; f(x)=f(y) => x=y by clj=
|
|
|
|
|
(do (swap! bin->val assoc bin val)
|
|
|
|
|
true))))))
|
2015-09-14 07:37:10 +00:00
|
|
|
#_{:bin->val @bin->val
|
|
|
|
|
:val->bin @val->bin}
|
2014-01-21 08:37:19 +00:00
|
|
|
nil)))
|
|
|
|
|
|
|
|
|
|
(comment
|
2014-02-28 14:01:20 +00:00
|
|
|
(check-gen/sample check-gen/any 10)
|
2014-01-21 08:37:19 +00:00
|
|
|
(:result (qc-prop-bijection 80))
|
|
|
|
|
(let [{:keys [result bin->val val->bin]} (qc-prop-bijection 10)]
|
|
|
|
|
[result (vals bin->val)]))
|
|
|
|
|
|
2014-02-16 11:49:33 +00:00
|
|
|
;; (expect #(:result %) (qc-prop-bijection 120)) ; Time is n-non-linear
|
2014-01-21 08:37:19 +00:00
|
|
|
(expect #(:result %) (qc-prop-bijection 80))
|
|
|
|
|
|
2015-09-14 07:37:10 +00:00
|
|
|
;;;; Thread safety
|
|
|
|
|
|
|
|
|
|
;; Not sure why, but record equality test fails in futures:
|
|
|
|
|
(def test-data-threaded (dissoc nippy/stress-data-comparable :stress-record))
|
|
|
|
|
|
|
|
|
|
(expect
|
|
|
|
|
(let [futures
|
|
|
|
|
(mapv
|
|
|
|
|
(fn [_]
|
|
|
|
|
(future
|
|
|
|
|
(= (thaw (freeze test-data-threaded)) test-data-threaded)))
|
|
|
|
|
(range 50))]
|
|
|
|
|
(every? deref futures)))
|
|
|
|
|
|
|
|
|
|
(expect
|
|
|
|
|
(let [futures
|
|
|
|
|
(mapv
|
|
|
|
|
(fn [_]
|
|
|
|
|
(future
|
|
|
|
|
(= (thaw (freeze test-data-threaded {:password [:salted "password"]})
|
|
|
|
|
{:password [:salted "password"]})
|
|
|
|
|
test-data-threaded)))
|
|
|
|
|
(range 50))]
|
|
|
|
|
(every? deref futures)))
|
|
|
|
|
|
|
|
|
|
(expect
|
|
|
|
|
(let [futures
|
|
|
|
|
(mapv
|
|
|
|
|
(fn [_]
|
|
|
|
|
(future
|
|
|
|
|
(= (thaw (freeze test-data-threaded {:password [:cached "password"]})
|
|
|
|
|
{:password [:cached "password"]})
|
|
|
|
|
test-data-threaded)))
|
|
|
|
|
(range 50))]
|
|
|
|
|
(every? deref futures)))
|
|
|
|
|
|
2014-01-21 08:37:19 +00:00
|
|
|
;;;; Benchmarks
|
|
|
|
|
|
2015-09-14 07:08:06 +00:00
|
|
|
(expect (benchmarks/bench {})) ; Also tests :cached passwords
|