summaryrefslogtreecommitdiff
path: root/test/clojure/test_clojure
diff options
context:
space:
mode:
Diffstat (limited to 'test/clojure/test_clojure')
-rw-r--r--test/clojure/test_clojure/agents.clj41
-rw-r--r--test/clojure/test_clojure/atoms.clj18
-rw-r--r--test/clojure/test_clojure/clojure_set.clj117
-rw-r--r--test/clojure/test_clojure/clojure_xml.clj18
-rw-r--r--test/clojure/test_clojure/clojure_zip.clj45
-rw-r--r--test/clojure/test_clojure/compilation.clj36
-rw-r--r--test/clojure/test_clojure/control.clj114
-rw-r--r--test/clojure/test_clojure/data_structures.clj734
-rw-r--r--test/clojure/test_clojure/evaluation.clj230
-rw-r--r--test/clojure/test_clojure/for.clj123
-rw-r--r--test/clojure/test_clojure/java_interop.clj404
-rw-r--r--test/clojure/test_clojure/logic.clj202
-rw-r--r--test/clojure/test_clojure/macros.clj16
-rw-r--r--test/clojure/test_clojure/metadata.clj17
-rw-r--r--test/clojure/test_clojure/multimethods.clj25
-rw-r--r--test/clojure/test_clojure/ns_libs.clj26
-rw-r--r--test/clojure/test_clojure/numbers.clj390
-rw-r--r--test/clojure/test_clojure/other_functions.clj57
-rw-r--r--test/clojure/test_clojure/parallel.clj26
-rw-r--r--test/clojure/test_clojure/predicates.clj139
-rw-r--r--test/clojure/test_clojure/printer.clj81
-rw-r--r--test/clojure/test_clojure/reader.clj203
-rw-r--r--test/clojure/test_clojure/refs.clj19
-rw-r--r--test/clojure/test_clojure/sequences.clj982
-rw-r--r--test/clojure/test_clojure/special.clj21
-rw-r--r--test/clojure/test_clojure/test.clj113
-rw-r--r--test/clojure/test_clojure/test_fixtures.clj42
-rw-r--r--test/clojure/test_clojure/test_utils.clj30
-rw-r--r--test/clojure/test_clojure/vars.clj34
29 files changed, 4303 insertions, 0 deletions
diff --git a/test/clojure/test_clojure/agents.clj b/test/clojure/test_clojure/agents.clj
new file mode 100644
index 00000000..044e68ee
--- /dev/null
+++ b/test/clojure/test_clojure/agents.clj
@@ -0,0 +1,41 @@
+;; Copyright (c) Shawn Hoover. All rights reserved. The use and
+;; distribution terms for this software are covered by the Eclipse Public
+;; License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which can
+;; be found in the file epl-v10.html at the root of this distribution. By
+;; using this software in any fashion, you are agreeing to be bound by the
+;; terms of this license. You must not remove this notice, or any other,
+;; from this software.
+
+(ns clojure.test-clojure.agents
+ (:use clojure.test))
+
+(deftest handle-all-throwables-during-agent-actions
+ ;; Bug fixed in r1198; previously hung Clojure or didn't report agent errors
+ ;; after OutOfMemoryError, yet wouldn't execute new actions.
+ (let [agt (agent nil)]
+ (send agt (fn [state] (throw (Throwable. "just testing Throwables"))))
+ (try
+ ;; Let the action finish; eat the "agent has errors" error that bubbles up
+ (await agt)
+ (catch RuntimeException _))
+ (is (instance? Throwable (first (agent-errors agt))))
+ (is (= 1 (count (agent-errors agt))))
+
+ ;; And now send an action that should work
+ (clear-agent-errors agt)
+ (is (= nil @agt))
+ (send agt nil?)
+ (await agt)
+ (is (true? @agt))))
+
+
+; http://clojure.org/agents
+
+; agent
+; deref, @-reader-macro, agent-errors
+; send send-off clear-agent-errors
+; await await-for
+; set-validator get-validator
+; add-watch remove-watch
+; shutdown-agents
+
diff --git a/test/clojure/test_clojure/atoms.clj b/test/clojure/test_clojure/atoms.clj
new file mode 100644
index 00000000..7ac36fcc
--- /dev/null
+++ b/test/clojure/test_clojure/atoms.clj
@@ -0,0 +1,18 @@
+;; Copyright (c) Frantisek Sodomka. All rights reserved. The use and
+;; distribution terms for this software are covered by the Eclipse Public
+;; License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which can
+;; be found in the file epl-v10.html at the root of this distribution. By
+;; using this software in any fashion, you are agreeing to be bound by the
+;; terms of this license. You must not remove this notice, or any other,
+;; from this software.
+
+(ns clojure.test-clojure.atoms
+ (:use clojure.test))
+
+; http://clojure.org/atoms
+
+; atom
+; deref, @-reader-macro
+; swap! reset!
+; compare-and-set!
+
diff --git a/test/clojure/test_clojure/clojure_set.clj b/test/clojure/test_clojure/clojure_set.clj
new file mode 100644
index 00000000..9faf3410
--- /dev/null
+++ b/test/clojure/test_clojure/clojure_set.clj
@@ -0,0 +1,117 @@
+;; Copyright (c) Frantisek Sodomka. All rights reserved. The use and
+;; distribution terms for this software are covered by the Eclipse Public
+;; License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which can
+;; be found in the file epl-v10.html at the root of this distribution. By
+;; using this software in any fashion, you are agreeing to be bound by the
+;; terms of this license. You must not remove this notice, or any other,
+;; from this software.
+
+(ns clojure.test-clojure.clojure-set
+ (:use clojure.test)
+ (:require [clojure.set :as set]))
+
+
+(deftest test-union
+ (are [x y] (= x y)
+ (set/union) #{}
+
+ ; identity
+ (set/union #{}) #{}
+ (set/union #{1}) #{1}
+ (set/union #{1 2 3}) #{1 2 3}
+
+ ; 2 sets, at least one is empty
+ (set/union #{} #{}) #{}
+ (set/union #{} #{1}) #{1}
+ (set/union #{} #{1 2 3}) #{1 2 3}
+ (set/union #{1} #{}) #{1}
+ (set/union #{1 2 3} #{}) #{1 2 3}
+
+ ; 2 sets
+ (set/union #{1} #{2}) #{1 2}
+ (set/union #{1} #{1 2}) #{1 2}
+ (set/union #{2} #{1 2}) #{1 2}
+ (set/union #{1 2} #{3}) #{1 2 3}
+ (set/union #{1 2} #{2 3}) #{1 2 3}
+
+ ; 3 sets, some are empty
+ (set/union #{} #{} #{}) #{}
+ (set/union #{1} #{} #{}) #{1}
+ (set/union #{} #{1} #{}) #{1}
+ (set/union #{} #{} #{1}) #{1}
+ (set/union #{1 2} #{2 3} #{}) #{1 2 3}
+
+ ; 3 sets
+ (set/union #{1 2} #{3 4} #{5 6}) #{1 2 3 4 5 6}
+ (set/union #{1 2} #{2 3} #{1 3 4}) #{1 2 3 4}
+
+ ; different data types
+ (set/union #{1 2} #{:a :b} #{nil} #{false true} #{\c "abc"} #{[] [1 2]}
+ #{{} {:a 1}} #{#{} #{1 2}})
+ #{1 2 :a :b nil false true \c "abc" [] [1 2] {} {:a 1} #{} #{1 2}}
+
+ ; different types of sets
+ (set/union (hash-set) (hash-set 1 2) (hash-set 2 3))
+ (hash-set 1 2 3)
+ (set/union (sorted-set) (sorted-set 1 2) (sorted-set 2 3))
+ (sorted-set 1 2 3)
+ (set/union (hash-set) (hash-set 1 2) (hash-set 2 3)
+ (sorted-set) (sorted-set 4 5) (sorted-set 5 6))
+ (hash-set 1 2 3 4 5 6) ; also equals (sorted-set 1 2 3 4 5 6)
+))
+
+
+(deftest test-intersection
+ ; at least one argument is needed
+ (is (thrown? IllegalArgumentException (set/intersection)))
+
+ (are [x y] (= x y)
+ ; identity
+ (set/intersection #{}) #{}
+ (set/intersection #{1}) #{1}
+ (set/intersection #{1 2 3}) #{1 2 3}
+
+ ; 2 sets, at least one is empty
+ (set/intersection #{} #{}) #{}
+ (set/intersection #{} #{1}) #{}
+ (set/intersection #{} #{1 2 3}) #{}
+ (set/intersection #{1} #{}) #{}
+ (set/intersection #{1 2 3} #{}) #{}
+
+ ; 2 sets
+ (set/intersection #{1 2} #{1 2}) #{1 2}
+ (set/intersection #{1 2} #{3 4}) #{}
+ (set/intersection #{1 2} #{1}) #{1}
+ (set/intersection #{1 2} #{2}) #{2}
+ (set/intersection #{1 2 4} #{2 3 4 5}) #{2 4}
+
+ ; 3 sets, some are empty
+ (set/intersection #{} #{} #{}) #{}
+ (set/intersection #{1} #{} #{}) #{}
+ (set/intersection #{1} #{1} #{}) #{}
+ (set/intersection #{1} #{} #{1}) #{}
+ (set/intersection #{1 2} #{2 3} #{}) #{}
+
+ ; 3 sets
+ (set/intersection #{1 2} #{2 3} #{5 2}) #{2}
+ (set/intersection #{1 2 3} #{1 3 4} #{1 3}) #{1 3}
+ (set/intersection #{1 2 3} #{3 4 5} #{8 2 3}) #{3}
+
+ ; different types of sets
+ (set/intersection (hash-set 1 2) (hash-set 2 3)) #{2}
+ (set/intersection (sorted-set 1 2) (sorted-set 2 3)) #{2}
+ (set/intersection
+ (hash-set 1 2) (hash-set 2 3)
+ (sorted-set 1 2) (sorted-set 2 3)) #{2} ))
+
+
+; difference
+;
+; select
+; project
+; rename-keys
+; rename
+; index
+; map-invert
+; join
+
diff --git a/test/clojure/test_clojure/clojure_xml.clj b/test/clojure/test_clojure/clojure_xml.clj
new file mode 100644
index 00000000..b9ab0829
--- /dev/null
+++ b/test/clojure/test_clojure/clojure_xml.clj
@@ -0,0 +1,18 @@
+;; Copyright (c) Frantisek Sodomka. All rights reserved. The use and
+;; distribution terms for this software are covered by the Eclipse Public
+;; License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which can
+;; be found in the file epl-v10.html at the root of this distribution. By
+;; using this software in any fashion, you are agreeing to be bound by the
+;; terms of this license. You must not remove this notice, or any other,
+;; from this software.
+
+(ns clojure.test-clojure.clojure-xml
+ (:use clojure.test)
+ (:require [clojure.xml :as xml]))
+
+
+; parse
+
+; emit-element
+; emit
+
diff --git a/test/clojure/test_clojure/clojure_zip.clj b/test/clojure/test_clojure/clojure_zip.clj
new file mode 100644
index 00000000..b3e53e95
--- /dev/null
+++ b/test/clojure/test_clojure/clojure_zip.clj
@@ -0,0 +1,45 @@
+;; Copyright (c) Frantisek Sodomka. All rights reserved. The use and
+;; distribution terms for this software are covered by the Eclipse Public
+;; License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which can
+;; be found in the file epl-v10.html at the root of this distribution. By
+;; using this software in any fashion, you are agreeing to be bound by the
+;; terms of this license. You must not remove this notice, or any other,
+;; from this software.
+
+(ns clojure.test-clojure.clojure-zip
+ (:use clojure.test)
+ (:require [clojure.zip :as zip]))
+
+
+; zipper
+;
+; seq-zip
+; vector-zip
+; xml-zip
+;
+; node
+; branch?
+; children
+; make-node
+; path
+; lefts
+; rights
+; down
+; up
+; root
+; right
+; rightmost
+; left
+; leftmost
+;
+; insert-left
+; insert-right
+; replace
+; edit
+; insert-child
+; append-child
+; next
+; prev
+; end?
+; remove
+
diff --git a/test/clojure/test_clojure/compilation.clj b/test/clojure/test_clojure/compilation.clj
new file mode 100644
index 00000000..03557033
--- /dev/null
+++ b/test/clojure/test_clojure/compilation.clj
@@ -0,0 +1,36 @@
+;; Copyright (c) Frantisek Sodomka. All rights reserved. The use and
+;; distribution terms for this software are covered by the Eclipse Public
+;; License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which can
+;; be found in the file epl-v10.html at the root of this distribution. By
+;; using this software in any fashion, you are agreeing to be bound by the
+;; terms of this license. You must not remove this notice, or any other,
+;; from this software.
+
+(ns clojure.test-clojure.compilation
+ (:use clojure.test))
+
+; http://clojure.org/compilation
+
+; compile
+; gen-class, gen-interface
+
+
+(deftest test-compiler-metadata
+ (let [m ^#'when]
+ (are [x y] (= x y)
+ (list? (:arglists m)) true
+ (> (count (:arglists m)) 0) true
+
+ (string? (:doc m)) true
+ (> (.length (:doc m)) 0) true
+
+ (string? (:file m)) true
+ (> (.length (:file m)) 0) true
+
+ (integer? (:line m)) true
+ (> (:line m) 0) true
+
+ (:macro m) true
+ (:name m) 'when )))
+
+
diff --git a/test/clojure/test_clojure/control.clj b/test/clojure/test_clojure/control.clj
new file mode 100644
index 00000000..0b29e205
--- /dev/null
+++ b/test/clojure/test_clojure/control.clj
@@ -0,0 +1,114 @@
+;; Copyright (c) Frantisek Sodomka. All rights reserved. The use and
+;; distribution terms for this software are covered by the Eclipse Public
+;; License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which can
+;; be found in the file epl-v10.html at the root of this distribution. By
+;; using this software in any fashion, you are agreeing to be bound by the
+;; terms of this license. You must not remove this notice, or any other,
+;; from this software.
+;;
+;; Test "flow control" constructs.
+;;
+
+(ns clojure.test-clojure.control
+ (:use clojure.test
+ [clojure.test-clojure.test-utils :only (exception)]))
+
+;; *** Helper functions ***
+
+(defn maintains-identity [f]
+ (are [x] (= (f x) x)
+ 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} ))
+
+
+; http://clojure.org/special_forms
+; http://clojure.org/macros
+
+(deftest test-do
+ (are [x y] (= x y)
+ ; no params => nil
+ (do) nil
+
+ ; return last
+ (do 1) 1
+ (do 1 2) 2
+ (do 1 2 3 4 5) 5
+
+ ; evaluate and return last
+ (let [a (atom 0)]
+ (do (reset! a (+ @a 1)) ; 1
+ (reset! a (+ @a 1)) ; 2
+ (reset! a (+ @a 1)) ; 3
+ @a)) 3 )
+
+ ; identity (= (do x) x)
+ (maintains-identity (fn [_] (do _))) )
+
+
+; loop/recur
+; throw, try
+
+; [if (logic.clj)], if-not, if-let
+; when, when-not, when-let, when-first
+
+
+(deftest test-cond
+ (are [x y] (= x y)
+ (cond) nil
+
+ (cond nil true) nil
+ (cond false true) nil
+
+ (cond true 1 true (exception)) 1
+ (cond nil 1 false 2 true 3 true 4) 3
+ (cond nil 1 false 2 true 3 true (exception)) 3 )
+
+ ; false
+ (are [x] (= (cond x :a true :b) :b)
+ nil false )
+
+ ; true
+ (are [x] (= (cond x :a true :b) :a)
+ 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} )
+
+ ; evaluation
+ (are [x y] (= x y)
+ (cond (> 3 2) (+ 1 2) true :result true (exception)) 3
+ (cond (< 3 2) (+ 1 2) true :result true (exception)) :result )
+
+ ; identity (= (cond true x) x)
+ (maintains-identity (fn [_] (cond true _))) )
+
+
+; condp
+
+; [for, doseq (for.clj)]
+
+; dotimes, while
+
+; locking, monitor-enter, monitor-exit
+
diff --git a/test/clojure/test_clojure/data_structures.clj b/test/clojure/test_clojure/data_structures.clj
new file mode 100644
index 00000000..edca3955
--- /dev/null
+++ b/test/clojure/test_clojure/data_structures.clj
@@ -0,0 +1,734 @@
+;; Copyright (c) Frantisek Sodomka. All rights reserved. The use and
+;; distribution terms for this software are covered by the Eclipse Public
+;; License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which can
+;; be found in the file epl-v10.html at the root of this distribution. By
+;; using this software in any fashion, you are agreeing to be bound by the
+;; terms of this license. You must not remove this notice, or any other,
+;; from this software.
+;;
+
+(ns clojure.test-clojure.data-structures
+ (:use clojure.test))
+
+
+;; *** 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 [x] (not (= nil x))
+ true false
+ 0 0.0
+ \space
+ "" #""
+ () [] #{} {}
+ (lazy-seq nil) ; SVN 1292: fixed (= (lazy-seq nil) nil)
+ (lazy-seq ())
+ (lazy-seq [])
+ (lazy-seq {})
+ (lazy-seq #{})
+ (lazy-seq "")
+ (lazy-seq (into-array []))
+ (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 [x y] (= x y)
+ '() [] ; 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 [x y] (not= x y)
+ ; only () equals []
+ () #{}
+ () {}
+ [] #{}
+ [] {}
+ #{} {}
+ ; only '(1) equals [1]
+ '(1) #{1}
+ [1] #{1} )
+
+ ; sorted-map, hash-map and array-map - classes differ, but content is equal
+
+;; TODO: reimplement all-are with new do-template?
+;; (all-are (not= (class _1) (class _2))
+;; (sorted-map :a 1)
+;; (hash-map :a 1)
+;; (array-map :a 1))
+;; (all-are (= _1 _2)
+;; (sorted-map)
+;; (hash-map)
+;; (array-map))
+;; (all-are (= _1 _2)
+;; (sorted-map :a 1)
+;; (hash-map :a 1)
+;; (array-map :a 1))
+;; (all-are (= _1 _2)
+;; (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
+ (are [x] (and (not= (class (struct equality-struct 1 2)) (class x))
+ (= (struct equality-struct 1 2) x))
+ (sorted-map :a 1 :b 2)
+ (hash-map :a 1 :b 2)
+ (array-map :a 1 :b 2))
+
+ ; sorted-set vs. hash-set
+ (is (not= (class (sorted-set 1)) (class (hash-set 1))))
+ (are [x y] (= x y)
+ (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 [x y] (= x y)
+ (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 [x] (= (count [x]) 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 [x y] (= x y)
+ (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 [x y] (= x y)
+ (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 [x y] (= x y)
+ (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 [x] (list? x)
+ ()
+ '()
+ (list)
+ (list 1 2 3) )
+
+ ; order is important
+ (are [x y] (not (= x y))
+ (list 1 2) (list 2 1)
+ (list 3 1 2) (list 1 2 3) )
+
+ (are [x y] (= x y)
+ '() ()
+ (list) '()
+ (list 1) '(1)
+ (list 1 2) '(1 2)
+
+ ; nesting
+ (list 1 (list 2 3) (list 3 (list 4 5 (list 6 (list 7)))))
+ '(1 (2 3) (3 (4 5 (6 (7)))))
+
+ ; different data structures
+ (list true false nil)
+ '(true false nil)
+ (list 1 2.5 2/3 "ab" \x 'cd :kw)
+ '(1 2.5 2/3 "ab" \x cd :kw)
+ (list (list 1 2) [3 4] {:a 1 :b 2} #{:c :d})
+ '((1 2) [3 4] {:a 1 :b 2} #{:c :d})
+
+ ; evaluation
+ (list (+ 1 2) [(+ 2 3) 'a] (list (* 2 3) 8))
+ '(3 [5 a] (6 8))
+
+ ; special cases
+ (list nil) '(nil)
+ (list 1 nil) '(1 nil)
+ (list nil 2) '(nil 2)
+ (list ()) '(())
+ (list 1 ()) '(1 ())
+ (list () 2) '(() 2) ))
+
+
+;; *** Maps (IPersistentMap) ***
+
+(deftest test-find
+ (are [x y] (= x y)
+ (find {} :a) nil
+
+ (find {:a 1} :a) [:a 1]
+ (find {:a 1} :b) nil
+
+ (find {:a 1 :b 2} :a) [:a 1]
+ (find {:a 1 :b 2} :b) [:b 2]
+ (find {:a 1 :b 2} :c) nil
+
+ (find {} nil) nil
+ (find {:a 1} nil) nil
+ (find {:a 1 :b 2} nil) nil ))
+
+
+(deftest test-contains?
+ ; contains? is designed to work preferably on maps and sets
+ (are [x y] (= x y)
+ (contains? {} :a) false
+ (contains? {} nil) false
+
+ (contains? {:a 1} :a) true
+ (contains? {:a 1} :b) false
+ (contains? {:a 1} nil) false
+
+ (contains? {:a 1 :b 2} :a) true
+ (contains? {:a 1 :b 2} :b) true
+ (contains? {:a 1 :b 2} :c) false
+ (contains? {:a 1 :b 2} nil) false
+
+ ; sets
+ (contains? #{} 1) false
+ (contains? #{} nil) false
+
+ (contains? #{1} 1) true
+ (contains? #{1} 2) false
+ (contains? #{1} nil) false
+
+ (contains? #{1 2 3} 1) true
+ (contains? #{1 2 3} 3) true
+ (contains? #{1 2 3} 10) false
+ (contains? #{1 2 3} nil) false)
+
+ ; numerically indexed collections (e.g. vectors and Java arrays)
+ ; => test if the numeric key is WITHIN THE RANGE OF INDEXES
+ (are [x y] (= x y)
+ (contains? [] 0) false
+ (contains? [] -1) false
+ (contains? [] 1) false
+
+ (contains? [1] 0) true
+ (contains? [1] -1) false
+ (contains? [1] 1) false
+
+ (contains? [1 2 3] 0) true
+ (contains? [1 2 3] 2) true
+ (contains? [1 2 3] 3) false
+ (contains? [1 2 3] -1) false
+
+ ; arrays
+ (contains? (into-array []) 0) false
+ (contains? (into-array []) -1) false
+ (contains? (into-array []) 1) false
+
+ (contains? (into-array [1]) 0) true
+ (contains? (into-array [1]) -1) false
+ (contains? (into-array [1]) 1) false
+
+ (contains? (into-array [1 2 3]) 0) true
+ (contains? (into-array [1 2 3]) 2) true
+ (contains? (into-array [1 2 3]) 3) false
+ (contains? (into-array [1 2 3]) -1) false)
+
+ ; 'contains?' operates constant or logarithmic time,
+ ; it WILL NOT perform a linear search for a value.
+ (are [x] (= x false)
+ (contains? '(1 2 3) 0)
+ (contains? '(1 2 3) 1)
+ (contains? '(1 2 3) 3)
+ (contains? '(1 2 3) 10)
+ (contains? '(1 2 3) nil)
+ (contains? '(1 2 3) ()) ))
+
+
+(deftest test-keys
+ (are [x y] (= x y) ; other than map data structures
+ (keys ()) nil
+ (keys []) nil
+ (keys #{}) nil
+ (keys "") nil )
+
+ (are [x y] (= x y)
+ ; (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 [x y] (= x y) ; other than map data structures
+ (vals ()) nil
+ (vals []) nil
+ (vals #{}) nil
+ (vals "") nil )
+
+ (are [x y] (= x y)
+ ; (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 [x] (= (key (first (hash-map x :value))) x)
+ 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 [x] (= (val (first (hash-map :key x))) x)
+ 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} ))
+
+