Drop Expectations, migrate to clojure.test, update test.check stuff

This commit is contained in:
Peter Taoussanis 2015-12-01 13:07:38 +07:00
parent f70cfc3772
commit 5849320d3a
2 changed files with 158 additions and 133 deletions

View file

@ -28,8 +28,7 @@
:1.7 {:dependencies [[org.clojure/clojure "1.7.0"]]} :1.7 {:dependencies [[org.clojure/clojure "1.7.0"]]}
:1.8 {:dependencies [[org.clojure/clojure "1.8.0-RC2"]]} :1.8 {:dependencies [[org.clojure/clojure "1.8.0-RC2"]]}
:test {:jvm-opts ["-Xms1024m" "-Xmx2048m"] :test {:jvm-opts ["-Xms1024m" "-Xmx2048m"]
:dependencies [[expectations "2.1.4"] :dependencies [[org.clojure/test.check "0.9.0"]
[org.clojure/test.check "0.9.0"]
[org.clojure/data.fressian "0.2.1"] [org.clojure/data.fressian "0.2.1"]
[org.xerial.snappy/snappy-java "1.1.2"]]} [org.xerial.snappy/snappy-java "1.1.2"]]}
:dev [:1.7 :test :dev [:1.7 :test
@ -45,8 +44,7 @@
:source-uri "https://github.com/ptaoussanis/nippy/blob/master/{filepath}#L{line}"} :source-uri "https://github.com/ptaoussanis/nippy/blob/master/{filepath}#L{line}"}
:aliases :aliases
{"test-all" ["with-profile" "+1.5:+1.6:+1.7:+1.8" "expectations"] {"test-all" ["with-profile" "+1.5:+1.6:+1.7:+1.8" "test"]
"test-auto" ["with-profile" "+test" "autoexpect"]
"deploy-lib" ["do" "deploy" "clojars," "install"] "deploy-lib" ["do" "deploy" "clojars," "install"]
"start-dev" ["with-profile" "+server-jvm" "repl" ":headless"]} "start-dev" ["with-profile" "+server-jvm" "repl" ":headless"]}

View file

@ -1,174 +1,201 @@
(ns taoensso.nippy.tests.main (ns taoensso.nippy.tests.main
(:require [clojure.test.check :as check] (:require
[clojure.test.check.generators :as check-gen] [clojure.test :as test :refer (is are deftest run-tests)]
[clojure.test.check.properties :as check-props] [clojure.test.check :as tc]
[expectations :as test :refer :all] [clojure.test.check.generators :as tc-gens]
[taoensso.nippy :as nippy :refer (freeze thaw)] [clojure.test.check.properties :as tc-props]
[taoensso.nippy.benchmarks :as benchmarks])) [taoensso.encore :as enc :refer ()]
[taoensso.nippy :as nippy :refer (freeze thaw)]
[taoensso.nippy.benchmarks :as benchmarks]))
(comment (test/run-tests '[taoensso.nippy.tests.main])) (comment (test/run-tests))
(def test-data nippy/stress-data-comparable) (def test-data nippy/stress-data-comparable)
(defn- before-run {:expectations-options :before-run} []) (def tc-num-tests 120)
(defn- after-run {:expectations-options :after-run} []) (def tc-gens
"Like `tc-gens/any` but removes NaN (which breaks equality tests)"
(tc-gens/recursive-gen tc-gens/container-type #_simple-type
(tc-gens/one-of
[tc-gens/int tc-gens/large-integer #_tc-gens/double
(tc-gens/double* {:NaN? false})
tc-gens/char tc-gens/string tc-gens/ratio tc-gens/boolean tc-gens/keyword
tc-gens/keyword-ns tc-gens/symbol tc-gens/symbol-ns tc-gens/uuid])))
(comment (tc-gens/sample tc-gens 10))
;;;; Core ;;;; Core
(expect (do (println (str "Clojure version: " *clojure-version*)) true)) (deftest _core
(is (do (println (str "Clojure version: " *clojure-version*)) true))
(is (= test-data ((comp thaw freeze) test-data)))
(is (= test-data ((comp #(thaw % {:no-header? true
:compressor nippy/lz4-compressor
:encryptor nil})
#(freeze % {:no-header? true}))
test-data)))
(expect test-data ((comp thaw freeze) test-data)) (is (= test-data ((comp #(thaw % {:password [:salted "p"]})
(expect test-data ((comp #(thaw % {:no-header? true #(freeze % {:password [:salted "p"]}))
:compressor nippy/lz4-compressor test-data)))
:encryptor nil})
#(freeze % {:no-header? true}))
test-data))
(expect test-data ((comp #(thaw % {:password [:salted "p"]})
#(freeze % {:password [:salted "p"]}))
test-data))
(expect test-data ((comp #(thaw % {:compressor nippy/lzma2-compressor})
#(freeze % {:compressor nippy/lzma2-compressor}))
test-data))
(expect test-data ((comp #(thaw % {:compressor nippy/lzma2-compressor
:password [:salted "p"]})
#(freeze % {:compressor nippy/lzma2-compressor
:password [:salted "p"]}))
test-data))
(expect test-data ((comp #(thaw % {:compressor nippy/lz4-compressor})
#(freeze % {:compressor nippy/lz4hc-compressor}))
test-data))
(expect ; Try roundtrip anything that simple-check can dream up (is (= test-data ((comp #(thaw % {:compressor nippy/lzma2-compressor})
(:result (check/quick-check 80 ; Time is n-non-linear #(freeze % {:compressor nippy/lzma2-compressor}))
(check-props/for-all [val check-gen/any] test-data)))
(= val (thaw (freeze val)))))))
(expect Exception (thaw (freeze test-data {:password "malformed"}))) (is (= test-data ((comp #(thaw % {:compressor nippy/lzma2-compressor
(expect Exception (thaw (freeze test-data {:password [:salted "p"]}) :password [:salted "p"]})
{;; Necessary to prevent against JVM segfault due to #(freeze % {:compressor nippy/lzma2-compressor
;; https://goo.gl/t0OUIo: :password [:salted "p"]}))
:v1-compatibility? false})) test-data)))
(expect Exception (thaw (freeze test-data {:password [:salted "p"]})
{:v1-compatibility? false ; Ref. https://goo.gl/t0OUIo
:compressor nil}))
(expect ; Snappy lib compatibility (for legacy versions of Nippy) (is (= test-data ((comp #(thaw % {:compressor nippy/lz4-compressor})
(let [^bytes raw-ba (freeze test-data {:compressor nil}) #(freeze % {:compressor nippy/lz4hc-compressor}))
^bytes xerial-ba (org.xerial.snappy.Snappy/compress raw-ba) test-data)))
^bytes iq80-ba (org.iq80.snappy.Snappy/compress raw-ba)]
(= (thaw raw-ba) (is ; Try roundtrip anything that simple-check can dream up
(thaw (org.xerial.snappy.Snappy/uncompress xerial-ba)) (:result (tc/quick-check tc-num-tests
(thaw (org.xerial.snappy.Snappy/uncompress iq80-ba)) (tc-props/for-all [val tc-gens]
(thaw (org.iq80.snappy.Snappy/uncompress iq80-ba 0 (alength iq80-ba))) (= val (thaw (freeze val)))))))
(thaw (org.iq80.snappy.Snappy/uncompress xerial-ba 0 (alength xerial-ba))))))
(is (thrown? Exception (thaw (freeze test-data {:password "malformed"}))))
(is (thrown? Exception (thaw (freeze test-data {:password [:salted "p"]})
{;; Necessary to prevent against JVM segfault due to
;; https://goo.gl/t0OUIo:
:v1-compatibility? false})))
(is (thrown? Exception (thaw (freeze test-data {:password [:salted "p"]})
{:v1-compatibility? false ; Ref. https://goo.gl/t0OUIo
:compressor nil})))
(is ; 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)))))))
;;;; Custom types & records ;;;; Custom types & records
;;; Extend to custom Type (deftype MyType [data])
(defrecord MyType [data]) (defrecord MyRec [data])
(expect Exception (do (nippy/extend-freeze MyType 1 [x s] (.writeUTF s (:data x)))
(thaw (freeze (->MyType "val")))))
(expect (do (nippy/extend-thaw 1 [s] (->MyType (.readUTF s)))
(let [type (->MyType "val")] (= type (thaw (freeze type))))))
;;; Extend to custom Record (deftest _types
(defrecord MyRec [data]) ;;; Extend to custom Type
(expect (do (nippy/extend-freeze MyRec 2 [x s] (.writeUTF s (str "foo-" (:data x)))) (is (thrown? Exception ; No thaw extension yet
(nippy/extend-thaw 2 [s] (->MyRec (.readUTF s))) (do (nippy/swap-custom-readers! (constantly {}))
(= (->MyRec "foo-val") (thaw (freeze (->MyRec "val")))))) (nippy/extend-freeze MyType 1 [x s] (.writeUTF s (.data x)))
(thaw (freeze (->MyType "val"))))))
(is (do (nippy/extend-thaw 1 [s] (->MyType (.readUTF s)))
(let [mt (->MyType "val")] (= (.data ^MyType mt)
(.data ^MyType (thaw (freeze mt)))))))
;;; Keyword (prefixed) extensions ;;; Extend to custom Record
(expect (is (do (nippy/extend-freeze MyRec 2 [x s] (.writeUTF s (str "foo-" (:data x))))
(do (nippy/extend-freeze MyType :nippy-tests/MyType [x s] (.writeUTF s (:data x))) (nippy/extend-thaw 2 [s] (->MyRec (.readUTF s)))
(nippy/extend-thaw :nippy-tests/MyType [s] (->MyType (.readUTF s))) (= (->MyRec "foo-val") (thaw (freeze (->MyRec "val"))))))
(let [type (->MyType "val")] (= type (thaw (freeze type))))))
;;; Keyword (prefixed) extensions
(is
(do (nippy/extend-freeze MyRec :nippy-tests/MyRec [x s] (.writeUTF s (:data x)))
(nippy/extend-thaw :nippy-tests/MyRec [s] (->MyRec (.readUTF s)))
(let [mr (->MyRec "val")] (= mr (thaw (freeze mr)))))))
;;;; Stable binary representation of vals ;;;; Stable binary representation of vals
(expect (seq (freeze test-data)) (deftest _stable-bin
(seq (freeze test-data))) ; f(x)=f(y) | x=y
;; As above, but try multiple times to catch possible protocol interface races: (is (= (seq (freeze test-data))
(expect #(every? true? %) (seq (freeze test-data)))) ; f(x)=f(y) | x=y
;; As above, but try multiple times to catch possible protocol interface races:
(is (every? true?
(repeatedly 1000 (fn [] (= (seq (freeze test-data)) (repeatedly 1000 (fn [] (= (seq (freeze test-data))
(seq (freeze test-data)))))) (seq (freeze test-data)))))))
;; NB abandoning - no way to do this reliably w/o appropriate contracts from ;; NB abandoning - no way to do this reliably w/o appropriate contracts from
;; (seq <unordered-coll>): ;; (seq <unordered-coll>):
;; ;;
;; (expect (seq (-> test-data freeze)) ; f(x)=f(f-1(f(x))) ;; (is (= (seq (-> test-data freeze))
;; (seq (-> test-data freeze thaw freeze))) ;; (seq (-> test-data freeze thaw freeze)))) ; f(x)=f(f-1(f(x)))
;; ;;
;; As above, but with repeated refreeze to catch possible protocol interface races: ;; As above, but with repeated refreeze to catch possible protocol interface races:
;; (expect (= (seq (freeze test-data)) ;; (is (= (seq (freeze test-data))
;; (seq (reduce (fn [frozen _] (freeze (thaw frozen))) ;; (seq (reduce (fn [frozen _] (freeze (thaw frozen)))
;; (freeze test-data) (range 1000))))) ;; (freeze test-data) (range 1000)))))
)
(defn qc-prop-bijection [& [n]] (defn qc-prop-bijection [& [n]]
(let [bin->val (atom {}) (let [bin->val (atom {})
val->bin (atom {})] val->bin (atom {})]
(merge (merge
(check/quick-check (or n 1) (tc/quick-check (or n 1)
(check-props/for-all [val check-gen/any #_check-gen/any-printable] (tc-props/for-all [val tc-gens]
(let [;; Nb need `seq` for Clojure hash equality: (let [;; Nb need `seq` for Clojure hash equality:
bin (hash (seq (freeze val)))] bin (hash (seq (freeze val)))]
(and (and
(if (contains? val->bin val) (if (contains? val->bin val)
(= (get val->bin val) bin) ; x=y => f(x)=f(y) by clj= (= (get val->bin val) bin) ; x=y => f(x)=f(y) by clj=
(do (swap! val->bin assoc val bin) (do (swap! val->bin assoc val bin)
true)) true))
(if (contains? bin->val bin) (if (contains? bin->val bin)
(= (get bin->val bin) val) ; f(x)=f(y) => x=y by clj= (= (get bin->val bin) val) ; f(x)=f(y) => x=y by clj=
(do (swap! bin->val assoc bin val) (do (swap! bin->val assoc bin val)
true)))))) true))))))
#_{:bin->val @bin->val #_{:bin->val @bin->val
:val->bin @val->bin} :val->bin @val->bin}
nil))) nil)))
(comment (comment
(check-gen/sample check-gen/any 10) (tc-gens/sample tc-gens 10)
(:result (qc-prop-bijection 80)) (:result (qc-prop-bijection 80))
(let [{:keys [result bin->val val->bin]} (qc-prop-bijection 10)] (let [{:keys [result bin->val val->bin]} (qc-prop-bijection 10)]
[result (vals bin->val)])) [result (vals bin->val)]))
(expect #(:result %) (qc-prop-bijection 80)) (deftest _gc-prop-bijection
(is (:result (qc-prop-bijection tc-num-tests))))
;;;; Thread safety ;;;; Thread safety
;; Not sure why, but record equality test fails in futures: ;; Not sure why, but record equality test fails in futures:
(def test-data-threaded (dissoc nippy/stress-data-comparable :stress-record)) (def test-data-threaded (dissoc nippy/stress-data-comparable :stress-record))
(expect (deftest _thread-safe
(let [futures (is
(mapv (let [futures
(fn [_] (mapv
(future (fn [_]
(= (thaw (freeze test-data-threaded)) test-data-threaded))) (future
(range 50))] (= (thaw (freeze test-data-threaded)) test-data-threaded)))
(every? deref futures))) (range 50))]
(every? deref futures)))
(expect (is
(let [futures (let [futures
(mapv (mapv
(fn [_] (fn [_]
(future (future
(= (thaw (freeze test-data-threaded {:password [:salted "password"]}) (= (thaw (freeze test-data-threaded {:password [:salted "password"]})
{:password [:salted "password"]}) {:password [:salted "password"]})
test-data-threaded))) test-data-threaded)))
(range 50))] (range 50))]
(every? deref futures))) (every? deref futures)))
(expect (is
(let [futures (let [futures
(mapv (mapv
(fn [_] (fn [_]
(future (future
(= (thaw (freeze test-data-threaded {:password [:cached "password"]}) (= (thaw (freeze test-data-threaded {:password [:cached "password"]})
{:password [:cached "password"]}) {:password [:cached "password"]})
test-data-threaded))) test-data-threaded)))
(range 50))] (range 50))]
(every? deref futures))) (every? deref futures))))
;;;; Benchmarks ;;;; Benchmarks
(expect (benchmarks/bench {})) ; Also tests :cached passwords (deftest _benchmarks
(is (benchmarks/bench {})) ; Also tests :cached passwords
)