aboutsummaryrefslogtreecommitdiff
path: root/src/clojure/contrib/test_clojure/data_structures.clj
diff options
context:
space:
mode:
Diffstat (limited to 'src/clojure/contrib/test_clojure/data_structures.clj')
-rw-r--r--src/clojure/contrib/test_clojure/data_structures.clj510
1 files changed, 510 insertions, 0 deletions
diff --git a/src/clojure/contrib/test_clojure/data_structures.clj b/src/clojure/contrib/test_clojure/data_structures.clj
index 1460e75d..16cae04a 100644
--- a/src/clojure/contrib/test_clojure/data_structures.clj
+++ b/src/clojure/contrib/test_clojure/data_structures.clj
@@ -10,6 +10,276 @@
(ns clojure.contrib.test-clojure.data-structures
(:use clojure.contrib.test-is))
+;; *** Helper functions ***
+
+(defn diff [s1 s2]
+ (seq (reduce disj (set s1) (set s2))))
+
+
+;; *** General ***
+
+(defstruct equality-struct :a :b)
+
+(deftest test-equality
+ ; nil is not equal to any other value
+ (are (not (= nil _))
+ true false
+ 0 0.0
+ \space
+ "" #""
+ () [] #{} {}
+ (new Object) )
+
+ ; numbers equality across types (see tests below - NOT IMPLEMENTED YET)
+
+ ; ratios
+ (is (= 1/2 0.5))
+ (is (= 1/1000 0.001))
+ (is (not= 2/3 0.6666666666666666))
+
+ ; vectors equal other seqs by items equality
+ (are (= _1 _2)
+ '() [] ; regression fixed in r1208; was not equal
+ '(1) [1]
+ '(1 2) [1 2]
+
+ [] '() ; same again, but vectors first
+ [1] '(1)
+ [1 2] '(1 2) )
+ (is (not= [1 2] '(2 1))) ; order of items matters
+
+ ; list and vector vs. set and map
+ (are (not= _1 _2)
+ ; only () equals []
+ () #{}
+ () {}
+ [] #{}
+ [] {}
+ #{} {}
+ ; only '(1) equals [1]
+ '(1) #{1}
+ [1] #{1} )
+
+ ; sorted-map, hash-map and array-map - classes differ, but maps they are equal
+ (is (not= (class (sorted-map :a 1)) (class (hash-map :a 1))))
+ (is (not= (class (sorted-map :a 1)) (class (array-map :a 1))))
+ (is (not= (class (hash-map :a 1)) (class (array-map :a 1))))
+ (are (= _1 _2 _3)
+ (sorted-map) (hash-map) (array-map)
+ (sorted-map :a 1) (hash-map :a 1) (array-map :a 1)
+ (sorted-map :a 1 :z 3 :c 2) (hash-map :a 1 :z 3 :c 2) (array-map :a 1 :z 3 :c 2))
+
+ ; struct-map vs. sorted-map, hash-map and array-map
+ (is (not= (class (struct equality-struct 1 2)) (class (sorted-map :a 1 :b 2))))
+ (is (not= (class (struct equality-struct 1 2)) (class (hash-map :a 1 :b 2))))
+ (is (not= (class (struct equality-struct 1 2)) (class (array-map :a 1 :b 2))))
+ (are (= (struct equality-struct 1 2) _)
+ (sorted-map :a 1 :b 2)
+ (hash-map :a 1 :b 2)
+ (array-map :a 1 :b 2) )
+
+ ; sorted-set and hash-set are equal
+ (is (not= (class (sorted-set 1)) (class (hash-set 1))))
+ (are (= _1 _2)
+ (sorted-set) (hash-set)
+ (sorted-set 1) (hash-set 1)
+ (sorted-set 3 2 1) (hash-set 3 2 1) ))
+
+
+;; *** Collections ***
+
+(deftest test-count
+ (are (= _1 _2)
+ (count nil) 0
+
+ (count ()) 0
+ (count '(1)) 1
+ (count '(1 2 3)) 3
+
+ (count []) 0
+ (count [1]) 1
+ (count [1 2 3]) 3
+
+ (count #{}) 0
+ (count #{1}) 1
+ (count #{1 2 3}) 3
+
+ (count {}) 0
+ (count {:a 1}) 1
+ (count {:a 1 :b 2 :c 3}) 3
+
+ (count "") 0
+ (count "a") 1
+ (count "abc") 3
+
+ (count (into-array [])) 0
+ (count (into-array [1])) 1
+ (count (into-array [1 2 3])) 3
+
+ (count (java.util.ArrayList. [])) 0
+ (count (java.util.ArrayList. [1])) 1
+ (count (java.util.ArrayList. [1 2 3])) 3
+
+ (count (java.util.HashMap. {})) 0
+ (count (java.util.HashMap. {:a 1})) 1
+ (count (java.util.HashMap. {:a 1 :b 2 :c 3})) 3 )
+
+ ; different types
+ (are (= (count [_]) 1)
+ nil true false
+ 0 0.0 "" \space
+ () [] #{} {} ))
+
+
+(deftest test-conj
+ ; doesn't work on strings or arrays
+ (is (thrown? ClassCastException (conj "" \a)))
+ (is (thrown? ClassCastException (conj (into-array []) 1)))
+
+ (are (= _1 _2)
+ (conj nil 1) '(1)
+ (conj nil 3 2 1) '(1 2 3)
+
+ (conj nil nil) '(nil)
+ (conj nil nil nil) '(nil nil)
+ (conj nil nil nil 1) '(1 nil nil)
+
+ ; list -> conj puts the item at the front of the list
+ (conj () 1) '(1)
+ (conj () 1 2) '(2 1)
+
+ (conj '(2 3) 1) '(1 2 3)
+ (conj '(2 3) 1 4 3) '(3 4 1 2 3)
+
+ (conj () nil) '(nil)
+ (conj () ()) '(())
+
+ ; vector -> conj puts the item at the end of the vector
+ (conj [] 1) [1]
+ (conj [] 1 2) [1 2]
+
+ (conj [2 3] 1) [2 3 1]
+ (conj [2 3] 1 4 3) [2 3 1 4 3]
+
+ (conj [] nil) [nil]
+ (conj [] []) [[]]
+
+ ; map -> conj expects another (possibly single entry) map as the item,
+ ; and returns a new map which is the old map plus the entries
+ ; from the new, which may overwrite entries of the old.
+ ; conj also accepts a MapEntry or a vector of two items (key and value).
+ (conj {} {}) {}
+ (conj {} {:a 1}) {:a 1}
+ (conj {} {:a 1 :b 2}) {:a 1 :b 2}
+ (conj {} {:a 1 :b 2} {:c 3}) {:a 1 :b 2 :c 3}
+ (conj {} {:a 1 :b 2} {:a 3 :c 4}) {:a 3 :b 2 :c 4}
+
+ (conj {:a 1} {:a 7}) {:a 7}
+ (conj {:a 1} {:b 2}) {:a 1 :b 2}
+ (conj {:a 1} {:a 7 :b 2}) {:a 7 :b 2}
+ (conj {:a 1} {:a 7 :b 2} {:c 3}) {:a 7 :b 2 :c 3}
+ (conj {:a 1} {:a 7 :b 2} {:b 4 :c 5}) {:a 7 :b 4 :c 5}
+
+ (conj {} (first {:a 1})) {:a 1} ; MapEntry
+ (conj {:a 1} (first {:b 2})) {:a 1 :b 2}
+ (conj {:a 1} (first {:a 7})) {:a 7}
+ (conj {:a 1} (first {:b 2}) (first {:a 5})) {:a 5 :b 2}
+
+ (conj {} [:a 1]) {:a 1} ; vector
+ (conj {:a 1} [:b 2]) {:a 1 :b 2}
+ (conj {:a 1} [:a 7]) {:a 7}
+ (conj {:a 1} [:b 2] [:a 5]) {:a 5 :b 2}
+
+ (conj {} {nil {}}) {nil {}}
+ (conj {} {{} nil}) {{} nil}
+ (conj {} {{} {}}) {{} {}}
+
+ ; set
+ (conj #{} 1) #{1}
+ (conj #{} 1 2 3) #{1 2 3}
+
+ (conj #{2 3} 1) #{3 1 2}
+ (conj #{3 2} 1) #{1 2 3}
+
+ (conj #{2 3} 2) #{2 3}
+ (conj #{2 3} 2 3) #{2 3}
+ (conj #{2 3} 4 1 2 3) #{1 2 3 4}
+
+ (conj #{} nil) #{nil}
+ (conj #{} #{}) #{#{}} ))
+
+
+;; *** Lists and Vectors ***
+
+(deftest test-peek
+ ; doesn't work for sets and maps
+ (is (thrown? ClassCastException (peek #{1})))
+ (is (thrown? ClassCastException (peek {:a 1})))
+
+ (are (= _1 _2)
+ (peek nil) nil
+
+ ; list = first
+ (peek ()) nil
+ (peek '(1)) 1
+ (peek '(1 2 3)) 1
+
+ (peek '(nil)) nil ; special cases
+ (peek '(1 nil)) 1
+ (peek '(nil 2)) nil
+ (peek '(())) ()
+ (peek '(() nil)) ()
+ (peek '(() 2 nil)) ()
+
+ ; vector = last
+ (peek []) nil
+ (peek [1]) 1
+ (peek [1 2 3]) 3
+
+ (peek [nil]) nil ; special cases
+ (peek [1 nil]) nil
+ (peek [nil 2]) 2
+ (peek [[]]) []
+ (peek [[] nil]) nil
+ (peek [[] 2 nil]) nil ))
+
+
+(deftest test-pop
+ ; doesn't work for sets and maps
+ (is (thrown? ClassCastException (pop #{1})))
+ (is (thrown? ClassCastException (pop #{:a 1})))
+
+ ; collection cannot be empty
+ (is (thrown? IllegalStateException (pop ())))
+ (is (thrown? IllegalStateException (pop [])))
+
+ (are (= _1 _2)
+ (pop nil) nil
+
+ ; list - pop first
+ (pop '(1)) ()
+ (pop '(1 2 3)) '(2 3)
+
+ (pop '(nil)) ()
+ (pop '(1 nil)) '(nil)
+ (pop '(nil 2)) '(2)
+ (pop '(())) ()
+ (pop '(() nil)) '(nil)
+ (pop '(() 2 nil)) '(2 nil)
+
+ ; vector - pop last
+ (pop [1]) []
+ (pop [1 2 3]) [1 2]
+
+ (pop [nil]) []
+ (pop [1 nil]) [1]
+ (pop [nil 2]) [nil]
+ (pop [[]]) []
+ (pop [[] nil]) [[]]
+ (pop [[] 2 nil]) [[] 2] ))
+
+
+;; *** Lists (IPersistentList) ***
(deftest test-list
(are (list? _)
@@ -54,6 +324,94 @@
(list () 2) '(() 2) ))
+;; *** Maps (IPersistentMap) ***
+
+(deftest test-keys
+ (are (= _1 _2) ; other than map data structures
+ (keys ()) nil
+ (keys []) nil
+ (keys #{}) nil
+ (keys "") nil )
+
+ (are (= _1 _2)
+ ; (class {:a 1}) => clojure.lang.PersistentArrayMap
+ (keys {}) nil
+ (keys {:a 1}) '(:a)
+ (diff (keys {:a 1 :b 2}) '(:a :b)) nil ; (keys {:a 1 :b 2}) '(:a :b)
+
+ ; (class (sorted-map :a 1)) => clojure.lang.PersistentTreeMap
+ (keys (sorted-map)) nil
+ (keys (sorted-map :a 1)) '(:a)
+ (diff (keys (sorted-map :a 1 :b 2)) '(:a :b)) nil ; (keys (sorted-map :a 1 :b 2)) '(:a :b)
+
+ ; (class (hash-map :a 1)) => clojure.lang.PersistentHashMap
+ (keys (hash-map)) nil
+ (keys (hash-map :a 1)) '(:a)
+ (diff (keys (hash-map :a 1 :b 2)) '(:a :b)) nil )) ; (keys (hash-map :a 1 :b 2)) '(:a :b)
+
+
+(deftest test-vals
+ (are (= _1 _2) ; other than map data structures
+ (vals ()) nil
+ (vals []) nil
+ (vals #{}) nil
+ (vals "") nil )
+
+ (are (= _1 _2)
+ ; (class {:a 1}) => clojure.lang.PersistentArrayMap
+ (vals {}) nil
+ (vals {:a 1}) '(1)
+ (diff (vals {:a 1 :b 2}) '(1 2)) nil ; (vals {:a 1 :b 2}) '(1 2)
+
+ ; (class (sorted-map :a 1)) => clojure.lang.PersistentTreeMap
+ (vals (sorted-map)) nil
+ (vals (sorted-map :a 1)) '(1)
+ (diff (vals (sorted-map :a 1 :b 2)) '(1 2)) nil ; (vals (sorted-map :a 1 :b 2)) '(1 2)
+
+ ; (class (hash-map :a 1)) => clojure.lang.PersistentHashMap
+ (vals (hash-map)) nil
+ (vals (hash-map :a 1)) '(1)
+ (diff (vals (hash-map :a 1 :b 2)) '(1 2)) nil )) ; (vals (hash-map :a 1 :b 2)) '(1 2)
+
+
+(deftest test-key
+ (are (= (key (first (hash-map _ :value))) _)
+ nil
+ false true
+ 0 42
+ 0.0 3.14
+ 2/3
+ 0M 1M
+ \c
+ "" "abc"
+ 'sym
+ :kw
+ () '(1 2)
+ [] [1 2]
+ {} {:a 1 :b 2}
+ #{} #{1 2} ))
+
+
+(deftest test-val
+ (are (= (val (first (hash-map :key _))) _)
+ nil
+ false true
+ 0 42
+ 0.0 3.14
+ 2/3
+ 0M 1M
+ \c
+ "" "abc"
+ 'sym
+ :kw
+ () '(1 2)
+ [] [1 2]
+ {} {:a 1 :b 2}
+ #{} #{1 2} ))
+
+
+;; *** Sets ***
+
(deftest test-hash-set
(are (set? _)
#{}
@@ -120,3 +478,155 @@
(hash-set 1 #{}) #{1 #{}}
(hash-set #{} 2) #{#{} 2} ))
+
+(deftest test-sorted-set
+ ; only compatible types can be used
+ (is (thrown? ClassCastException (sorted-set 1 "a")))
+ (is (thrown? ClassCastException (sorted-set '(1 2) [3 4])))
+
+ ; creates set?
+ (are (set? _)
+ (sorted-set)
+ (sorted-set 1 2) )
+
+ ; equal and unique
+ (are (and (= (sorted-set _) #{_})
+ (= (sorted-set _ _) (sorted-set _)))
+ nil
+ false true
+ 0 42
+ 0.0 3.14
+ 2/3
+ 0M 1M
+ \c
+ "" "abc"
+ 'sym
+ :kw
+ () ; '(1 2)
+ [] [1 2]
+ {} ; {:a 1 :b 2}
+ #{} ; #{1 2}
+ )
+ ; cannot be cast to java.lang.Comparable
+ (is (thrown? ClassCastException (sorted-set '(1 2) '(1 2))))
+ (is (thrown? ClassCastException (sorted-set {:a 1 :b 2} {:a 1 :b 2})))
+ (is (thrown? ClassCastException (sorted-set #{1 2} #{1 2})))
+
+ (are (= _1 _2)
+ ; generating
+ (sorted-set) #{}
+ (sorted-set 1) #{1}
+ (sorted-set 1 2) #{1 2}
+
+ ; sorting
+ (seq (sorted-set 5 4 3 2 1)) '(1 2 3 4 5)
+
+ ; special cases
+ (sorted-set nil) #{nil}
+ (sorted-set 1 nil) #{nil 1}
+ (sorted-set nil 2) #{nil 2}
+ (sorted-set #{}) #{#{}} ))
+
+
+(deftest test-set
+ ; set?
+ (are (set? (set _))
+ () '(1 2)
+ [] [1 2]
+ #{} #{1 2}
+ {} {:a 1 :b 2}
+ (into-array []) (into-array [1 2])
+ "" "abc" )
+
+ ; unique
+ (are (= (set [_ _]) #{_})
+ nil
+ false true
+ 0 42
+ 0.0 3.14
+ 2/3
+ 0M 1M
+ \c
+ "" "abc"
+ 'sym
+ :kw
+ () '(1 2)
+ [] [1 2]
+ {} {:a 1 :b 2}
+ #{} #{1 2} )
+
+ ; conversion
+ (are (= (set _1) _2)
+ () #{}
+ '(1 2) #{1 2}
+
+ [] #{}
+ [1 2] #{1 2}
+
+ #{} #{} ; identity
+ #{1 2} #{1 2} ; identity
+
+ {} #{}
+ {:a 1 :b 2} #{[:a 1] [:b 2]}
+
+ (into-array []) #{}
+ (into-array [1 2]) #{1 2}
+
+ "" #{}
+ "abc" #{\a \b \c} ))
+
+
+(deftest test-disj
+ ; doesn't work on lists, vectors or maps
+ (is (thrown? ClassCastException (disj '(1 2) 1)))
+ (is (thrown? ClassCastException (disj [1 2] 1)))
+ (is (thrown? ClassCastException (disj {:a 1} :a)))
+
+ ; identity
+ (are (= (disj _) _)
+ #{}
+ #{1 2 3}
+ ; different data types
+ #{nil
+ false true
+ 0 42
+ 0.0 3.14
+ 2/3
+ 0M 1M
+ \c
+ "" "abc"
+ 'sym
+ :kw
+ [] [1 2]
+ {} {:a 1 :b 2}
+ #{} #{1 2}} )
+
+ ; type identity
+ (are (= (class (disj _)) (class _))
+ (hash-set)
+ (hash-set 1 2)
+ (sorted-set)
+ (sorted-set 1 2) )
+
+ (are (= _1 _2)
+ (disj #{} :a) #{}
+ (disj #{} :a :b) #{}
+
+ (disj #{:a} :a) #{}
+ (disj #{:a} :a :b) #{}
+ (disj #{:a} :c) #{:a}
+
+ (disj #{:a :b :c :d} :a) #{:b :c :d}
+ (disj #{:a :b :c :d} :a :d) #{:b :c}
+ (disj #{:a :b :c :d} :a :b :c) #{:d}
+ (disj #{:a :b :c :d} :d :a :c :b) #{}
+
+ (disj #{nil} :a) #{nil}
+ (disj #{nil} #{}) #{nil}
+ (disj #{nil} nil) #{}
+
+ (disj #{#{}} nil) #{#{}}
+ (disj #{#{}} #{}) #{}
+ (disj #{#{nil}} #{nil}) #{} ))
+
+