rlm@10
|
1 ; Copyright (c) Rich Hickey. All rights reserved.
|
rlm@10
|
2 ; The use and distribution terms for this software are covered by the
|
rlm@10
|
3 ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
|
rlm@10
|
4 ; which can be found in the file epl-v10.html at the root of this distribution.
|
rlm@10
|
5 ; By using this software in any fashion, you are agreeing to be bound by
|
rlm@10
|
6 ; the terms of this license.
|
rlm@10
|
7 ; You must not remove this notice, or any other, from this software.
|
rlm@10
|
8
|
rlm@10
|
9 ;; Author: Chas Emerick
|
rlm@10
|
10 ;; cemerick@snowtide.com
|
rlm@10
|
11
|
rlm@10
|
12 (ns clojure.test-clojure.serialization
|
rlm@10
|
13 (:use clojure.test)
|
rlm@10
|
14 (:import (java.io ObjectOutputStream ObjectInputStream
|
rlm@10
|
15 ByteArrayOutputStream ByteArrayInputStream)))
|
rlm@10
|
16
|
rlm@10
|
17 (defn- serialize
|
rlm@10
|
18 "Serializes a single object, returning a byte array."
|
rlm@10
|
19 [v]
|
rlm@10
|
20 (with-open [bout (ByteArrayOutputStream.)
|
rlm@10
|
21 oos (ObjectOutputStream. bout)]
|
rlm@10
|
22 (.writeObject oos v)
|
rlm@10
|
23 (.flush oos)
|
rlm@10
|
24 (.toByteArray bout)))
|
rlm@10
|
25
|
rlm@10
|
26 (defn- deserialize
|
rlm@10
|
27 "Deserializes and returns a single object from the given byte array."
|
rlm@10
|
28 [bytes]
|
rlm@10
|
29 (with-open [ois (-> bytes ByteArrayInputStream. ObjectInputStream.)]
|
rlm@10
|
30 (.readObject ois)))
|
rlm@10
|
31
|
rlm@10
|
32 (defrecord SerializationRecord [a b c])
|
rlm@10
|
33 (defstruct SerializationStruct :a :b :c)
|
rlm@10
|
34
|
rlm@10
|
35 (defn- build-via-transient
|
rlm@10
|
36 [coll]
|
rlm@10
|
37 (persistent!
|
rlm@10
|
38 (reduce conj! (transient coll) (map vec (partition 2 (range 1000))))))
|
rlm@10
|
39
|
rlm@10
|
40 (defn- roundtrip
|
rlm@10
|
41 [v]
|
rlm@10
|
42 (let [rt (-> v serialize deserialize)
|
rlm@10
|
43 rt-seq (-> v seq serialize deserialize)]
|
rlm@10
|
44 (and (= v rt)
|
rlm@10
|
45 (= (seq v) (seq rt))
|
rlm@10
|
46 (= (seq v) rt-seq))))
|
rlm@10
|
47
|
rlm@10
|
48 (deftest sequable-serialization
|
rlm@10
|
49 (are [val] (roundtrip val)
|
rlm@10
|
50 ; lists and related
|
rlm@10
|
51 (list)
|
rlm@10
|
52 (apply list (range 10))
|
rlm@10
|
53 (cons 0 nil)
|
rlm@10
|
54 (clojure.lang.Cons. 0 nil)
|
rlm@10
|
55
|
rlm@10
|
56 ; vectors
|
rlm@10
|
57 []
|
rlm@10
|
58 (into [] (range 10))
|
rlm@10
|
59 (into [] (range 25))
|
rlm@10
|
60 (into [] (range 100))
|
rlm@10
|
61 (into [] (range 500))
|
rlm@10
|
62 (into [] (range 1000))
|
rlm@10
|
63
|
rlm@10
|
64 ; maps
|
rlm@10
|
65 {}
|
rlm@10
|
66 {:a 5 :b 0}
|
rlm@10
|
67 (apply array-map (range 100))
|
rlm@10
|
68 (apply hash-map (range 100))
|
rlm@10
|
69
|
rlm@10
|
70 ; sets
|
rlm@10
|
71 #{}
|
rlm@10
|
72 #{'a 'b 'c}
|
rlm@10
|
73 (set (range 10))
|
rlm@10
|
74 (set (range 25))
|
rlm@10
|
75 (set (range 100))
|
rlm@10
|
76 (set (range 500))
|
rlm@10
|
77 (set (range 1000))
|
rlm@10
|
78 (sorted-set)
|
rlm@10
|
79 (sorted-set 'a 'b 'c)
|
rlm@10
|
80 (apply sorted-set (reverse (range 10)))
|
rlm@10
|
81 (apply sorted-set (reverse (range 25)))
|
rlm@10
|
82 (apply sorted-set (reverse (range 100)))
|
rlm@10
|
83 (apply sorted-set (reverse (range 500)))
|
rlm@10
|
84 (apply sorted-set (reverse (range 1000)))
|
rlm@10
|
85
|
rlm@10
|
86 ; queues
|
rlm@10
|
87 clojure.lang.PersistentQueue/EMPTY
|
rlm@10
|
88 (into clojure.lang.PersistentQueue/EMPTY (range 50))
|
rlm@10
|
89
|
rlm@10
|
90 ; lazy seqs
|
rlm@10
|
91 (lazy-seq nil)
|
rlm@10
|
92 (lazy-seq (range 50))
|
rlm@10
|
93
|
rlm@10
|
94 ; transient / persistent! round-trip
|
rlm@10
|
95 (build-via-transient [])
|
rlm@10
|
96 (build-via-transient {})
|
rlm@10
|
97 (build-via-transient #{})
|
rlm@10
|
98
|
rlm@10
|
99 ; array-seqs
|
rlm@10
|
100 (seq (make-array Object 10))
|
rlm@10
|
101 (seq (make-array Boolean/TYPE 10))
|
rlm@10
|
102 (seq (make-array Byte/TYPE 10))
|
rlm@10
|
103 (seq (make-array Character/TYPE 10))
|
rlm@10
|
104 (seq (make-array Double/TYPE 10))
|
rlm@10
|
105 (seq (make-array Float/TYPE 10))
|
rlm@10
|
106 (seq (make-array Integer/TYPE 10))
|
rlm@10
|
107 (seq (make-array Long/TYPE 10))
|
rlm@10
|
108
|
rlm@10
|
109 ; "records"
|
rlm@10
|
110 (SerializationRecord. 0 :foo (range 20))
|
rlm@10
|
111 (struct SerializationStruct 0 :foo (range 20))
|
rlm@10
|
112
|
rlm@10
|
113 ; misc seqs
|
rlm@10
|
114 (seq "s11n")
|
rlm@10
|
115 (range 50)
|
rlm@10
|
116 (rseq (apply sorted-set (reverse (range 100))))))
|
rlm@10
|
117
|
rlm@10
|
118 (deftest misc-serialization
|
rlm@10
|
119 (are [v] (= v (-> v serialize deserialize))
|
rlm@10
|
120 25/3
|
rlm@10
|
121 :keyword
|
rlm@10
|
122 ::namespaced-keyword
|
rlm@10
|
123 'symbol))
|
rlm@10
|
124
|
rlm@10
|
125 (deftest interned-serializations
|
rlm@10
|
126 (are [v] (identical? v (-> v serialize deserialize))
|
rlm@10
|
127 clojure.lang.RT/DEFAULT_COMPARATOR
|
rlm@10
|
128
|
rlm@10
|
129 ; namespaces just get deserialized back into the same-named ns in the present runtime
|
rlm@10
|
130 ; (they're referred to by defrecord instances)
|
rlm@10
|
131 *ns*))
|
rlm@10
|
132
|
rlm@10
|
133 (deftest function-serialization
|
rlm@10
|
134 (let [capture 5]
|
rlm@10
|
135 (are [f] (= capture ((-> f serialize deserialize)))
|
rlm@10
|
136 (constantly 5)
|
rlm@10
|
137 (fn [] 5)
|
rlm@10
|
138 #(do 5)
|
rlm@10
|
139 (constantly capture)
|
rlm@10
|
140 (fn [] capture)
|
rlm@10
|
141 #(do capture))))
|
rlm@10
|
142
|
rlm@10
|
143 (deftest check-unserializable-objects
|
rlm@10
|
144 (are [t] (thrown? java.io.NotSerializableException (serialize t))
|
rlm@10
|
145 ;; transients
|
rlm@10
|
146 (transient [])
|
rlm@10
|
147 (transient {})
|
rlm@10
|
148 (transient #{})
|
rlm@10
|
149
|
rlm@10
|
150 ;; reference types
|
rlm@10
|
151 (atom nil)
|
rlm@10
|
152 (ref nil)
|
rlm@10
|
153 (agent nil)
|
rlm@10
|
154 #'+
|
rlm@10
|
155
|
rlm@10
|
156 ;; stateful seqs
|
rlm@10
|
157 (enumeration-seq (java.util.Collections/enumeration (range 50)))
|
rlm@10
|
158 (iterator-seq (.iterator (range 50))))) |