summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Hickey <richhickey@gmail.com>2009-07-14 20:11:22 -0400
committerRich Hickey <richhickey@gmail.com>2009-07-14 20:11:22 -0400
commit1ac552bb74ce96df21fa870e57b0fbf5e336c9f0 (patch)
tree2a81916605700d8fe06eec47e054f38b2d44c3a7
parent9b6b549df3d2d835f6c2305e6962e31b21b374af (diff)
parent12888faab8f5c7bc13da5a8f506c2a594c48500c (diff)
Merge branch 'master' into chunks
-rw-r--r--build.xml19
-rw-r--r--src/clj/clojure/core.clj163
-rw-r--r--src/clj/clojure/main.clj8
-rw-r--r--src/clj/clojure/stacktrace.clj74
-rw-r--r--src/clj/clojure/template.clj55
-rw-r--r--src/clj/clojure/test.clj923
-rw-r--r--src/clj/clojure/test/tap.clj111
-rw-r--r--src/clj/clojure/walk.clj133
-rw-r--r--src/jvm/clojure/lang/Compiler.java2
-rw-r--r--src/jvm/clojure/lang/LispReader.java12
-rw-r--r--src/jvm/clojure/lang/LockingTransaction.java5
-rw-r--r--src/jvm/clojure/lang/RT.java7
-rw-r--r--src/jvm/clojure/lang/Ref.java44
-rw-r--r--test/clojure/test_clojure.clj68
-rw-r--r--test/clojure/test_clojure/agents.clj43
-rw-r--r--test/clojure/test_clojure/atoms.clj20
-rw-r--r--test/clojure/test_clojure/clojure_set.clj120
-rw-r--r--test/clojure/test_clojure/clojure_xml.clj21
-rw-r--r--test/clojure/test_clojure/clojure_zip.clj48
-rw-r--r--test/clojure/test_clojure/compilation.clj39
-rw-r--r--test/clojure/test_clojure/control.clj117
-rw-r--r--test/clojure/test_clojure/data_structures.clj736
-rw-r--r--test/clojure/test_clojure/evaluation.clj229
-rw-r--r--test/clojure/test_clojure/for.clj123
-rw-r--r--test/clojure/test_clojure/java_interop.clj407
-rw-r--r--test/clojure/test_clojure/logic.clj205
-rw-r--r--test/clojure/test_clojure/macros.clj18
-rw-r--r--test/clojure/test_clojure/metadata.clj19
-rw-r--r--test/clojure/test_clojure/multimethods.clj27
-rw-r--r--test/clojure/test_clojure/ns_libs.clj28
-rw-r--r--test/clojure/test_clojure/numbers.clj391
-rw-r--r--test/clojure/test_clojure/other_functions.clj60
-rw-r--r--test/clojure/test_clojure/parallel.clj29
-rw-r--r--test/clojure/test_clojure/predicates.clj142
-rw-r--r--test/clojure/test_clojure/printer.clj83
-rw-r--r--test/clojure/test_clojure/reader.clj299
-rw-r--r--test/clojure/test_clojure/refs.clj22
-rw-r--r--test/clojure/test_clojure/sequences.clj984
-rw-r--r--test/clojure/test_clojure/special.clj24
-rw-r--r--test/clojure/test_clojure/test.clj113
-rw-r--r--test/clojure/test_clojure/test_fixtures.clj41
-rw-r--r--test/clojure/test_clojure/test_utils.clj33
-rw-r--r--test/clojure/test_clojure/vars.clj56
43 files changed, 6046 insertions, 55 deletions
diff --git a/build.xml b/build.xml
index 2fa8d8bd..b37adefc 100644
--- a/build.xml
+++ b/build.xml
@@ -9,6 +9,7 @@
</description>
<property name="src" location="src"/>
+ <property name="test" location="test"/>
<property name="jsrc" location="${src}/jvm"/>
<property name="cljsrc" location="${src}/clj"/>
<property name="build" location="classes"/>
@@ -92,6 +93,11 @@
<arg value="clojure.xml"/>
<arg value="clojure.zip"/>
<arg value="clojure.inspector"/>
+ <arg value="clojure.walk"/>
+ <arg value="clojure.stacktrace"/>
+ <arg value="clojure.template"/>
+ <arg value="clojure.test"/>
+ <arg value="clojure.test.tap"/>
</java>
</target>
@@ -110,6 +116,19 @@
<copy file="${clojure_jar}" tofile="${clojure_noversion_jar}" />
</target>
+ <target name="test"
+ description="Run clojure tests">
+<!-- depends="clojure"> -->
+ <java classname="clojure.main">
+ <classpath>
+ <path location="${test}"/>
+ <path location="${clojure_jar}"/>
+ </classpath>
+ <arg value="-e"/>
+ <arg value="(require '(clojure [test-clojure :as main])) (main/run)"/>
+ </java>
+ </target>
+
<target name="clojure-slim" depends="compile-java"
description="Create clojure-slim jar file (omits compiled Clojure code)">
<jar jarfile="${slim_jar}">
diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj
index 6b7661fb..8ed4aaf1 100644
--- a/src/clj/clojure/core.clj
+++ b/src/clj/clojure/core.clj
@@ -129,17 +129,6 @@
vector? (fn vector? [x] (instance? clojure.lang.IPersistentVector x)))
(def
- #^{:private true}
- sigs
- (fn [fdecl]
- (if (seq? (first fdecl))
- (loop [ret [] fdecl fdecl]
- (if fdecl
- (recur (conj ret (first (first fdecl))) (next fdecl))
- (seq ret)))
- (list (first fdecl)))))
-
-(def
#^{:arglists '([map key val] [map key val & kvs])
:doc "assoc[iate]. When applied to a map, returns a new map of the
same (hashed/sorted) type, that contains the mapping of key(s) to
@@ -169,6 +158,27 @@
with-meta (fn with-meta [#^clojure.lang.IObj x m]
(. x (withMeta m))))
+(def
+ #^{:private true}
+ sigs
+ (fn [fdecl]
+ (let [asig
+ (fn [fdecl]
+ (let [arglist (first fdecl)
+ body (next fdecl)]
+ (if (map? (first body))
+ (if (next body)
+ (with-meta arglist (conj (if (meta arglist) (meta arglist) {}) (first body)))
+ arglist)
+ arglist)))]
+ (if (seq? (first fdecl))
+ (loop [ret [] fdecls fdecl]
+ (if fdecls
+ (recur (conj ret (asig (first fdecls))) (next fdecls))
+ (seq ret)))
+ (list (asig fdecl))))))
+
+
(def
#^{:arglists '([coll])
:doc "Return the last item in coll, in linear time"}
@@ -1300,14 +1310,30 @@
:validator validate-fn
+ :min-history (default 0)
+ :max-history (default 10)
+
If metadata-map is supplied, it will be come the metadata on the
ref. validate-fn must be nil or a side-effect-free fn of one
argument, which will be passed the intended new state on any state
change. If the new state is unacceptable, the validate-fn should
return false or throw an exception. validate-fn will be called on
- transaction commit, when all refs have their final values."
+ transaction commit, when all refs have their final values.
+
+ Normally refs accumulate history dynamically as needed to deal with
+ read demands. If you know in advance you will need history you can
+ set :min-history to ensure it will be available when first needed (instead
+ of after a read fault). History is limited, and the limit can be set
+ with :max-history."
([x] (new clojure.lang.Ref x))
- ([x & options] (setup-reference (ref x) options)))
+ ([x & options]
+ (let [r #^clojure.lang.Ref (setup-reference (ref x) options)
+ opts (apply hash-map options)]
+ (when (:max-history opts)
+ (.setMaxHistory r (:max-history opts)))
+ (when (:min-history opts)
+ (.setMinHistory r (:min-history opts)))
+ r)))
(defn deref
"Also reader macro: @ref/@agent/@var/@atom/@delay/@future. Within a transaction,
@@ -1415,6 +1441,25 @@
[#^clojure.lang.Ref ref val]
(. ref (set val)))
+(defn ref-history-count
+ "Returns the history count of a ref"
+ [#^clojure.lang.Ref ref]
+ (.getHistoryCount ref))
+
+(defn ref-min-history
+ "Gets the min-history of a ref, or sets it and returns the ref"
+ ([#^clojure.lang.Ref ref]
+ (.getMinHistory ref))
+ ([#^clojure.lang.Ref ref n]
+ (.setMinHistory ref n)))
+
+(defn ref-max-history
+ "Gets the max-history of a ref, or sets it and returns the ref"
+ ([#^clojure.lang.Ref ref]
+ (.getMaxHistory ref))
+ ([#^clojure.lang.Ref ref n]
+ (.setMaxHistory ref n)))
+
(defn ensure
"Must be called in a transaction. Protects the ref from modification
by other transactions. Returns the in-transaction-value of
@@ -1497,10 +1542,10 @@
false."
{:tag Boolean}
[pred coll]
- (if (seq coll)
- (and (pred (first coll))
- (recur pred (next coll)))
- true))
+ (cond
+ (nil? (seq coll)) true
+ (pred (first coll)) (recur pred (next coll))
+ :else false))
(def
#^{:tag Boolean
@@ -1778,15 +1823,24 @@
(defn partition
"Returns a lazy sequence of lists of n items each, at offsets step
apart. If step is not supplied, defaults to n, i.e. the partitions
- do not overlap."
+ do not overlap. If a pad collection is supplied, use its elements as
+ necessary to complete last partition upto n items. In case there are
+ not enough padding elements, return a partition with less than n items."
([n coll]
(partition n n coll))
([n step coll]
- (lazy-seq
- (when-let [s (seq coll)]
- (let [p (take n s)]
- (when (= n (count p))
- (cons p (partition n step (drop step s)))))))))
+ (lazy-seq
+ (when-let [s (seq coll)]
+ (let [p (take n s)]
+ (when (= n (count p))
+ (cons p (partition n step (drop step s))))))))
+ ([n step pad coll]
+ (lazy-seq
+ (when-let [s (seq coll)]
+ (let [p (take n s)]
+ (if (= n (count p))
+ (cons p (partition n step pad (drop step s)))
+ (list (take n (concat p pad)))))))))
;; evaluation
@@ -2657,7 +2711,7 @@
(even? (count bindings)) "an even number of forms in binding vector")
`(let* ~(destructure bindings) ~@body))
-;redefine fn with destructuring
+;redefine fn with destructuring and pre/post conditions
(defmacro fn
"(fn name? [params* ] exprs*)
(fn name? ([params* ] exprs*)+)
@@ -2673,9 +2727,26 @@
sigs (if name (next sigs) sigs)
sigs (if (vector? (first sigs)) (list sigs) sigs)
psig (fn [sig]
- (let [[params & body] sig]
+ (let [[params & body] sig
+ conds (when (and (next body) (map? (first body)))
+ (first body))
+ body (if conds (next body) body)
+ conds (or conds ^params)
+ pre (:pre conds)
+ post (:post conds)
+ body (if post
+ `((let [~'% ~(if (< 1 (count body))
+ `(do ~@body)
+ (first body))]
+ ~@(map (fn [c] `(assert ~c)) post)
+ ~'%))
+ body)
+ body (if pre
+ (concat (map (fn [c] `(assert ~c)) pre)
+ body)
+ body)]
(if (every? symbol? params)
- sig
+ (cons params body)
(loop [params params
new-params []
lets []]
@@ -2844,8 +2915,9 @@
"Evaluates expr and throws an exception if it does not evaluate to
logical true."
[x]
- `(when-not ~x
- (throw (new Exception (str "Assert failed: " (pr-str '~x))))))
+ (when *assert*
+ `(when-not ~x
+ (throw (new Exception (str "Assert failed: " (pr-str '~x)))))))
(defn test
"test [v] finds fn at key :test in var metadata and calls it,
@@ -3034,16 +3106,20 @@
[v] (instance? clojure.lang.Var v))
(defn slurp
- "Reads the file named by f into a string and returns it."
- [#^String f]
- (with-open [r (new java.io.BufferedReader (new java.io.FileReader f))]
+ "Reads the file named by f using the encoding enc into a string
+ and returns it."
+ ([f] (slurp f (.name (java.nio.charset.Charset/defaultCharset))))
+ ([#^String f #^String enc]
+ (with-open [r (new java.io.BufferedReader
+ (new java.io.InputStreamReader
+ (new java.io.FileInputStream f) enc))]
(let [sb (new StringBuilder)]
- (loop [c (. r (read))]
+ (loop [c (.read r)]
(if (neg? c)
(str sb)
(do
- (. sb (append (char c)))
- (recur (. r (read)))))))))
+ (.append sb (char c))
+ (recur (.read r)))))))))
(defn subs
"Returns the substring of s beginning at start inclusive, and ending
@@ -3735,11 +3811,11 @@
All definitions a lib makes should be in its associated namespace.
'require loads a lib by loading its root resource. The root resource path
- is derived from the root directory path by repeating its last component
- and appending '.clj'. For example, the lib 'x.y.z has root directory
- <classpath>/x/y/z; root resource <classpath>/x/y/z/z.clj. The root
- resource should contain code to create the lib's namespace and load any
- additional lib resources.
+ is derived from the lib name in the following manner:
+ Consider a lib named by the symbol 'x.y.z; it has the root directory
+ <classpath>/x/y/, and its root resource is <classpath>/x/y/z.clj. The root
+ resource should contain code to create the lib's namespace (usually by using
+ the ns macro) and load any additional lib resources.
Libspecs
@@ -3766,7 +3842,14 @@
already loaded
:reload-all implies :reload and also forces loading of all libs that the
identified libs directly or indirectly load via require or use
- :verbose triggers printing information about each load, alias, and refer"
+ :verbose triggers printing information about each load, alias, and refer
+
+ Example:
+
+ The following would load the libraries clojure.zip and clojure.set
+ abbreviated as 's'.
+
+ (require '(clojure zip [set :as s]))"
[& args]
(apply load-libs :require args))
diff --git a/src/clj/clojure/main.clj b/src/clj/clojure/main.clj
index ee185afe..58fa0a3f 100644
--- a/src/clj/clojure/main.clj
+++ b/src/clj/clojure/main.clj
@@ -16,17 +16,19 @@
(defmacro with-bindings
"Executes body in the context of thread-local bindings for several vars
- that often need to be set!: *ns* *warn-on-reflection* *print-meta*
- *print-length* *print-level* *compile-path* *command-line-args* *1
- *2 *3 *e"
+ that often need to be set!: *ns* *warn-on-reflection* *math-context*
+ *print-meta* *print-length* *print-level* *compile-path*
+ *command-line-args* *1 *2 *3 *e"
[& body]
`(binding [*ns* *ns*
*warn-on-reflection* *warn-on-reflection*
+ *math-context* *math-context*
*print-meta* *print-meta*
*print-length* *print-length*
*print-level* *print-level*
*compile-path* (System/getProperty "clojure.compile.path" "classes")
*command-line-args* *command-line-args*
+ *assert* *assert*
*1 nil
*2 nil
*3 nil
diff --git a/src/clj/clojure/stacktrace.clj b/src/clj/clojure/stacktrace.clj
new file mode 100644
index 00000000..52d03b9b
--- /dev/null
+++ b/src/clj/clojure/stacktrace.clj
@@ -0,0 +1,74 @@
+; Copyright (c) Rich Hickey. 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.
+
+;;; stacktrace.clj: print Clojure-centric stack traces
+
+;; by Stuart Sierra
+;; January 6, 2009
+
+(ns
+ #^{:author "Stuart Sierra",
+ :doc "Print Clojure-centric stack traces"}
+ clojure.stacktrace)
+
+(defn root-cause
+ "Returns the last 'cause' Throwable in a chain of Throwables."
+ [tr]
+ (if-let [cause (.getCause tr)]
+ (recur cause)
+ tr))
+
+(defn print-trace-element
+ "Prints a Clojure-oriented view of one element in a stack trace."
+ [e]
+ (let [class (.getClassName e)
+ method (.getMethodName e)]
+ (let [match (re-matches #"^([A-Za-z0-9_.-]+)\$(\w+)__\d+$" class)]
+ (if (and match (= "invoke" method))
+ (apply printf "%s/%s" (rest match))
+ (printf "%s.%s" class method))))
+ (printf " (%s:%d)" (or (.getFileName e) "") (.getLineNumber e)))
+
+(defn print-throwable
+ "Prints the class and message of a Throwable."
+ [tr]
+ (printf "%s: %s" (.getName (class tr)) (.getMessage tr)))
+
+(defn print-stack-trace
+ "Prints a Clojure-oriented stack trace of tr, a Throwable.
+ Prints a maximum of n stack frames (default: unlimited).
+ Does not print chained exceptions (causes)."
+ ([tr] (print-stack-trace tr nil))
+ ([tr n]
+ (let [st (.getStackTrace tr)]
+ (print-throwable tr)
+ (newline)
+ (print " at ")
+ (print-trace-element (first st))
+ (newline)
+ (doseq [e (if (nil? n)
+ (rest st)
+ (take (dec n) (rest st)))]
+ (print " ")
+ (print-trace-element e)
+ (newline)))))
+
+(defn print-cause-trace
+ "Like print-stack-trace but prints chained exceptions (causes)."
+ ([tr] (print-cause-trace tr nil))
+ ([tr n]
+ (print-stack-trace tr n)
+ (when-let [cause (.getCause tr)]
+ (print "Caused by: " )
+ (recur cause n))))
+
+(defn e
+ "REPL utility. Prints a brief stack trace for the root cause of the
+ most recent exception."
+ []
+ (print-stack-trace (root-cause *e) 8))
diff --git a/src/clj/clojure/template.clj b/src/clj/clojure/template.clj
new file mode 100644
index 00000000..d62390a6
--- /dev/null
+++ b/src/clj/clojure/template.clj
@@ -0,0 +1,55 @@
+; Copyright (c) Rich Hickey. 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.
+
+;;; template.clj - anonymous functions that pre-evaluate sub-expressions
+
+;; By Stuart Sierra
+;; June 23, 2009
+
+;; CHANGE LOG
+;;
+;; June 23, 2009: complete rewrite, eliminated _1,_2,... argument
+;; syntax
+;;
+;; January 20, 2009: added "template?" and checks for valid template
+;; expressions.
+;;
+;; December 15, 2008: first version
+
+
+(ns #^{:author "Stuart Sierra"
+ :doc "Macros that expand to repeated copies of a template expression."}
+ clojure.template
+ (:require [clojure.walk :as walk]))
+
+(defn apply-template
+ "For use in macros. argv is an argument list, as in defn. expr is
+ a quoted expression using the symbols in argv. values is a sequence
+ of values to be used for the arguments.
+
+ apply-template will recursively replace argument symbols in expr
+ with their corresponding values, returning a modified expr.
+
+ Example: (apply-template '[x] '(+ x x) '[2])
+ ;=> (+ 2 2)"
+ [argv expr values]
+ (assert (vector? argv))
+ (assert (every? symbol? argv))
+ (walk/prewalk-replace (zipmap argv values) expr))
+
+(defmacro do-template
+ "Repeatedly copies expr (in a do block) for each group of arguments
+ in values. values are automatically partitioned by the number of
+ arguments in argv, an argument vector as in defn.
+
+ Example: (macroexpand '(do-template [x y] (+ y x) 2 4 3 5))
+ ;=> (do (+ 4 2) (+ 5 3))"
+ [argv expr & values]
+ (let [c (count argv)]
+ `(do ~@(map (fn [a] (apply-template argv expr a))
+ (partition c values)))))
diff --git a/src/clj/clojure/test.clj b/src/clj/clojure/test.clj
new file mode 100644
index 00000000..7195034b
--- /dev/null
+++ b/src/clj/clojure/test.clj
@@ -0,0 +1,923 @@
+; Copyright (c) Rich Hickey. 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.clj: test framework for Clojure
+
+;; by Stuart Sierra
+;; March 28, 2009
+
+;; Thanks to Chas Emerick, Allen Rohner, and Stuart Halloway for
+;; contributions and suggestions.
+
+
+
+(comment
+ ;; Inspired by many Common Lisp test frameworks and clojure/test,
+ ;; this file is a Clojure test framework.
+ ;;
+ ;;
+ ;;
+ ;; ASSERTIONS
+ ;;
+ ;; The core of the library is the "is" macro, which lets you make
+ ;; assertions of any arbitrary expression:
+
+ (is (= 4 (+ 2 2)))
+ (is (instance? Integer 256))
+ (is (.startsWith "abcde" "ab"))
+
+ ;; You can type an "is" expression directly at the REPL, which will
+ ;; print a message if it fails.
+ ;;
+ ;; user> (is (= 5 (+ 2 2)))
+ ;;
+ ;; FAIL in (:1)
+ ;; expected: (= 5 (+ 2 2))
+ ;; actual: (not (= 5 4))
+ ;; false
+ ;;
+ ;; The "expected:" line shows you the original expression, and the
+ ;; "actual:" shows you what actually happened. In this case, it
+ ;; shows that (+ 2 2) returned 4, which is not = to 5. Finally, the
+ ;; "false" on the last line is the value returned from the
+ ;; expression. The "is" macro always returns the result of the
+ ;; inner expression.
+ ;;
+ ;; There are two special assertions for testing exceptions. The
+ ;; "(is (thrown? c ...))" form tests if an exception of class c is
+ ;; thrown:
+
+ (is (thrown? ArithmeticException (/ 1 0)))
+
+ ;; "(is (thrown-with-msg? c re ...))" does the same thing and also
+ ;; tests that the message on the exception matches the regular
+ ;; expression re:
+
+ (is (thrown-with-msg? ArithmeticException #"Divide by zero"
+ (/ 1 0)))
+
+ ;;
+ ;;
+ ;;
+ ;; DOCUMENTING TESTS
+ ;;
+ ;; "is" takes an optional second argument, a string describing the
+ ;; assertion. This message will be included in the error report.
+
+ (is (= 5 (+ 2 2)) "Crazy arithmetic")
+
+ ;; In addition, you can document groups of assertions with the
+ ;; "testing" macro, which takes a string followed by any number of
+ ;; assertions. The string will be included in failure reports.
+ ;; Calls to "testing" may be nested, and all of the strings will be
+ ;; joined together with spaces in the final report, in a style
+ ;; similar to RSpec <http://rspec.info/>
+
+ (testing "Arithmetic"
+ (testing "with positive integers"
+ (is (= 4 (+ 2 2)))
+ (is (= 7 (+ 3 4))))
+ (testing "with negative integers"
+ (is (= -4 (+ -2 -2)))
+ (is (= -1 (+ 3 -4)))))
+
+ ;; Note that, unlike RSpec, the "testing" macro may only be used
+ ;; INSIDE a "deftest" or "with-test" form (see below).
+ ;;
+ ;;
+ ;;
+ ;; DEFINING TESTS
+ ;;
+ ;; There are two ways to define tests. The "with-test" macro takes
+ ;; a defn or def form as its first argument, followed by any number
+ ;; of assertions. The tests will be stored as metadata on the
+ ;; definition.
+
+ (with-test
+ (defn my-function [x y]
+ (+ x y))
+ (is (= 4 (my-function 2 2)))
+ (is (= 7 (my-function 3 4))))
+
+ ;; As of Clojure SVN rev. 1221, this does not work with defmacro.
+ ;; See http://code.google.com/p/clojure/issues/detail?id=51
+ ;;
+ ;; The other way lets you define tests separately from the rest of
+ ;; your code, even in a different namespace:
+
+ (deftest addition
+ (is (= 4 (+ 2 2)))
+ (is (= 7 (+ 3 4))))
+
+ (deftest subtraction
+ (is (= 1 (- 4 3)))
+ (is (= 3 (- 7 4))))
+
+ ;; This creates functions named "addition" and "subtraction", which
+ ;; can be called like any other function. Therefore, tests can be
+ ;; grouped and composed, in a style similar to the test framework in
+ ;; Peter Seibel's "Practical Common Lisp"
+ ;; <http://www.gigamonkeys.com/book/practical-building-a-unit-test-framework.html>
+
+ (deftest arithmetic
+ (addition)
+ (subtraction))
+
+ ;; The names of the nested tests will be joined in a list, like
+ ;; "(arithmetic addition)", in failure reports. You can use nested
+ ;; tests to set up a context shared by several tests.
+ ;;
+ ;;
+ ;;
+ ;; RUNNING TESTS
+ ;;
+ ;; Run tests with the function "(run-tests namespaces...)":
+
+ (run-tests 'your.namespace 'some.other.namespace)
+
+ ;; If you don't specify any namespaces, the current namespace is
+ ;; used. To run all tests in all namespaces, use "(run-all-tests)".
+ ;;
+ ;; By default, these functions will search for all tests defined in
+ ;; a namespace and run them in an undefined order. However, if you
+ ;; are composing tests, as in the "arithmetic" example above, you
+ ;; probably do not want the "addition" and "subtraction" tests run
+ ;; separately. In that case, you must define a special function
+ ;; named "test-ns-hook" that runs your tests in the correct order:
+
+ (defn test-ns-hook []
+ (arithmetic))
+
+ ;;
+ ;;
+ ;;
+ ;; OMITTING TESTS FROM PRODUCTION CODE
+ ;;
+ ;; You can bind the variable "*load-tests*" to false when loading or
+ ;; compiling code in production. This will prevent any tests from
+ ;; being created by "with-test" or "deftest".
+ ;;
+ ;;
+ ;;
+ ;; FIXTURES (new)
+ ;;
+ ;; Fixtures allow you to run code before and after tests, to set up
+ ;; the context in which tests should be run.
+ ;;
+ ;; A fixture is just a function that calls another function passed as
+ ;; an argument. It looks like this:
+ (defn my-fixture [f]
+ ;; Perform setup, establish bindings, whatever.
+ (f) ;; Then call the function we were passed.
+ ;; Tear-down / clean-up code here.
+ )
+
+ ;; Fixtures are attached to namespaces in one of two ways. "each"
+ ;; fixtures are run repeatedly, once for each test function created
+ ;; with "deftest" or "with-test". "each" fixtures are useful for
+ ;; establishing a consistent before/after state for each test, like
+ ;; clearing out database tables.
+ ;;
+ ;; "each" fixtures can be attached to the current namespace like this:
+ (use-fixtures :each fixture1 fixture2 ...)
+ ;; The fixture1, fixture2 are just functions like the example above.
+ ;; They can also be anonymous functions, like this:
+ (use-fixtures :each (fn [f] setup... (f) cleanup...))
+ ;;
+ ;; The other kind of fixture, a "once" fixture, is only run once,
+ ;; around ALL the tests in the namespace. "once" fixtures are useful
+ ;; for tasks that only need to be performed once, like establishing
+ ;; database connections, or for time-consuming tasks.
+ ;;
+ ;; Attach "once" fixtures to the current namespace like this:
+ (use-fixtures :once fixture1 fixture2 ...)
+ ;;
+ ;;
+ ;;
+ ;; SAVING TEST OUTPUT TO A FILE
+ ;;
+ ;; All the test reporting functions write to the var *test-out*. By
+ ;; default, this is the same as *out*, but you can rebind it to any
+ ;; PrintWriter. For example, it could be a file opened with
+ ;; clojure.contrib.duck-streams/writer.
+ ;;
+ ;;
+ ;;
+ ;; EXTENDING TEST-IS (ADVANCED)
+ ;;
+ ;; You can extend the behavior of the "is" macro by defining new
+ ;; methods for the "assert-expr" multimethod. These methods are
+ ;; called during expansion of the "is" macro, so they should return
+ ;; quoted forms to be evaluated.
+ ;;
+ ;; You can plug in your own test-reporting framework by rebinding
+ ;; the "report" function: (report event)
+ ;;
+ ;; The 'event' argument is a map. It will always have a :type key,
+ ;; whose value will be a keyword signaling the type of event being
+ ;; reported. Standard events with :type value of :pass, :fail, and
+ ;; :error are called when an assertion passes, fails, and throws an
+ ;; exception, respectively. In that case, the event will also have
+ ;; the following keys:
+ ;;
+ ;; :expected The form that was expected to be true
+ ;; :actual A form representing what actually occurred
+ ;; :message The string message given as an argument to 'is'
+ ;;
+ ;; The "testing" strings will be a list in "*testing-contexts*", and
+ ;; the vars being tested will be a list in "*testing-vars*".
+ ;;
+ ;; Your "report" function should wrap any printing calls in the
+ ;; "with-test-out" macro, which rebinds *out* to the current value
+ ;; of *test-out*.
+ ;;
+ ;; For additional event types, see the examples in the code below.
+
+ ) ;; end comment
+
+
+
+(ns
+ #^{:author "Stuart Sierra, with contributions and suggestions by
+Chas Emerick, Allen Rohner, and Stuart Halloway",
+ :doc "Inspired by many Common Lisp test frameworks and clojure/test,
+ this file is a Clojure test framework.
+
+ ASSERTIONS
+
+ The core of the library is the \"is\" macro, which lets you make
+ assertions of any arbitrary expression:
+
+ (is (= 4 (+ 2 2)))
+ (is (instance? Integer 256))
+ (is (.startsWith \"abcde\" \"ab\"))
+
+ You can type an \"is\" expression directly at the REPL, which will
+ print a message if it fails.
+
+ user> (is (= 5 (+ 2 2)))
+
+ FAIL in (:1)
+ expected: (= 5 (+ 2 2))
+ actual: (not (= 5 4))
+ false
+
+ The \"expected:\" line shows you the original expression, and the
+ \"actual:\" shows you what actually happened. In this case, it
+ shows that (+ 2 2) returned 4, which is not = to 5. Finally, the
+ \"false\" on the last line is the value returned from the
+ expression. The \"is\" macro always returns the result of the
+ inner expression.
+
+ There are two special assertions for testing exceptions. The
+ \"(is (thrown? c ...))\" form tests if an exception of class c is
+ thrown:
+
+ (is (thrown? ArithmeticException (/ 1 0)))
+
+ \"(is (thrown-with-msg? c re ...))\" does the same thing and also
+ tests that the message on the exception matches the regular
+ expression re:
+
+ (is (thrown-with-msg? ArithmeticException #\"Divide by zero\"
+ (/ 1 0)))
+
+ DOCUMENTING TESTS
+
+ \"is\" takes an optional second argument, a string describing the
+ assertion. This message will be included in the error report.
+
+ (is (= 5 (+ 2 2)) \"Crazy arithmetic\")
+
+ In addition, you can document groups of assertions with the
+ \"testing\" macro, which takes a string followed by any number of
+ assertions. The string will be included in failure reports.
+ Calls to \"testing\" may be nested, and all of the strings will be
+ joined together with spaces in the final report, in a style
+ similar to RSpec <http://rspec.info/>
+
+ (testing \"Arithmetic\"
+ (testing \"with positive integers\"
+ (is (= 4 (+ 2 2)))
+ (is (= 7 (+ 3 4))))
+ (testing \"with negative integers\"
+ (is (= -4 (+ -2 -2)))
+ (is (= -1 (+ 3 -4)))))
+
+ Note that, unlike RSpec, the \"testing\" macro may only be used
+ INSIDE a \"deftest\" or \"with-test\" form (see below).
+
+
+ DEFINING TESTS
+
+ There are two ways to define tests. The \"with-test\" macro takes
+ a defn or def form as its first argument, followed by any number
+ of assertions. The tests will be stored as metadata on the
+ definition.
+
+ (with-test
+ (defn my-function [x y]
+ (+ x y))
+ (is (= 4 (my-function 2 2)))
+ (is (= 7 (my-function 3 4))))
+
+ As of Clojure SVN rev. 1221, this does not work with defmacro.
+ See http://code.google.com/p/clojure/issues/detail?id=51
+
+ The other way lets you define tests separately from the rest of
+ your code, even in a different namespace:
+
+ (deftest addition
+ (is (= 4 (+ 2 2)))
+ (is (= 7 (+ 3 4))))
+
+ (deftest subtraction
+ (is (= 1 (- 4 3)))
+ (is (= 3 (- 7 4))))
+
+ This creates functions named \"addition\" and \"subtraction\", which
+ can be called like any other function. Therefore, tests can be
+ grouped and composed, in a style similar to the test framework in
+ Peter Seibel's \"Practical Common Lisp\"
+ <http://www.gigamonkeys.com/book/practical-building-a-unit-test-framework.html>
+
+ (deftest arithmetic
+ (addition)
+ (subtraction))
+
+ The names of the nested tests will be joined in a list, like
+ \"(arithmetic addition)\", in failure reports. You can use nested
+ tests to set up a context shared by several tests.
+
+
+ RUNNING TESTS
+
+ Run tests with the function \"(run-tests namespaces...)\":
+
+ (run-tests 'your.namespace 'some.other.namespace)
+
+ If you don't specify any namespaces, the current namespace is
+ used. To run all tests in all namespaces, use \"(run-all-tests)\".
+
+ By default, these functions will search for all tests defined in
+ a namespace and run them in an undefined order. However, if you
+ are composing tests, as in the \"arithmetic\" example above, you
+ probably do not want the \"addition\" and \"subtraction\" tests run
+ separately. In that case, you must define a special function
+ named \"test-ns-hook\" that runs your tests in the correct order:
+
+ (defn test-ns-hook []
+ (arithmetic))
+
+
+ OMITTING TESTS FROM PRODUCTION CODE
+
+ You can bind the variable \"*load-tests*\" to false when loading or
+ compiling code in production. This will prevent any tests from
+ being created by \"with-test\" or \"deftest\".
+
+
+ FIXTURES (new)
+
+ Fixtures allow you to run code before and after tests, to set up
+ the context in which tests should be run.
+
+ A fixture is just a function that calls another function passed as
+ an argument. It looks like this:
+
+ (defn my-fixture [f]
+ Perform setup, establish bindings, whatever.
+ (f) Then call the function we were passed.
+ Tear-down / clean-up code here.
+ )
+
+ Fixtures are attached to namespaces in one of two ways. \"each\"
+ fixtures are run repeatedly, once for each test function created
+ with \"deftest\" or \"with-test\". \"each\" fixtures are useful for
+ establishing a consistent before/after state for each test, like
+ clearing out database tables.
+
+ \"each\" fixtures can be attached to the current namespace like this:
+ (use-fixtures :each fixture1 fixture2 ...)
+ The fixture1, fixture2 are just functions like the example above.
+ They can also be anonymous functions, like this:
+ (use-fixtures :each (fn [f] setup... (f) cleanup...))
+
+ The other kind of fixture, a \"once\" fixture, is only run once,
+ around ALL the tests in the namespace. \"once\" fixtures are useful
+ for tasks that only need to be performed once, like establishing
+ database connections, or for time-consuming tasks.
+
+ Attach \"once\" fixtures to the current namespace like this:
+ (use-fixtures :once fixture1 fixture2 ...)
+
+
+ SAVING TEST OUTPUT TO A FILE
+
+ All the test reporting functions write to the var *test-out*. By
+ default, this is the same as *out*, but you can rebind it to any
+ PrintWriter. For example, it could be a file opened with
+ clojure.contrib.duck-streams/writer.
+
+
+ EXTENDING TEST-IS (ADVANCED)
+
+ You can extend the behavior of the \"is\" macro by defining new
+ methods for the \"assert-expr\" multimethod. These methods are
+ called during expansion of the \"is\" macro, so they should return
+ quoted forms to be evaluated.
+
+ You can plug in your own test-reporting framework by rebinding
+ the \"report\" function: (report event)
+
+ The 'event' argument is a map. It will always have a :type key,
+ whose value will be a keyword signaling the type of event being
+ reported. Standard events with :type value of :pass, :fail, and
+ :error are called when an assertion passes, fails, and throws an
+ exception, respectively. In that case, the event will also have
+ the following keys:
+
+ :expected The form that was expected to be true
+ :actual A form representing what actually occurred
+ :message The string message given as an argument to 'is'
+
+ The \"testing\" strings will be a list in \"*testing-contexts*\", and
+ the vars being tested will be a list in \"*testing-vars*\".
+
+ Your \"report\" function should wrap any printing calls in the
+ \"with-test-out\" macro, which rebinds *out* to the current value
+ of *test-out*.
+
+ For additional event types, see the examples in the code.
+"}
+ clojure.test
+ (:require [clojure.template :as temp]
+ [clojure.stacktrace :as stack]))
+
+;; Nothing is marked "private" here, so you can rebind things to plug
+;; in your own testing or reporting frameworks.
+
+
+;;; USER-MODIFIABLE GLOBALS
+
+(defonce
+ #^{:doc "True by default. If set to false, no test functions will
+ be created by deftest, set-test, or with-test. Use this to omit
+ tests when compiling or loading production code."}
+ *load-tests* true)
+
+(def
+ #^{:doc "The maximum depth of stack traces to print when an Exception
+ is thrown during a test. Defaults to nil, which means print the
+ complete stack trace."}
+ *stack-trace-depth* nil)
+
+
+;;; GLOBALS USED BY THE REPORTING FUNCTIONS
+
+(def *report-counters* nil) ; bound to a ref of a map in test-ns
+
+(def *initial-report-counters* ; used to initialize *report-counters*
+ {:test 0, :pass 0, :fail 0, :error 0})
+
+(def *testing-vars* (list)) ; bound to hierarchy of vars being tested
+
+(def *testing-contexts* (list)) ; bound to hierarchy of "testing" strings
+
+(def *test-out* *out*) ; PrintWriter for test reporting output
+
+(defmacro with-test-out
+ "Runs body with *out* bound to the value of *test-out*."
+ [& body]
+ `(binding [*out* *test-out*]
+ ~@body))
+
+
+
+;;; UTILITIES FOR REPORTING FUNCTIONS
+
+(defn file-position
+ "Returns a vector [filename line-number] for the nth call up the
+ stack."
+ [n]
+ (let [s (nth (.getStackTrace (new java.lang.Throwable)) n)]
+ [(.getFileName s) (.getLineNumber s)]))
+
+(defn testing-vars-str
+ "Returns a string representation of the current test. Renders names
+ in *testing-vars* as a list, then the source file and line of
+ current assertion."
+ []
+ (let [[file line] (file-position 4)]
+ (str
+ ;; Uncomment to include namespace in failure report:
+ ;;(ns-name (:ns (meta (first *testing-vars*)))) "/ "
+ (reverse (map #(:name (meta %)) *testing-vars*))
+ " (" file ":" line ")")))
+
+(defn testing-contexts-str
+ "Returns a string representation of the current test context. Joins
+ strings in *testing-contexts* with spaces."
+ []
+ (apply str (interpose " " (reverse *testing-contexts*))))
+
+(defn inc-report-counter
+ "Increments the named counter in *report-counters*, a ref to a map.
+ Does nothing if *report-counters* is nil."
+ [name]
+ (when *report-counters*
+ (dosync (commute *report-counters* assoc name
+ (inc (or (*report-counters* name) 0))))))
+
+
+
+;;; TEST RESULT REPORTING
+
+(defmulti
+ #^{:doc "Generic reporting function, may be overridden to plug in
+ different report formats (e.g., TAP, JUnit). Assertions such as
+ 'is' call 'report' to indicate results. The argument given to
+ 'report' will be a map with a :type key. See the documentation at
+ the top of test_is.clj for more information on the types of
+ arguments for 'report'."}
+ report :type)
+
+(defmethod report :default [m]
+ (with-test-out (prn m)))
+
+(defmethod report :pass [m]
+ (with-test-out (inc-report-counter :pass)))
+
+(defmethod report :fail [m]
+ (with-test-out
+ (inc-report-counter :fail)
+ (println "\nFAIL in" (testing-vars-str))
+ (when (seq *testing-contexts*) (println (testing-contexts-str)))
+ (when-let [message (:message m)] (println message))
+ (println "expected:" (pr-str (:expected m)))
+ (println " actual:" (pr-str (:actual m)))))
+
+(defmethod report :error [m]
+ (with-test-out
+ (inc-report-counter :error)
+ (println "\nERROR in" (testing-vars-str))
+ (when (seq *testing-contexts*) (println (testing-contexts-str)))
+ (when-let [message (:message m)] (println message))
+ (println "expected:" (pr-str (:expected m)))
+ (print " actual: ")
+ (let [actual (:actual m)]
+ (if (instance? Throwable actual)
+ (stack/print-cause-trace actual *stack-trace-depth*)
+ (prn actual)))))
+
+(defmethod report :summary [m]
+ (with-test-out
+ (println "\nRan" (:test m) "tests containing"
+ (+ (:pass m) (:fail m) (:error m)) "assertions.")
+ (println (:fail m) "failures," (:error m) "errors.")))
+
+(defmethod report :begin-test-ns [m]
+ (with-test-out
+ (println "\nTesting" (ns-name (:ns m)))))
+
+;; Ignore these message types:
+(defmethod report :end-test-ns [m])
+(defmethod report :begin-test-var [m])
+(defmethod report :end-test-var [m])
+
+
+
+;;; UTILITIES FOR ASSERTIONS
+
+(defn get-possibly-unbound-var
+ "Like var-get but returns nil if the var is unbound."
+ [v]
+ (try (var-get v)
+ (catch IllegalStateException e
+ nil)))
+
+(defn function?
+ "Returns true if argument is a function or a symbol that resolves to
+ a function (not a macro)."
+ [x]
+ (if (symbol? x)
+ (when-let [v (resolve x)]
+ (when-let [value (get-possibly-unbound-var v)]
+ (and (fn? value)
+ (not (:macro (meta v))))))
+ (fn? x)))
+
+(defn assert-predicate
+ "Returns generic assertion code for any functional predicate. The
+ 'expected' argument to 'report' will contains the original form, the
+ 'actual' argument will contain the form with all its sub-forms
+ evaluated. If the predicate returns false, the 'actual' form will
+ be wrapped in (not...)."
+ [msg form]
+ (let [args (rest form)
+ pred (first form)]
+ `(let [values# (list ~@args)
+ result# (apply ~pred values#)]
+ (if result#
+ (report {:type :pass, :message ~msg,
+ :expected '~form, :actual (cons ~pred values#)})
+ (report {:type :fail, :message ~msg,
+ :expected '~form, :actual (list '~'not (cons '~pred values#))}))
+ result#)))
+
+(defn assert-any
+ "Returns generic assertion code for any test, including macros, Java
+ method calls, or isolated symbols."
+ [msg form]
+ `(let [value# ~form]
+ (if value#
+ (report {:type :pass, :message ~msg,
+ :expected '~form, :actual value#})
+ (report {:type :fail, :message ~msg,
+ :expected '~form, :actual value#}))
+ value#))
+
+
+
+;;; ASSERTION METHODS
+
+;; You don't call these, but you can add methods to extend the 'is'
+;; macro. These define different kinds of tests, based on the first
+;; symbol in the test expression.
+
+(defmulti assert-expr
+ (fn [msg form]
+ (cond
+ (nil? form) :always-fail
+ (seq? form) (first form)
+ :else :default)))
+
+(defmethod assert-expr :always-fail [msg form]
+ ;; nil test: always fail
+ `(report {:type :fail, :message ~msg}))
+
+(defmethod assert-expr :default [msg form]
+ (if (and (sequential? form) (function? (first form)))
+ (assert-predicate msg form)
+ (assert-any msg form)))
+
+(defmethod assert-expr 'instance? [msg form]
+ ;; Test if x is an instance of y.
+ `(let [klass# ~(nth form 1)
+ object# ~(nth form 2)]
+ (let [result# (instance? klass# object#)]
+ (if result#
+ (report {:type :pass, :message ~msg,
+ :expected '~form, :actual (class object#)})
+ (report {:type :fail, :message ~msg,
+ :expected '~form, :actual (class object#)}))
+ result#)))
+
+(defmethod assert-expr 'thrown? [msg form]
+ ;; (is (thrown? c expr))
+ ;; Asserts that evaluating expr throws an exception of class c.
+ ;; Returns the exception thrown.
+ (let [klass (second form)
+ body (nthnext form 2)]
+ `(try ~@body
+ (report {:type :fail, :message ~msg,
+ :expected '~form, :actual nil})
+ (catch ~klass e#
+ (report {:type :pass, :message ~msg,
+ :expected '~form, :actual e#})
+ e#))))
+
+(defmethod assert-expr 'thrown-with-msg? [msg form]
+ ;; (is (thrown-with-msg? c re expr))
+ ;; Asserts that evaluating expr throws an exception of class c.
+ ;; Also asserts that the message string of the exception matches
+ ;; (with re-matches) the regular expression re.
+ (let [klass (nth form 1)
+ re (nth form 2)
+ body (nthnext form 3)]
+ `(try ~@body
+ (report {:type :fail, :message ~msg, :expected '~form, :actual nil})
+ (catch ~klass e#
+ (let [m# (.getMessage e#)]
+ (if (re-matches ~re m#)
+ (report {:type :pass, :message ~msg,
+ :expected '~form, :actual e#})
+ (report {:type :fail, :message ~msg,
+ :expected '~form, :actual e#})))
+ e#))))
+
+
+(defmacro try-expr
+ "Used by the 'is' macro to catch unexpected exceptions.
+ You don't call this."
+ [msg form]
+ `(try ~(assert-expr msg form)
+ (catch Throwable t#
+ (report {:type :error, :message ~msg,
+ :expected '~form, :actual t#}))))
+
+
+
+;;; ASSERTION MACROS
+
+;; You use these in your tests.
+
+(defmacro is
+ "Generic assertion macro. 'form' is any predicate test.
+ 'msg' is an optional message to attach to the assertion.
+
+ Example: (is (= 4 (+ 2 2)) \"Two plus two should be 4\")
+
+ Special forms:
+
+ (is (thrown? c body)) checks that an instance of c is thrown from
+ body, fails if not; then returns the thing thrown.
+
+ (is (thrown-with-msg? c re body)) checks that an instance of c is
+ thrown AND that the message on the exception matches (with
+ re-matches) the regular expression re."
+ ([form] `(is ~form nil))
+ ([form msg] `(try-expr ~msg ~form)))
+
+(defmacro are
+ "Checks multiple assertions with a template expression.
+ See clojure.template/do-template for an explanation of
+ templates.
+
+ Example: (are [x y] (= x y)
+ 2 (+ 1 1)
+ 4 (* 2 2))
+ Expands to:
+ (do (is (= 2 (+ 1 1)))
+ (is (= 4 (* 2 2))))
+
+ Note: This breaks some reporting features, such as line numbers."
+ [argv expr & args]
+ `(temp/do-template ~argv (is ~expr) ~@args))
+
+(defmacro testing
+ "Adds a new string to the list of testing contexts. May be nested,
+ but must occur inside a test function (deftest)."
+ [string & body]
+ `(binding [*testing-contexts* (conj *testing-contexts* ~string)]
+ ~@body))
+
+
+
+;;; DEFINING TESTS
+
+(defmacro with-test
+ "Takes any definition form (that returns a Var) as the first argument.
+ Remaining body goes in the :test metadata function for that Var.
+
+ When *load-tests* is false, only evaluates the definition, ignoring
+ the tests."
+ [definition & body]
+ (if *load-tests*
+ `(doto ~definition (alter-meta! assoc :test (fn [] ~@body)))
+ definition))
+
+
+(defmacro deftest
+ "Defines a test function with no arguments. Test functions may call
+ other tests, so tests may be composed. If you compose tests, you
+ should also define a function named test-ns-hook; run-tests will
+ call test-ns-hook instead of testing all vars.
+
+ Note: Actually, the test body goes in the :test metadata on the var,
+ and the real function (the value of the var) calls test-var on
+ itself.
+
+ When *load-tests* is false, deftest is ignored."
+ [name & body]
+ (when *load-tests*
+ `(def ~(with-meta name {:test `(fn [] ~@body)})
+ (fn [] (test-var (var ~name))))))
+
+(defmacro deftest-
+ "Like deftest but creates a private var."
+ [name & body]
+ (when *load-tests*
+ `(def ~(with-meta name {:test `(fn [] ~@body), :private true})
+ (fn [] (test-var (var ~name))))))
+
+
+(defmacro set-test
+ "Experimental.
+ Sets :test metadata of the named var to a fn with the given body.
+ The var must already exist. Does not modify the value of the var.
+
+ When *load-tests* is false, set-test is ignored."
+ [name & body]
+ (when *load-tests*
+ `(alter-meta! (var ~name) assoc :test (fn [] ~@body))))
+
+
+
+;;; DEFINING FIXTURES
+
+(defn- add-ns-meta
+ "Adds elements in coll to the current namespace metadata as the
+ value of key."
+ [key coll]
+ (alter-meta! *ns* assoc key (concat (key (meta *ns*)) coll)))
+
+(defmulti use-fixtures (fn [fixture-type & args] fixture-type))
+
+(defmethod use-fixtures :each [fixture-type & args]
+ (add-ns-meta ::each-fixtures args))
+
+(defmethod use-fixtures :once [fixture-type & args]
+ (add-ns-meta ::once-fixtures args))
+
+(defn- default-fixture
+ "The default, empty, fixture function. Just calls its argument."
+ [f]
+ (f))
+
+(defn compose-fixtures
+ "Composes two fixture functions, creating a new fixture function
+ that combines their behavior."
+ [f1 f2]
+ (fn [g] (f1 (fn [] (f2 g)))))
+
+(defn join-fixtures
+ "Composes a collection of fixtures, in order. Always returns a valid
+ fixture function, even if the collection is empty."
+ [fixtures]
+ (reduce compose-fixtures default-fixture fixtures))
+
+
+
+
+;;; RUNNING TESTS: LOW-LEVEL FUNCTIONS
+
+(defn test-var
+ "If v has a function in its :test metadata, calls that function,
+ with *testing-vars* bound to (conj *testing-vars* v)."
+ [v]
+ (when-let [t (:test (meta v))]
+ (binding [*testing-vars* (conj *testing-vars* v)]
+ (report {:type :begin-test-var, :var v})
+ (inc-report-counter :test)
+ (try (t)
+ (catch Throwable e
+ (report {:type :error, :message "Uncaught exception, not in assertion."
+ :expected nil, :actual e})))
+ (report {:type :end-test-var, :var v}))))
+
+(defn test-all-vars
+ "Calls test-var on every var interned in the namespace, with fixtures."
+ [ns]
+ (let [once-fixture-fn (join-fixtures (::once-fixtures (meta ns)))
+ each-fixture-fn (join-fixtures (::each-fixtures (meta ns)))]
+ (once-fixture-fn
+ (fn []
+ (doseq [v (vals (ns-interns ns))]
+ (when (:test (meta v))
+ (each-fixture-fn (fn [] (test-var v)))))))))
+
+(defn test-ns
+ "If the namespace defines a function named test-ns-hook, calls that.
+ Otherwise, calls test-all-vars on the namespace. 'ns' is a
+ namespace object or a symbol.
+
+ Internally binds *report-counters* to a ref initialized to
+ *inital-report-counters*. Returns the final, dereferenced state of
+ *report-counters*."
+ [ns]
+ (binding [*report-counters* (ref *initial-report-counters*)]
+ (let [ns-obj (the-ns ns)]
+ (report {:type :begin-test-ns, :ns ns-obj})
+ ;; If the namespace has a test-ns-hook function, call that:
+ (if-let [v (find-var (symbol (str (ns-name ns-obj)) "test-ns-hook"))]
+ ((var-get v))
+ ;; Otherwise, just test every var in the namespace.
+ (test-all-vars ns-obj))
+ (report {:type :end-test-ns, :ns ns-obj}))
+ @*report-counters*))
+
+
+
+;;; RUNNING TESTS: HIGH-LEVEL FUNCTIONS
+
+(defn run-tests
+ "Runs all tests in the given namespaces; prints results.
+ Defaults to current namespace if none given."
+ ([] (run-tests *ns*))
+ ([& namespaces]
+ (report (assoc (apply merge-with + (map test-ns namespaces))
+ :type :summary))))
+
+(defn run-all-tests
+ "Runs all tests in all namespaces; prints results.
+ Optional argument is a regular expression; only namespaces with
+ names matching the regular expression (with re-matches) will be
+ tested."
+ ([] (apply run-tests (all-ns)))
+ ([re] (apply run-tests (filter #(re-matches re (name (ns-name %))) (all-ns)))))
diff --git a/src/clj/clojure/test/tap.clj b/src/clj/clojure/test/tap.clj
new file mode 100644
index 00000000..6f4b57a6
--- /dev/null
+++ b/src/clj/clojure/test/tap.clj
@@ -0,0 +1,111 @@
+; Copyright (c) Rich Hickey. 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_is/tap.clj: Extension to test for TAP output
+
+;; by Stuart Sierra
+;; March 31, 2009
+
+;; Inspired by ClojureCheck by Meikel Brandmeyer:
+;; http://kotka.de/projects/clojure/clojurecheck.html
+
+
+;; DOCUMENTATION
+;;
+;; This is an extension to clojure.test that adds support
+;; for the Test Anything Protocol (TAP).
+;;
+;; TAP is a simple text-based syntax for reporting test results. TAP
+;; was originally develped for Perl, and now has implementations in
+;; several languages. For more information on TAP, see
+;; http://testanything.org/ and
+;; http://search.cpan.org/~petdance/TAP-1.0.0/TAP.pm
+;;
+;; To use this library, wrap any calls to
+;; clojure.test/run-tests in the with-tap-output macro,
+;; like this:
+;;
+;; (use 'clojure.test)
+;; (use 'clojure.test.tap)
+;;
+;; (with-tap-output
+;; (run-tests 'my.cool.library))
+
+
+
+(ns clojure.test.tap
+ (:require [clojure.test :as t]
+ [clojure.stacktrace :as stack]))
+
+(defn print-tap-plan
+ "Prints a TAP plan line like '1..n'. n is the number of tests"
+ [n]
+ (println (str "1.." n)))
+
+(defn print-tap-diagnostic
+ "Prints a TAP diagnostic line. data is a (possibly multi-line)
+ string."
+ [data]
+ (doseq [line (.split data "\n")]
+ (println "#" line)))
+
+(defn print-tap-pass
+ "Prints a TAP 'ok' line. msg is a string, with no line breaks"
+ [msg]
+ (println "ok" msg))
+
+(defn print-tap-fail
+ "Prints a TAP 'not ok' line. msg is a string, with no line breaks"
+ [msg]
+ (println "not ok" msg))
+
+;; This multimethod will override test/report
+(defmulti tap-report (fn [data] (:type data)))
+
+(defmethod tap-report :default [data]
+ (t/with-test-out
+ (print-tap-diagnostic (pr-str data))))
+
+(defmethod tap-report :pass [data]
+ (t/with-test-out
+ (t/inc-report-counter :pass)
+ (print-tap-pass (t/testing-vars-str))
+ (when (seq t/*testing-contexts*)
+ (print-tap-diagnostic (t/testing-contexts-str)))
+ (when (:message data)
+ (print-tap-diagnostic (:message data)))
+ (print-tap-diagnostic (str "expected:" (pr-str (:expected data))))
+ (print-tap-diagnostic (str " actual:" (pr-str (:actual data))))))
+
+(defmethod tap-report :error [data]
+ (t/with-test-out
+ (t/inc-report-counter :error)
+ (print-tap-fail (t/testing-vars-str))
+ (when (seq t/*testing-contexts*)
+ (print-tap-diagnostic (t/testing-contexts-str)))
+ (when (:message data)
+ (print-tap-diagnostic (:message data)))
+ (print-tap-diagnostic "expected:" (pr-str (:expected data)))
+ (print-tap-diagnostic " actual: ")
+ (print-tap-diagnostic
+ (with-out-str
+ (if (instance? Throwable (:actual data))
+ (stack/print-cause-trace (:actual data) t/*stack-trace-depth*)
+ (prn (:actual data)))))))
+
+(defmethod tap-report :summary [data]
+ (t/with-test-out
+ (print-tap-plan (+ (:pass data) (:fail data) (:error data)))))
+
+
+(defmacro with-tap-output
+ "Execute body with modified test reporting functions that produce
+ TAP output"
+ [& body]
+ `(binding [t/report tap-report]
+ ~@body))
diff --git a/src/clj/clojure/walk.clj b/src/clj/clojure/walk.clj
new file mode 100644
index 00000000..6b5bad90
--- /dev/null
+++ b/src/clj/clojure/walk.clj
@@ -0,0 +1,133 @@
+; Copyright (c) Rich Hickey. 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.
+
+;;; walk.clj - generic tree walker with replacement
+
+;; by Stuart Sierra
+;; December 15, 2008
+
+;; This file defines a generic tree walker for Clojure data
+;; structures. It takes any data structure (list, vector, map, set,
+;; seq), calls a function on every element, and uses the return value
+;; of the function in place of the original. This makes it fairly
+;; easy to write recursive search-and-replace functions, as shown in
+;; the examples.
+;;
+;; Note: "walk" supports all Clojure data structures EXCEPT maps
+;; created with sorted-map-by. There is no (obvious) way to retrieve
+;; the sorting function.
+;;
+;; CHANGE LOG:
+;;
+;; * December 15, 2008: replaced 'walk' with 'prewalk' & 'postwalk'
+;;
+;; * December 9, 2008: first version
+
+
+(ns
+ #^{:author "Stuart Sierra",
+ :doc "This file defines a generic tree walker for Clojure data
+structures. It takes any data structure (list, vector, map, set,
+seq), calls a function on every element, and uses the return value
+of the function in place of the original. This makes it fairly
+easy to write recursive search-and-replace functions, as shown in
+the examples.
+
+Note: \"walk\" supports all Clojure data structures EXCEPT maps
+created with sorted-map-by. There is no (obvious) way to retrieve
+the sorting function."}
+ clojure.walk)
+
+(defn walk
+ "Traverses form, an arbitrary data structure. inner and outer are
+ functions. Applies inner to each element of form, building up a
+ data structure of the same type, then applies outer to the result.
+ Recognizes all Clojure data structures except sorted-map-by.
+ Consumes seqs as with doall."
+ [inner outer form]
+ (cond
+ (list? form) (outer (apply list (map inner form)))
+ (seq? form) (outer (doall (map inner form)))
+ (vector? form) (outer (vec (map inner form)))
+ (map? form) (outer (into (if (sorted? form) (sorted-map) {})
+ (map inner form)))
+ (set? form) (outer (into (if (sorted? form) (sorted-set) #{})
+ (map inner form)))
+ :else (outer form)))
+
+(defn postwalk
+ "Performs a depth-first, post-order traversal of form. Calls f on
+ each sub-form, uses f's return value in place of the original.
+ Recognizes all Clojure data structures except sorted-map-by.
+ Consumes seqs as with doall."
+ [f form]
+ (walk (partial postwalk f) f form))
+
+(defn prewalk
+ "Like postwalk, but does pre-order traversal."
+ [f form]
+ (walk (partial prewalk f) identity (f form)))
+
+
+;; Note: I wanted to write:
+;;
+;; (defn walk
+;; [f form]
+;; (let [pf (partial walk f)]
+;; (if (coll? form)
+;; (f (into (empty form) (map pf form)))
+;; (f form))))
+;;
+;; but this throws a ClassCastException when applied to a map.
+
+
+(defn postwalk-demo
+ "Demonstrates the behavior of postwalk by printing each form as it is
+ walked. Returns form."
+ [form]
+ (postwalk (fn [x] (print "Walked: ") (prn x) x) form))
+
+(defn prewalk-demo
+ "Demonstrates the behavior of prewalk by printing each form as it is
+ walked. Returns form."
+ [form]
+ (prewalk (fn [x] (print "Walked: ") (prn x) x) form))
+
+(defn keywordize-keys
+ "Recursively transforms all map keys from strings to keywords."
+ [m]
+ (let [f (fn [[k v]] (if (string? k) [(keyword k) v] [k v]))]
+ ;; only apply to maps
+ (postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m)))
+
+(defn stringify-keys
+ "Recursively transforms all map keys from keywords to strings."
+ [m]
+ (let [f (fn [[k v]] (if (keyword? k) [(name k) v] [k v]))]
+ ;; only apply to maps
+ (postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m)))
+
+(defn prewalk-replace
+ "Recursively transforms form by replacing keys in smap with their
+ values. Like clojure/replace but works on any data structure. Does
+ replacement at the root of the tree first."
+ [smap form]
+ (prewalk (fn [x] (if (contains? smap x) (smap x) x)) form))
+
+(defn postwalk-replace
+ "Recursively transforms form by replacing keys in smap with their
+ values. Like clojure/replace but works on any data structure. Does
+ replacement at the leaves of the tree first."
+ [smap form]
+ (postwalk (fn [x] (if (contains? smap x) (smap x) x)) form))
+
+(defn macroexpand-all
+ "Recursively performs all possible macroexpansions in form."
+ [form]
+ (prewalk (fn [x] (if (seq? x) (macroexpand x) x)) form))
+
diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java
index cb14d96f..9d744d70 100644
--- a/src/jvm/clojure/lang/Compiler.java
+++ b/src/jvm/clojure/lang/Compiler.java
@@ -971,7 +971,7 @@ static class InstanceFieldExpr extends FieldExpr implements AssignableExpr{
public void emitAssign(C context, FnExpr fn, GeneratorAdapter gen,
Expr val){
gen.visitLineNumber(line, gen.mark());
- if(targetClass != null)
+ if(targetClass != null && field != null)
{
target.emit(C.EXPRESSION, fn, gen);
gen.checkCast(Type.getType(targetClass));
diff --git a/src/jvm/clojure/lang/LispReader.java b/src/jvm/clojure/lang/LispReader.java
index 14c39399..5bf22e66 100644
--- a/src/jvm/clojure/lang/LispReader.java
+++ b/src/jvm/clojure/lang/LispReader.java
@@ -47,9 +47,9 @@ static Pattern symbolPat = Pattern.compile("[:]?([\\D&&[^/]].*/)?([\\D&&[^/]][^/
//static Pattern intPat = Pattern.compile("[-+]?[0-9]+\\.?");
static Pattern intPat =
Pattern.compile(
- "([-+]?)(?:(0)|([1-9][0-9]*)|0[xX]([0-9A-Fa-f]+)|0([0-7]+)|([1-9][0-9]?)[rR]([0-9A-Za-z]+)|0[0-9]+)\\.?");
+ "([-+]?)(?:(0)|([1-9][0-9]*)|0[xX]([0-9A-Fa-f]+)|0([0-7]+)|([1-9][0-9]?)[rR]([0-9A-Za-z]+)|0[0-9]+)");
static Pattern ratioPat = Pattern.compile("([-+]?[0-9]+)/([0-9]+)");
-static Pattern floatPat = Pattern.compile("[-+]?[0-9]+(\\.[0-9]+)?([eE][-+]?[0-9]+)?[M]?");
+static Pattern floatPat = Pattern.compile("([-+]?[0-9]+(\\.[0-9]*)?([eE][-+]?[0-9]+)?)(M)?");
static final Symbol SLASH = Symbol.create("/");
static final Symbol CLOJURE_SLASH = Symbol.create("clojure.core","/");
//static Pattern accessorPat = Pattern.compile("\\.[a-zA-Z_]\\w*");
@@ -344,8 +344,8 @@ private static Object matchNumber(String s){
m = floatPat.matcher(s);
if(m.matches())
{
- if(s.charAt(s.length() - 1) == 'M')
- return new BigDecimal(s.substring(0, s.length() - 1));
+ if(m.group(4) != null)
+ return new BigDecimal(m.group(1));
return Double.parseDouble(s);
}
m = ratioPat.matcher(s);
@@ -607,6 +607,10 @@ static Symbol registerArg(int n){
static class ArgReader extends AFn{
public Object invoke(Object reader, Object pct) throws Exception{
PushbackReader r = (PushbackReader) reader;
+ if(ARG_ENV.deref() == null)
+ {
+ return interpretToken(readToken(r, '%'));
+ }
int ch = r.read();
unread(r, ch);
//% alone is first arg
diff --git a/src/jvm/clojure/lang/LockingTransaction.java b/src/jvm/clojure/lang/LockingTransaction.java
index 66a262e7..4976d169 100644
--- a/src/jvm/clojure/lang/LockingTransaction.java
+++ b/src/jvm/clojure/lang/LockingTransaction.java
@@ -281,11 +281,14 @@ Object run(Callable fn) throws Exception{
Ref ref = e.getKey();
Object oldval = ref.tvals == null ? null : ref.tvals.val;
Object newval = e.getValue();
+ int hcount = ref.histCount();
+
if(ref.tvals == null)
{
ref.tvals = new Ref.TVal(newval, commitPoint, msecs);
}
- else if(ref.faults.get() > 0)
+ else if((ref.faults.get() > 0 && hcount < ref.maxHistory)
+ || hcount < ref.minHistory)
{
ref.tvals = new Ref.TVal(newval, commitPoint, msecs, ref.tvals);
ref.faults.set(0);
diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java
index 728a2a76..263ec551 100644
--- a/src/jvm/clojure/lang/RT.java
+++ b/src/jvm/clojure/lang/RT.java
@@ -179,6 +179,7 @@ final static public Var ERR =
final static Keyword TAG_KEY = Keyword.intern(null, "tag");
final static public Var AGENT = Var.intern(CLOJURE_NS, Symbol.create("*agent*"), null);
final static public Var READEVAL = Var.intern(CLOJURE_NS, Symbol.create("*read-eval*"), T);
+final static public Var ASSERT = Var.intern(CLOJURE_NS, Symbol.create("*assert*"), T);
final static public Var MACRO_META = Var.intern(CLOJURE_NS, Symbol.create("*macro-meta*"), null);
final static public Var MATH_CONTEXT = Var.intern(CLOJURE_NS, Symbol.create("*math-context*"), null);
static Keyword LINE_KEY = Keyword.intern(null, "line");
@@ -720,12 +721,6 @@ static public Object dissoc(Object coll, Object key) throws Exception{
static public Object nth(Object coll, int n){
if(coll instanceof Indexed)
return ((Indexed) coll).nth(n);
- return do_nth(coll,n);
-}
-
-static public Object do_nth(Object coll, int n){
- if(coll instanceof Indexed)
- return ((Indexed) coll).nth(n);
if(coll == null)
return null;
else if(coll instanceof String)
diff --git a/src/jvm/clojure/lang/Ref.java b/src/jvm/clojure/lang/Ref.java
index 90faedcc..fef7c439 100644
--- a/src/jvm/clojure/lang/Ref.java
+++ b/src/jvm/clojure/lang/Ref.java
@@ -26,6 +26,24 @@ public class Ref extends ARef implements IFn, Comparable<Ref>, IRef{
return 1;
}
+public int getMinHistory(){
+ return minHistory;
+}
+
+public Ref setMinHistory(int minHistory){
+ this.minHistory = minHistory;
+ return this;
+}
+
+public int getMaxHistory(){
+ return maxHistory;
+}
+
+public Ref setMaxHistory(int maxHistory){
+ this.maxHistory = maxHistory;
+ return this;
+}
+
public static class TVal{
Object val;
long point;
@@ -60,6 +78,9 @@ LockingTransaction.Info tinfo;
//IFn validator;
final long id;
+volatile int minHistory = 0;
+volatile int maxHistory = 10;
+
static final AtomicLong ids = new AtomicLong();
public Ref(Object initVal) throws Exception{
@@ -187,6 +208,29 @@ public void trimHistory(){
}
}
+public int getHistoryCount(){
+ try
+ {
+ lock.writeLock().lock();
+ return histCount();
+ }
+ finally
+ {
+ lock.writeLock().unlock();
+ }
+}
+
+int histCount(){
+ if(tvals == null)
+ return 0;
+ else
+ {
+ int count = 0;
+ for(TVal tv = tvals.next;tv != tvals;tv = tv.next)
+ count++;
+ return count;
+ }
+}
final public IFn fn(){
return (IFn) deref();
diff --git a/test/clojure/test_clojure.clj b/test/clojure/test_clojure.clj
new file mode 100644
index 00000000..8b1e16ae
--- /dev/null
+++ b/test/clojure/test_clojure.clj
@@ -0,0 +1,68 @@
+; Copyright (c) Rich Hickey. 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.
+;
+
+;; clojure.test-clojure
+;;
+;; Tests for the facilities provided by Clojure
+;;
+;; scgilardi (gmail)
+;; Created 22 October 2008
+
+(ns clojure.test-clojure
+ (:use [clojure.test :only (run-tests)])
+ (:gen-class))
+
+(def test-names
+ [:reader
+ :printer
+ :compilation
+ :evaluation
+ :special
+ :macros
+ :metadata
+ :ns-libs
+ :logic
+ :predicates
+ :control
+ :data-structures
+ :numbers
+ :sequences
+ :for
+ :multimethods
+ :other-functions
+ :vars
+ :refs
+ :agents
+ :atoms
+ :parallel
+ :java-interop
+ :test
+ :test-fixtures
+ ;; libraries
+ :clojure-set
+ :clojure-xml
+ :clojure-zip
+ ])
+
+(def test-namespaces
+ (map #(symbol (str "clojure.test-clojure." (name %)))
+ test-names))
+
+(defn run
+ "Runs all defined tests"
+ []
+ (println "Loading tests...")
+ (apply require :reload-all test-namespaces)
+ (apply run-tests test-namespaces))
+
+(defn -main
+ "Run all defined tests from the command line"
+ [& args]
+ (run)
+ (System/exit 0))
diff --git a/test/clojure/test_clojure/agents.clj b/test/clojure/test_clojure/agents.clj
new file mode 100644
index 00000000..63b6c8cc
--- /dev/null
+++ b/test/clojure/test_clojure/agents.clj
@@ -0,0 +1,43 @@
+; Copyright (c) Rich Hickey. 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.
+
+;; Author: Shawn Hoover
+
+(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..672a1487
--- /dev/null
+++ b/test/clojure/test_clojure/atoms.clj
@@ -0,0 +1,20 @@
+; Copyright (c) Rich Hickey. 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.
+
+;;Author: Frantisek Sodomka
+
+(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..3339134d
--- /dev/null
+++ b/test/clojure/test_clojure/clojure_set.clj
@@ -0,0 +1,120 @@
+; Copyright (c) Rich Hickey. 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.
+
+;; Author: Frantisek Sodomka
+
+
+(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..cf7eb950
--- /dev/null
+++ b/test/clojure/test_clojure/clojure_xml.clj
@@ -0,0 +1,21 @@
+; Copyright (c) Rich Hickey. 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.
+
+;;Author: Frantisek Sodomka
+
+
+(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..f4190ece
--- /dev/null
+++ b/test/clojure/test_clojure/clojure_zip.clj
@@ -0,0 +1,48 @@
+; Copyright (c) Rich Hickey. 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.
+
+; Author: Frantisek Sodomka
+
+
+(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..c633db6d
--- /dev/null
+++ b/test/clojure/test_clojure/compilation.clj
@@ -0,0 +1,39 @@
+; Copyright (c) Rich Hickey. 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.
+
+; Author: Frantisek Sodomka
+
+
+(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..3a223d58
--- /dev/null
+++ b/test/clojure/test_clojure/control.clj
@@ -0,0 +1,117 @@
+; Copyright (c) Rich Hickey. 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.
+
+; Author: Frantisek Sodomka
+
+;;
+;; 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..19fafe62
--- /dev/null
+++ b/test/clojure/test_clojure/data_structures.clj
@@ -0,0 +1,736 @@
+; Copyright (c) Rich Hickey. 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.
+
+; Author: Frantisek Sodomka
+
+
+(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} ))
+
+
+;; *** Sets ***
+
+(deftest test-hash-set
+ (are [x] (set? x)
+ #{}
+ #{1 2}
+ (hash-set)
+ (hash-set 1 2) )
+
+ ; order isn't important
+ (are [x y] (= x y)
+ #{1 2} #{2 1}
+ #{3 1 2} #{1 2 3}
+ (hash-set 1 2) (hash-set 2 1)
+ (hash-set 3 1 2) (hash-set 1 2 3) )
+
+ ; equal and unique
+ (are [x] (and (= (hash-set x) #{x})
+ (= (hash-set x 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} )
+
+ (are [x y] (= x y)
+ ; equal classes
+ (class #{}) (class (hash-set))
+ (class #{1 2}) (class (hash-set 1 2))
+
+ ; creating
+ (hash-set) #{}
+ (hash-set 1) #{1}
+ (hash-set 1 2) #{1 2}
+
+ ; nesting
+ (hash-set 1 (hash-set 2 3) (hash-set 3 (hash-set 4 5 (hash-set 6 (hash-set 7)))))
+ #{1 #{2 3} #{3 #{4 5 #{6 #{7}}}}}
+
+ ; different data structures
+ (hash-set true false nil)
+ #{true false nil}
+ (hash-set 1 2.5 2/3 "ab" \x 'cd :kw)
+ #{1 2.5 2/3 "ab" \x 'cd :kw}
+ (hash-set (list 1 2) [3 4] {:a 1 :b 2} #{:c :d})
+ #{'(1 2) [3 4] {:a 1 :b 2} #{:c :d}}
+
+ ; evaluation
+ (hash-set (+ 1 2) [(+ 2 3) :a] (hash-set (* 2 3) 8))
+ #{3 [5 :a] #{6 8}}
+
+ ; special cases
+ (hash-set nil) #{nil}
+ (hash-set 1 nil) #{1 nil}
+ (hash-set nil 2) #{nil 2}
+ (hash-set #{}) #{#{}}
+ (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 [x] (set? x)
+ (sorted-set)
+ (sorted-set 1 2) )
+
+ ; equal and unique
+ (are [x] (and (= (sorted-set x) #{x})
+ (= (sorted-set x x) (sorted-set 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}
+ )
+ ; 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 [x y] (= x y)
+ ; 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 [x] (set? (set x))
+ () '(1 2)
+ [] [1 2]
+ #{} #{1 2}
+ {} {:a 1 :b 2}
+ (into-array []) (into-array [1 2])
+ "" "abc" )
+
+ ; unique
+ (are [x] (= (set [x 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} )
+
+ ; conversion
+ (are [x y] (= (set x) y)
+ () #{}
+ '(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 [x] (= (disj x) x)
+ #{}
+ #{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 [x] (= (class (disj x)) (class x))
+ (hash-set)
+ (hash-set 1 2)
+ (sorted-set)
+ (sorted-set 1 2) )
+
+ (are [x y] (= x y)
+ (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}) #{} ))
+
+
diff --git a/test/clojure/test_clojure/evaluation.clj b/test/clojure/test_clojure/evaluation.clj
new file mode 100644
index 00000000..283896c5
--- /dev/null
+++ b/test/clojure/test_clojure/evaluation.clj
@@ -0,0 +1,229 @@
+; Copyright (c) Rich Hickey. 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.
+
+
+;; Tests for the Clojure functions documented at the URL:
+;;
+;; http://clojure.org/Evaluation
+;;
+;; by J. McConnell
+;; Created 22 October 2008
+
+(ns clojure.test-clojure.evaluation
+ (:use clojure.test))
+
+(import '(java.lang Boolean)
+ '(clojure.lang Compiler Compiler$CompilerException))
+
+(defmacro test-that
+ "Provides a useful way for specifying the purpose of tests. If the first-level
+ forms are lists that make a call to a clojure.test function, it supplies the
+ purpose as the msg argument to those functions. Otherwise, the purpose just
+ acts like a comment and the forms are run unchanged."
+ [purpose & test-forms]
+ (let [tests (map
+ #(if (= (:ns (meta (resolve (first %))))
+ (the-ns 'clojure.test))
+ (concat % (list purpose))
+ %)
+ test-forms)]
+ `(do ~@tests)))
+
+(deftest Eval
+ (is (= (eval '(+ 1 2 3)) (Compiler/eval '(+ 1 2 3))))
+ (is (= (eval '(list 1 2 3)) '(1 2 3)))
+ (is (= (eval '(list + 1 2 3)) (list clojure.core/+ 1 2 3)))
+ (test-that "Non-closure fns are supported as code"
+ (is (= (eval (eval '(list + 1 2 3))) 6)))
+ (is (= (eval (list '+ 1 2 3)) 6)))
+
+; not using Clojure's RT/classForName since a bug in it could hide a bug in
+; eval's resolution
+(defn class-for-name [name]
+ (java.lang.Class/forName name))
+
+(defmacro in-test-ns [& body]
+ `(binding [*ns* *ns*]
+ (in-ns 'clojure.test-clojure.evaluation)
+ ~@body))
+
+;;; Literals tests ;;;
+
+(defmacro #^{:private true} evaluates-to-itself? [expr]
+ `(let [v# ~expr
+ q# (quote ~expr)]
+ (is (= (eval q#) q#) (str q# " does not evaluate to itself"))))
+
+(deftest Literals
+ ; Strings, numbers, characters, nil and keywords should evaluate to themselves
+ (evaluates-to-itself? "test")
+ (evaluates-to-itself? "test
+ multi-line
+ string")
+ (evaluates-to-itself? 1)
+ (evaluates-to-itself? 1.0)
+ (evaluates-to-itself? 1.123456789)
+ (evaluates-to-itself? 1/2)
+ (evaluates-to-itself? 1M)
+ (evaluates-to-itself? 999999999999999999)
+ (evaluates-to-itself? \a)
+ (evaluates-to-itself? \newline)
+ (evaluates-to-itself? nil)
+ (evaluates-to-itself? :test)
+ ; Boolean literals should evaluate to Boolean.{TRUE|FALSE}
+ (is (identical? (eval true) Boolean/TRUE))
+ (is (identical? (eval false) Boolean/FALSE)))
+
+;;; Symbol resolution tests ;;;
+
+(def foo "abc")
+(in-ns 'resolution-test)
+(def bar 123)
+(def #^{:private true} baz 456)
+(in-ns 'clojure.test-clojure.evaluation)
+
+(defn a-match? [re s] (not (nil? (re-matches re s))))
+
+(defmacro throws-with-msg
+ ([re form] `(throws-with-msg ~re ~form Exception))
+ ([re form x] `(throws-with-msg
+ ~re
+ ~form
+ ~(if (instance? Exception x) x Exception)
+ ~(if (instance? String x) x nil)))
+ ([re form class msg]
+ `(let [ex# (try
+ ~form
+ (catch ~class e# e#)
+ (catch Exception e#
+ (let [cause# (.getCause e#)]
+ (if (= ~class (class cause#)) cause# (throw e#)))))]
+ (is (a-match? ~re (.toString ex#))
+ (or ~msg
+ (str "Expected exception that matched " (pr-str ~re)
+ ", but got exception with message: \"" ex#))))))
+
+(deftest SymbolResolution
+ (test-that
+ "If a symbol is namespace-qualified, the evaluated value is the value
+ of the binding of the global var named by the symbol"
+ (is (= (eval 'resolution-test/bar) 123)))
+
+ (test-that
+ "It is an error if there is no global var named by the symbol"
+ (throws-with-msg
+ #".*Unable to resolve symbol: bar.*" (eval 'bar)))
+
+ (test-that
+ "It is an error if the symbol reference is to a non-public var in a
+ different namespace"
+ (throws-with-msg
+ #".*resolution-test/baz is not public.*"
+ (eval 'resolution-test/baz)
+ Compiler$CompilerException))
+
+ (test-that
+ "If a symbol is package-qualified, its value is the Java class named by the
+ symbol"
+ (is (= (eval 'java.lang.Math) (class-for-name "java.lang.Math"))))
+
+ (test-that
+ "If a symbol is package-qualified, it is an error if there is no Class named
+ by the symbol"
+ (is (thrown? Compiler$CompilerException (eval 'java.lang.FooBar))))
+
+ (test-that
+ "If a symbol is not qualified, the following applies, in this order:
+
+ 1. If it names a special form it is considered a special form, and must
+ be utilized accordingly.
+
+ 2. A lookup is done in the current namespace to see if there is a mapping
+ from the symbol to a class. If so, the symbol is considered to name a
+ Java class object.
+
+ 3. If in a local scope (i.e. in a function definition), a lookup is done
+ to see if it names a local binding (e.g. a function argument or
+ let-bound name). If so, the value is the value of the local binding.
+
+ 4. A lookup is done in the current namespace to see if there is a mapping
+ from the symbol to a var. If so, the value is the value of the binding
+ of the var referred-to by the symbol.
+
+ 5. It is an error."
+
+ ; First
+ (doall (for [form '(def if do let quote var fn loop recur throw try
+ monitor-enter monitor-exit)]
+ (is (thrown? Compiler$CompilerException (eval form)))))
+ (let [if "foo"]
+ (is (thrown? Compiler$CompilerException (eval 'if)))
+
+ ; Second
+ (is (= (eval 'Boolean) (class-for-name "java.lang.Boolean"))))
+ (let [Boolean "foo"]
+ (is (= (eval 'Boolean) (class-for-name "java.lang.Boolean"))))
+
+ ; Third
+ (is (= (eval '(let [foo "bar"] foo)) "bar"))
+
+ ; Fourth
+ (in-test-ns (is (= (eval 'foo) "abc")))
+ (is (thrown? Compiler$CompilerException (eval 'bar))) ; not in this namespace
+
+ ; Fifth
+ (is (thrown? Compiler$CompilerException (eval 'foobar)))))
+
+;;; Metadata tests ;;;
+
+(defstruct struct-with-symbols (with-meta 'k {:a "A"}))
+
+(deftest Metadata
+ (test-that
+ "If a Symbol has metadata, it will not be part of the resulting value"
+ (is (not (nil? (meta (with-meta (symbol "test") {:doc "doc"})))))
+ (is (nil? (meta (eval (with-meta (symbol "test") {:doc "doc"}))))))
+
+ (test-that
+ "find returns key symbols and their metadata"
+ (let [s (struct struct-with-symbols 1)]
+ (is (= {:a "A"} (meta (first (find s 'k))))))))
+
+;;; Collections tests ;;;
+(def x 1)
+(def y 2)
+
+(deftest Collections
+ (in-test-ns
+ (test-that
+ "Vectors and Maps yield vectors and (hash) maps whose contents are the
+ evaluated values of the objects they contain."
+ (is (= (eval '[x y 3]) [1 2 3]))
+ (is (= (eval '{:x x :y y :z 3}) {:x 1 :y 2 :z 3}))
+ (is (instance? clojure.lang.IPersistentMap (eval '{:x x :y y})))))
+
+ (in-test-ns
+ (test-that
+ "Metadata maps yield maps whose contents are the evaluated values of
+ the objects they contain. If a vector or map has metadata, the evaluated
+ metadata map will become the metadata of the resulting value."
+ (is (= (eval #^{:x x} '[x y]) #^{:x 1} [1 2]))))
+
+ (test-that
+ "An empty list () evaluates to an empty list."
+ (is (= (eval '()) ()))
+ (is (empty? (eval ())))
+ (is (= (eval (list)) ())))
+
+ (test-that
+ "Non-empty lists are considered calls"
+ (is (thrown? Compiler$CompilerException (eval '(1 2 3))))))
+
+(deftest Macros)
+
+(deftest Loading)
diff --git a/test/clojure/test_clojure/for.clj b/test/clojure/test_clojure/for.clj
new file mode 100644
index 00000000..d8ebed26
--- /dev/null
+++ b/test/clojure/test_clojure/for.clj
@@ -0,0 +1,123 @@
+; Copyright (c) Rich Hickey. 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.
+
+;; Tests for the Clojure 'for' macro
+;;
+;; by Chouser
+;; Created Dec 2008
+
+(ns clojure.test-clojure.for
+ (:use clojure.test))
+
+(deftest Docstring-Example
+ (is (= (take 100 (for [x (range 100000000)
+ y (range 1000000) :while (< y x)]
+ [x y]))
+ '([1 0] [2 0] [2 1] [3 0] [3 1] [3 2] [4 0] [4 1] [4 2] [4 3]
+ [5 0] [5 1] [5 2] [5 3] [5 4]
+ [6 0] [6 1] [6 2] [6 3] [6 4] [6 5]
+ [7 0] [7 1] [7 2] [7 3] [7 4] [7 5] [7 6]
+ [8 0] [8 1] [8 2] [8 3] [8 4] [8 5] [8 6] [8 7]
+ [9 0] [9 1] [9 2] [9 3] [9 4] [9 5] [9 6] [9 7] [9 8]
+ [10 0] [10 1] [10 2] [10 3] [10 4] [10 5] [10 6] [10 7] [10 8] [10 9]
+ [11 0] [11 1] [11 2] [11 3] [11 4] [11 5] [11 6] [11 7] [11 8] [11 9]
+ [11 10]
+ [12 0] [12 1] [12 2] [12 3] [12 4] [12 5] [12 6] [12 7] [12 8] [12 9]
+ [12 10] [12 11]
+ [13 0] [13 1] [13 2] [13 3] [13 4] [13 5] [13 6] [13 7] [13 8] [13 9]
+ [13 10] [13 11] [13 12]
+ [14 0] [14 1] [14 2] [14 3] [14 4] [14 5] [14 6] [14 7] [14 8]))))
+
+(defmacro deftest-both [txt & ises]
+ `(do
+ (deftest ~(symbol (str "For-" txt)) ~@ises)
+ (deftest ~(symbol (str "Doseq-" txt))
+ ~@(map (fn [[x-is [x-= [x-for binds body] value]]]
+ (when (and (= x-is 'is) (= x-= '=) (= x-for 'for))
+ `(is (= (let [acc# (atom [])]
+ (doseq ~binds (swap! acc# conj ~body))
+ @acc#)
+ ~value))))
+ ises))))
+
+(deftest-both When
+ (is (= (for [x (range 10) :when (odd? x)] x) '(1 3 5 7 9)))
+ (is (= (for [x (range 4) y (range 4) :when (odd? y)] [x y])
+ '([0 1] [0 3] [1 1] [1 3] [2 1] [2 3] [3 1] [3 3])))
+ (is (= (for [x (range 4) y (range 4) :when (odd? x)] [x y])
+ '([1 0] [1 1] [1 2] [1 3] [3 0] [3 1] [3 2] [3 3])))
+ (is (= (for [x (range 4) :when (odd? x) y (range 4)] [x y])
+ '([1 0] [1 1] [1 2] [1 3] [3 0] [3 1] [3 2] [3 3])))
+ (is (= (for [x (range 5) y (range 5) :when (< x y)] [x y])
+ '([0 1] [0 2] [0 3] [0 4] [1 2] [1 3] [1 4] [2 3] [2 4] [3 4]))))
+
+(defn only
+ "Returns a lazy seq of increasing ints starting at 0. Trying to get
+ the nth+1 value of the seq throws an exception. This is meant to
+ help detecting over-eagerness in lazy seq consumers."
+ [n]
+ (lazy-cat (range n)
+ (throw (Exception. "consumer went too far in lazy seq"))))
+
+(deftest-both While
+ (is (= (for [x (only 6) :while (< x 5)] x) '(0 1 2 3 4)))
+ (is (= (for [x (range 4) y (only 4) :while (< y 3)] [x y])
+ '([0 0] [0 1] [0 2] [1 0] [1 1] [1 2]
+ [2 0] [2 1] [2 2] [3 0] [3 1] [3 2])))
+ (is (= (for [x (range 4) y (range 4) :while (< x 3)] [x y])
+ '([0 0] [0 1] [0 2] [0 3] [1 0] [1 1] [1 2] [1 3]
+ [2 0] [2 1] [2 2] [2 3])))
+ (is (= (for [x (only 4) :while (< x 3) y (range 4)] [x y])
+ '([0 0] [0 1] [0 2] [0 3] [1 0] [1 1] [1 2] [1 3]
+ [2 0] [2 1] [2 2] [2 3])))
+ (is (= (for [x (range 4) y (range 4) :while (even? x)] [x y])
+ '([0 0] [0 1] [0 2] [0 3] [2 0] [2 1] [2 2] [2 3])))
+ (is (= (for [x (only 2) :while (even? x) y (range 4)] [x y])
+ '([0 0] [0 1] [0 2] [0 3])))
+ (is (= (for [x (range 4) y (only 4) :while (< y x)] [x y])
+ '([1 0] [2 0] [2 1] [3 0] [3 1] [3 2]))))
+
+(deftest-both While-and-When
+ (is (= (for [x (only 6) :while (< x 5) y (range 4) :when (odd? y)] [x y])
+ '([0 1] [0 3] [1 1] [1 3] [2 1] [2 3] [3 1] [3 3] [4 1] [4 3])))
+ (is (= (for [x (range 4) :when (odd? x) y (only 6) :while (< y 5)] [x y])
+ '([1 0] [1 1] [1 2] [1 3] [1 4] [3 0] [3 1] [3 2] [3 3] [3 4])))
+ (is (= (for [x (only 6) :while (< x 5) y (range 4) :when (odd? (+ x y))]
+ [x y])
+ '([0 1] [0 3] [1 0] [1 2] [2 1] [2 3] [3 0] [3 2] [4 1] [4 3])))
+ (is (= (for [x (range 4) :when (odd? x) y (only 2) :while (odd? (+ x y))]
+ [x y])
+ '([1 0] [3 0]))))
+
+(deftest-both While-and-When-Same-Binding
+ (is (= (for [x (only 6) :while (< x 5) :when (odd? x)] x) '(1 3)))
+ (is (= (for [x (only 6)
+ :while (< x 5) ; if :while is false, :when should not be evaled
+ :when (do (if (< x 5) (odd? x)))] x) '(1 3)))
+ (is (= (for [a (range -2 5)
+ :when (not= a 0) ; :when may guard :while
+ :while (> (Math/abs (/ 1.0 a)) 1/3)] a) '(-2 -1 1 2))))
+
+(deftest-both Nesting
+ (is (= (for [x '(a b) y (interpose x '(1 2)) z (list x y)] [x y z])
+ '([a 1 a] [a 1 1] [a a a] [a a a] [a 2 a] [a 2 2]
+ [b 1 b] [b 1 1] [b b b] [b b b] [b 2 b] [b 2 2])))
+ (is (= (for [x ['a nil] y [x 'b]] [x y])
+ '([a a] [a b] [nil nil] [nil b]))))
+
+(deftest-both Destructuring
+ (is (= (for [{:syms [a b c]} (map #(zipmap '(a b c) (range % 5)) (range 3))
+ x [a b c]]
+ (Integer. (str a b c x)))
+ '(120 121 122 1231 1232 1233 2342 2343 2344))))
+
+(deftest-both Let
+ (is (= (for [x (range 3) y (range 3) :let [z (+ x y)] :when (odd? z)] [x y z])
+ '([0 1 1] [1 0 1] [1 2 3] [2 1 3])))
+ (is (= (for [x (range 6) :let [y (rem x 2)] :when (even? y) z [8 9]] [x z])
+ '([0 8] [0 9] [2 8] [2 9] [4 8] [4 9]))))
diff --git a/test/clojure/test_clojure/java_interop.clj b/test/clojure/test_clojure/java_interop.clj
new file mode 100644
index 00000000..699ba361
--- /dev/null
+++ b/test/clojure/test_clojure/java_interop.clj
@@ -0,0 +1,407 @@
+; Copyright (c) Rich Hickey. 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.
+
+; Author: Frantisek Sodomka
+
+
+(ns clojure.test-clojure.java-interop
+ (:use clojure.test))
+
+; http://clojure.org/java_interop
+; http://clojure.org/compilation
+
+
+(deftest test-dot
+ ; (.instanceMember instance args*)
+ (are [x] (= x "FRED")
+ (.toUpperCase "fred")
+ (. "fred" toUpperCase)
+ (. "fred" (toUpperCase)) )
+
+ (are [x] (= x true)
+ (.startsWith "abcde" "ab")
+ (. "abcde" startsWith "ab")
+ (. "abcde" (startsWith "ab")) )
+
+ ; (.instanceMember Classname args*)
+ (are [x] (= x "java.lang.String")
+ (.getName String)
+ (. (identity String) getName)
+ (. (identity String) (getName)) )
+
+ ; (Classname/staticMethod args*)
+ (are [x] (= x 7)
+ (Math/abs -7)
+ (. Math abs -7)
+ (. Math (abs -7)) )
+
+ ; Classname/staticField
+ (are [x] (= x 2147483647)
+ Integer/MAX_VALUE
+ (. Integer MAX_VALUE) ))
+
+
+(deftest test-double-dot
+ (is (= (.. System (getProperties) (get "os.name"))
+ (. (. System (getProperties)) (get "os.name")))))
+
+
+(deftest test-doto
+ (let [m (doto (new java.util.HashMap)
+ (.put "a" 1)
+ (.put "b" 2))]
+ (are [x y] (= x y)
+ (class m) java.util.HashMap
+ m {"a" 1 "b" 2} )))
+
+
+(deftest test-new
+ ; Integer
+ (are [expr cls value] (and (= (class expr) cls)
+ (= expr value))
+ (new java.lang.Integer 42) java.lang.Integer 42
+ (java.lang.Integer. 123) java.lang.Integer 123 )
+
+ ; Date
+ (are [x] (= (class x) java.util.Date)
+ (new java.util.Date)
+ (java.util.Date.) ))
+
+
+(deftest test-instance?
+ ; evaluation
+ (are [x y] (= x y)
+ (instance? java.lang.Integer (+ 1 2)) true
+ (instance? java.lang.Long (+ 1 2)) false )
+
+ ; different types
+ (are [type literal] (instance? literal type)
+ 1 java.lang.Integer
+ 1.0 java.lang.Double
+ 1M java.math.BigDecimal
+ \a java.lang.Character
+ "a" java.lang.String )
+
+ ; it is an int, nothing else
+ (are [x y] (= (instance? x 42) y)
+ java.lang.Integer true
+ java.lang.Long false
+ java.lang.Character false
+ java.lang.String false ))
+
+
+; set!
+
+; memfn
+
+
+(deftest test-bean
+ (let [b (bean java.awt.Color/black)]
+ (are [x y] (= x y)
+ (map? b) true
+
+ (:red b) 0
+ (:green b) 0
+ (:blue b) 0
+ (:RGB b) -16777216
+
+ (:alpha b) 255
+ (:transparency b) 1
+
+ (:class b) java.awt.Color )))
+
+
+; proxy, proxy-super
+
+
+(deftest test-bases
+ (are [x y] (= x y)
+ (bases java.lang.Math)
+ (list java.lang.Object)
+ (bases java.lang.Integer)
+ (list java.lang.Number java.lang.Comparable) ))
+
+(deftest test-supers
+ (are [x y] (= x y)
+ (supers java.lang.Math)
+ #{java.lang.Object}
+ (supers java.lang.Integer)
+ #{java.lang.Number java.lang.Object
+ java.lang.Comparable java.io.Serializable} ))
+
+
+; Arrays: [alength] aget aset [make-array to-array into-array to-array-2d aclone]
+; [float-array, int-array, etc]
+; amap, areduce
+
+(defmacro deftest-type-array [type-array type]
+ `(deftest ~(symbol (str "test-" type-array))
+ ; correct type
+ (is (= (class (first (~type-array [1 2]))) (class (~type 1))))
+
+ ; given size (and empty)
+ (are [x] (and (= (alength (~type-array x)) x)
+ (= (vec (~type-array x)) (repeat x 0)))
+ 0 1 5 )
+
+ ; copy of a sequence
+ (are [x] (and (= (alength (~type-array x)) (count x))
+ (= (vec (~type-array x)) x))
+;; [] ;; ERROR
+ [1]
+ [1 -2 3 0 5] )
+
+ ; given size and init-value
+ (are [x] (and (= (alength (~type-array x 42)) x)
+ (= (vec (~type-array x 42)) (repeat x 42)))
+ 0 1 5 )
+
+ ; given size and init-seq
+ (are [x y z] (and (= (alength (~type-array x y)) x)
+ (= (vec (~type-array x y)) z))
+ 0 [] []
+ 0 [1] []
+ 0 [1 2 3] []
+ 1 [] [0]
+ 1 [1] [1]
+ 1 [1 2 3] [1]
+ 5 [] [0 0 0 0 0]
+ 5 [1] [1 0 0 0 0]
+ 5 [1 2 3] [1 2 3 0 0]
+ 5 [1 2 3 4 5] [1 2 3 4 5]
+ 5 [1 2 3 4 5 6 7] [1 2 3 4 5] )))
+
+(deftest-type-array int-array int)
+(deftest-type-array long-array long)
+(deftest-type-array float-array float)
+(deftest-type-array double-array double)
+
+; separate test for exceptions (doesn't work with above macro...)
+(deftest test-type-array-exceptions
+ (are [x] (thrown? NegativeArraySizeException x)
+ (int-array -1)
+ (long-array -1)
+ (float-array -1)
+ (double-array -1) ))
+
+
+(deftest test-make-array
+ ; negative size
+ (is (thrown? NegativeArraySizeException (make-array Integer -1)))
+
+ ; one-dimensional
+ (are [x] (= (alength (make-array Integer x)) x)
+ 0 1 5 )
+
+ (let [a (make-array Integer 5)]
+ (aset a 3 42)
+ (are [x y] (= x y)
+ (aget a 3) 42
+ (class (aget a 3)) Integer ))
+
+ ; multi-dimensional
+ (let [a (make-array Integer 3 2 4)]
+ (aset a 0 1 2 987)
+ (are [x y] (= x y)
+ (alength a) 3
+ (alength (first a)) 2
+ (alength (first (first a))) 4
+
+ (aget a 0 1 2) 987
+ (class (aget a 0 1 2)) Integer )))
+
+
+(deftest test-to-array
+ (let [v [1 "abc" :kw \c []]
+ a (to-array v)]
+ (are [x y] (= x y)
+ ; length
+ (alength a) (count v)
+
+ ; content
+ (vec a) v
+ (class (aget a 0)) (class (nth v 0))
+ (class (aget a 1)) (class (nth v 1))
+ (class (aget a 2)) (class (nth v 2))
+ (class (aget a 3)) (class (nth v 3))
+ (class (aget a 4)) (class (nth v 4)) ))
+
+ ; different kinds of collections
+ (are [x] (and (= (alength (to-array x)) (count x))
+ (= (vec (to-array x)) (vec x)))
+ ()
+ '(1 2)
+ []
+ [1 2]
+ (sorted-set)
+ (sorted-set 1 2)
+
+ (int-array 0)
+ (int-array [1 2 3])
+
+ (to-array [])
+ (to-array [1 2 3]) ))
+
+
+(deftest test-into-array
+ ; compatible types only
+ (is (thrown? IllegalArgumentException (into-array [1 "abc" :kw])))
+ (is (thrown? IllegalArgumentException (into-array [1.2 4])))
+ (is (thrown? IllegalArgumentException (into-array [(byte 2) (short 3)])))
+
+ ; simple case
+ (let [v [1 2 3 4 5]
+ a (into-array v)]
+ (are [x y] (= x y)
+ (alength a) (count v)
+ (vec a) v
+ (class (first a)) (class (first v)) ))
+
+ ; given type
+ (let [a (into-array Integer/TYPE [(byte 2) (short 3) (int 4)])]
+ (are [x] (= x Integer)
+ (class (aget a 0))
+ (class (aget a 1))
+ (class (aget a 2)) ))
+
+ ; different kinds of collections
+ (are [x] (and (= (alength (into-array x)) (count x))
+ (= (vec (into-array x)) (vec x))
+ (= (alength (into-array Integer/TYPE x)) (count x))
+ (= (vec (into-array Integer/TYPE x)) (vec x)))
+ ()
+ '(1 2)
+ []
+ [1 2]
+ (sorted-set)
+ (sorted-set 1 2)
+
+ (int-array 0)
+ (int-array [1 2 3])
+
+ (to-array [])
+ (to-array [1 2 3]) ))
+
+
+(deftest test-to-array-2d
+ ; needs to be a collection of collection(s)
+ (is (thrown? Exception (to-array-2d [1 2 3])))
+
+ ; ragged array
+ (let [v [[1] [2 3] [4 5 6]]
+ a (to-array-2d v)]
+ (are [x y] (= x y)
+ (alength a) (count v)
+ (alength (aget a 0)) (count (nth v 0))
+ (alength (aget a 1)) (count (nth v 1))
+ (alength (aget a 2)) (count (nth v 2))
+
+ (vec (aget a 0)) (nth v 0)
+ (vec (aget a 1)) (nth v 1)
+ (vec (aget a 2)) (nth v 2) ))
+
+ ; empty array
+ (let [a (to-array-2d [])]
+ (are [x y] (= x y)
+ (alength a) 0
+ (vec a) [] )))
+
+
+(deftest test-alength
+ (are [x] (= (alength x) 0)
+ (int-array 0)
+ (long-array 0)
+ (float-array 0)
+ (double-array 0)
+ (make-array Integer/TYPE 0)
+ (to-array [])
+ (into-array [])
+ (to-array-2d []) )
+
+ (are [x] (= (alength x) 1)
+ (int-array 1)
+ (long-array 1)
+ (float-array 1)
+ (double-array 1)
+ (make-array Integer/TYPE 1)
+ (to-array [1])
+ (into-array [1])
+ (to-array-2d [[1]]) )
+
+ (are [x] (= (alength x) 3)
+ (int-array 3)
+ (long-array 3)
+ (float-array 3)
+ (double-array 3)
+ (make-array Integer/TYPE 3)
+ (to-array [1 "a" :k])
+ (into-array [1 2 3])
+ (to-array-2d [[1] [2 3] [4 5 6]]) ))
+
+
+(deftest test-aclone
+ ; clone all arrays except 2D
+ (are [x] (and (= (alength (aclone x)) (alength x))
+ (= (vec (aclone x)) (vec x)))
+ (int-array 0)
+ (long-array 0)
+ (float-array 0)
+ (double-array 0)
+ (make-array Integer/TYPE 0)
+ (to-array [])
+ (into-array [])
+
+ (int-array [1 2 3])
+ (long-array [1 2 3])
+ (float-array [1 2 3])
+ (double-array [1 2 3])
+ (make-array Integer/TYPE 3)
+ (to-array [1 "a" :k])
+ (into-array [1 2 3]) )
+
+ ; clone 2D
+ (are [x] (and (= (alength (aclone x)) (alength x))
+ (= (map alength (aclone x)) (map alength x))
+ (= (map vec (aclone x)) (map vec x)))
+ (to-array-2d [])
+ (to-array-2d [[1] [2 3] [4 5 6]]) ))
+
+
+; Type Hints, *warn-on-reflection*
+; #^ints, #^floats, #^longs, #^doubles
+
+; Coercions: [int, long, float, double, char, boolean, short, byte]
+; num
+; ints/longs/floats/doubles
+
+(deftest test-boolean
+ (are [x y] (and (instance? java.lang.Boolean (boolean x))
+ (= (boolean x) y))
+ nil false
+ false false
+ true true
+
+ 0 true
+ 1 true
+ () true
+ [1] true
+
+ "" true
+ \space true
+ :kw true ))
+
+
+(deftest test-char
+ ; int -> char
+ (is (instance? java.lang.Character (char 65)))
+
+ ; char -> char
+ (is (instance? java.lang.Character (char \a)))
+ (is (= (char \a) \a)))
+
+;; Note: More coercions in numbers.clj
diff --git a/test/clojure/test_clojure/logic.clj b/test/clojure/test_clojure/logic.clj
new file mode 100644
index 00000000..b097468e
--- /dev/null
+++ b/test/clojure/test_clojure/logic.clj
@@ -0,0 +1,205 @@
+; Copyright (c) Rich Hickey. 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.
+
+; Author: Frantisek Sodomka
+
+;;
+;; Created 1/29/2009
+
+(ns clojure.test-clojure.logic
+ (:use clojure.test
+ [clojure.test-clojure.test-utils :only (exception)]))
+
+
+;; *** Tests ***
+
+(deftest test-if
+ ; true/false/nil
+ (are [x y] (= x y)
+ (if true :t) :t
+ (if true :t :f) :t
+ (if true :t (exception)) :t
+
+ (if false :t) nil
+ (if false :t :f) :f
+ (if false (exception) :f) :f
+
+ (if nil :t) nil
+ (if nil :t :f) :f
+ (if nil (exception) :f) :f )
+
+ ; zero/empty is true
+ (are [x] (= (if x :t :f) :t)
+ (byte 0)
+ (short 0)
+ (int 0)
+ (long 0)
+ (bigint 0)
+ (float 0)
+ (double 0)
+ (bigdec 0)
+
+ 0/2
+ ""
+ #""
+ (symbol "")
+
+ ()
+ []
+ {}
+ #{}
+ (into-array []) )
+
+ ; anything except nil/false is true
+ (are [x] (= (if x :t :f) :t)
+ (byte 2)
+ (short 2)
+ (int 2)
+ (long 2)
+ (bigint 2)
+ (float 2)
+ (double 2)
+ (bigdec 2)
+
+ 2/3
+ \a
+ "abc"
+ #"a*b"
+ 'abc
+ :kw
+
+ '(1 2)
+ [1 2]
+ {:a 1 :b 2}
+ #{1 2}
+ (into-array [1 2])
+
+ (new java.util.Date) ))
+
+
+(deftest test-nil-punning
+ (are [x y] (= (if x :no :yes) y)
+ (first []) :yes
+ (next [1]) :yes
+ (rest [1]) :no
+
+ (butlast [1]) :yes
+
+ (seq nil) :yes
+ (seq []) :yes
+
+ (sequence nil) :no
+ (sequence []) :no
+
+ (lazy-seq nil) :no
+ (lazy-seq []) :no
+
+ (filter #(> % 10) [1 2 3]) :no
+ (map identity []) :no
+ (apply concat []) :no
+
+ (concat) :no
+ (concat []) :no
+
+ (reverse nil) :no
+ (reverse []) :no
+
+ (sort nil) :no
+ (sort []) :no ))
+
+
+(deftest test-and
+ (are [x y] (= x y)
+ (and) true
+ (and true) true
+ (and nil) nil
+ (and false) false
+
+ (and true nil) nil
+ (and true false) false
+
+ (and 1 true :kw 'abc "abc") "abc"
+
+ (and 1 true :kw nil 'abc "abc") nil
+ (and 1 true :kw nil (exception) 'abc "abc") nil
+
+ (and 1 true :kw 'abc "abc" false) false
+ (and 1 true :kw 'abc "abc" false (exception)) false ))
+
+
+(deftest test-or
+ (are [x y] (= x y)
+ (or) nil
+ (or true) true
+ (or nil) nil
+ (or false) false
+
+ (or nil false true) true
+ (or nil false 1 2) 1
+ (or nil false "abc" :kw) "abc"
+
+ (or false nil) nil
+ (or nil false) false
+ (or nil nil nil false) false
+
+ (or nil true false) true
+ (or nil true (exception) false) true
+ (or nil false "abc" (exception)) "abc" ))
+
+
+(deftest test-not
+ (is (thrown? IllegalArgumentException (not)))
+ (are [x] (= (not x) true)
+ nil
+ false )
+ (are [x] (= (not x) false)
+ true
+
+ ; numbers
+ 0
+ 0.0
+ 42
+ 1.2
+ 0/2
+ 2/3
+
+ ; characters
+ \space
+ \tab
+ \a
+
+ ; strings
+ ""
+ "abc"
+
+ ; regexes
+ #""
+ #"a*b"
+
+ ; symbols
+ (symbol "")
+ 'abc
+
+ ; keywords
+ :kw
+
+ ; collections/arrays
+ ()
+ '(1 2)
+ []
+ [1 2]
+ {}
+ {:a 1 :b 2}
+ #{}
+ #{1 2}
+ (into-array [])
+ (into-array [1 2])
+
+ ; Java objects
+ (new java.util.Date) ))
+
diff --git a/test/clojure/test_clojure/macros.clj b/test/clojure/test_clojure/macros.clj
new file mode 100644
index 00000000..711130ef
--- /dev/null
+++ b/test/clojure/test_clojure/macros.clj
@@ -0,0 +1,18 @@
+; Copyright (c) Rich Hickey. 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.
+
+; Author: Frantisek Sodomka
+
+(ns clojure.test-clojure.macros
+ (:use clojure.test))
+
+; http://clojure.org/macros
+
+; ->
+; defmacro definline macroexpand-1 macroexpand
+
diff --git a/test/clojure/test_clojure/metadata.clj b/test/clojure/test_clojure/metadata.clj
new file mode 100644
index 00000000..3130b489
--- /dev/null
+++ b/test/clojure/test_clojure/metadata.clj
@@ -0,0 +1,19 @@
+; Copyright (c) Rich Hickey. 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.
+
+; Author: Frantisek Sodomka
+
+(ns clojure.test-clojure.metadata
+ (:use clojure.test))
+
+
+; http://clojure.org/metadata
+
+; meta
+; with-meta
+
diff --git a/test/clojure/test_clojure/multimethods.clj b/test/clojure/test_clojure/multimethods.clj
new file mode 100644
index 00000000..8c27034a
--- /dev/null
+++ b/test/clojure/test_clojure/multimethods.clj
@@ -0,0 +1,27 @@
+; Copyright (c) Rich Hickey. 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.
+
+; Author: Frantisek Sodomka
+
+(ns clojure.test-clojure.multimethods
+ (:use clojure.test))
+
+; http://clojure.org/multimethods
+
+; defmulti
+; defmethod
+; remove-method
+; prefer-method
+; methods
+; prefers
+
+; derive, [underive]
+; isa?
+; parents, ancestors, descendants
+; make-hierarchy
+
diff --git a/test/clojure/test_clojure/ns_libs.clj b/test/clojure/test_clojure/ns_libs.clj
new file mode 100644
index 00000000..a9a2145c
--- /dev/null
+++ b/test/clojure/test_clojure/ns_libs.clj
@@ -0,0 +1,28 @@
+; Copyright (c) Rich Hickey. 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.
+
+; Author: Frantisek Sodomka
+
+(ns clojure.test-clojure.ns-libs
+ (:use clojure.test))
+
+; http://clojure.org/namespaces
+
+; in-ns ns create-ns
+; alias import intern refer
+; all-ns find-ns
+; ns-name ns-aliases ns-imports ns-interns ns-map ns-publics ns-refers
+; resolve ns-resolve namespace
+; ns-unalias ns-unmap remove-ns
+
+
+; http://clojure.org/libs
+
+; require use
+; loaded-libs
+
diff --git a/test/clojure/test_clojure/numbers.clj b/test/clojure/test_clojure/numbers.clj
new file mode 100644
index 00000000..9f3cfdb2
--- /dev/null
+++ b/test/clojure/test_clojure/numbers.clj
@@ -0,0 +1,391 @@
+; Copyright (c) Rich Hickey. 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.
+
+; Author: Stephen C. Gilardi
+;; scgilardi (gmail)
+;; Created 30 October 2008
+;;
+
+(ns clojure.test-clojure.numbers
+ (:use clojure.test))
+
+
+; TODO:
+; ==
+; and more...
+
+
+;; *** Types ***
+
+(deftest Coerced-Byte
+ (let [v (byte 3)]
+ (are [x]
+ (instance? Byte v)
+ (number? v)
+ (integer? v)
+ (rational? v))))
+
+(deftest Coerced-Short
+ (let [v (short 3)]
+ (are [x]
+ (instance? Short v)
+ (number? v)
+ (integer? v)
+ (rational? v))))
+
+(deftest Coerced-Integer
+ (let [v (int 3)]
+ (are [x]
+ (instance? Integer v)
+ (number? v)
+ (integer? v)
+ (rational? v))))
+
+(deftest Coerced-Long
+ (let [v (long 3)]
+ (are [x]
+ (instance? Long v)
+ (number? v)
+ (integer? v)
+ (rational? v))))
+
+(deftest Coerced-BigInteger
+ (let [v (bigint 3)]
+ (are [x]
+ (instance? BigInteger v)
+ (number? v)
+ (integer? v)
+ (rational? v))))
+
+(deftest Coerced-Float
+ (let [v (float 3)]
+ (are [x]
+ (instance? Float v)
+ (number? v)
+ (float? v))))
+
+(deftest Coerced-Double
+ (let [v (double 3)]
+ (are [x]
+ (instance? Double v)
+ (number? v)
+ (float? v))))
+
+(deftest Coerced-BigDecimal
+ (let [v (bigdec 3)]
+ (are [x]
+ (instance? BigDecimal v)
+ (number? v)
+ (decimal? v)
+ (not (float? v)))))
+
+
+;; *** Functions ***
+
+(defonce DELTA 1e-12)
+
+(deftest test-add
+ (are [x y] (= x y)
+ (+) 0
+ (+ 1) 1
+ (+ 1 2) 3
+ (+ 1 2 3) 6
+
+ (+ -1) -1
+ (+ -1 -2) -3
+ (+ -1 +2 -3) -2
+
+ (+ 1 -1) 0
+ (+ -1 1) 0
+
+ (+ 2/3) 2/3
+ (+ 2/3 1) 5/3
+ (+ 2/3 1/3) 1 )
+
+ (are [x y] (< (- x y) DELTA)
+ (+ 1.2) 1.2
+ (+ 1.1 2.4) 3.5
+ (+ 1.1 2.2 3.3) 6.6 )
+
+ (is (> (+ Integer/MAX_VALUE 10) Integer/MAX_VALUE)) ; no overflow
+ (is (thrown? ClassCastException (+ "ab" "cd"))) ) ; no string concatenation
+
+
+(deftest test-subtract
+ (is (thrown? IllegalArgumentException (-)))
+ (are [x y] (= x y)
+ (- 1) -1
+ (- 1 2) -1
+ (- 1 2 3) -4
+
+ (- -2) 2
+ (- 1 -2) 3
+ (- 1 -2 -3) 6
+
+ (- 1 1) 0
+ (- -1 -1) 0
+
+ (- 2/3) -2/3
+ (- 2/3 1) -1/3
+ (- 2/3 1/3) 1/3 )
+
+ (are [x y] (< (- x y) DELTA)
+ (- 1.2) -1.2
+ (- 2.2 1.1) 1.1
+ (- 6.6 2.2 1.1) 3.3 )
+
+ (is (< (- Integer/MIN_VALUE 10) Integer/MIN_VALUE)) ) ; no underflow
+
+
+(deftest test-multiply
+ (are [x y] (= x y)
+ (*) 1
+ (* 2) 2
+ (* 2 3) 6
+ (* 2 3 4) 24
+
+ (* -2) -2
+ (* 2 -3) -6
+ (* 2 -3 -1) 6
+
+ (* 1/2) 1/2
+ (* 1/2 1/3) 1/6
+ (* 1/2 1/3 -1/4) -1/24 )
+
+ (are [x y] (< (- x y) DELTA)
+ (* 1.2) 1.2
+ (* 2.0 1.2) 2.4
+ (* 3.5 2.0 1.2) 8.4 )
+
+ (is (> (* 3 (int (/ Integer/MAX_VALUE 2.0))) Integer/MAX_VALUE)) ) ; no overflow
+
+
+(deftest test-divide
+ (are [x y] (= x y)
+ (/ 1) 1
+ (/ 2) 1/2
+ (/ 3 2) 3/2
+ (/ 4 2) 2
+ (/ 24 3 2) 4
+ (/ 24 3 2 -1) -4
+
+ (/ -1) -1
+ (/ -2) -1/2
+ (/ -3 -2) 3/2
+ (/ -4 -2) 2
+ (/ -4 2) -2 )
+
+ (are [x y] (< (- x y) DELTA)
+ (/ 4.5 3) 1.5
+ (/ 4.5 3.0 3.0) 0.5 )
+
+ (is (thrown? ArithmeticException (/ 0)))
+ (is (thrown? ArithmeticException (/ 2 0)))
+ (is (thrown? IllegalArgumentException (/))) )
+
+
+;; mod
+;; http://en.wikipedia.org/wiki/Modulo_operation
+;; http://mathforum.org/library/drmath/view/52343.html
+;;
+;; is mod correct?
+;; http://groups.google.com/group/clojure/browse_frm/thread/2a0ee4d248f3d131#
+;;
+;; Issue 23: mod (modulo) operator
+;; http://code.google.com/p/clojure/issues/detail?id=23
+
+(deftest test-mod
+ ; wrong number of args
+ (is (thrown? IllegalArgumentException (mod)))
+ (is (thrown? IllegalArgumentException (mod 1)))
+ (is (thrown? IllegalArgumentException (mod 3 2 1)))
+
+ ; divide by zero
+ (is (thrown? ArithmeticException (mod 9 0)))
+ (is (thrown? ArithmeticException (mod 0 0)))
+
+ (are [x y] (= x y)
+ (mod 4 2) 0
+ (mod 3 2) 1
+ (mod 6 4) 2
+ (mod 0 5) 0
+
+ (mod 2 1/2) 0
+ (mod 2/3 1/2) 1/6
+ (mod 1 2/3) 1/3
+
+ (mod 4.0 2.0) 0.0
+ (mod 4.5 2.0) 0.5
+
+ ; |num| > |div|, num != k * div
+ (mod 42 5) 2 ; (42 / 5) * 5 + (42 mod 5) = 8 * 5 + 2 = 42
+ (mod 42 -5) -3 ; (42 / -5) * (-5) + (42 mod -5) = -9 * (-5) + (-3) = 42
+ (mod -42 5) 3 ; (-42 / 5) * 5 + (-42 mod 5) = -9 * 5 + 3 = -42
+ (mod -42 -5) -2 ; (-42 / -5) * (-5) + (-42 mod -5) = 8 * (-5) + (-2) = -42
+
+ ; |num| > |div|, num = k * div
+ (mod 9 3) 0 ; (9 / 3) * 3 + (9 mod 3) = 3 * 3 + 0 = 9
+ (mod 9 -3) 0
+ (mod -9 3) 0
+ (mod -9 -3) 0
+
+ ; |num| < |div|
+ (mod 2 5) 2 ; (2 / 5) * 5 + (2 mod 5) = 0 * 5 + 2 = 2
+ (mod 2 -5) -3 ; (2 / -5) * (-5) + (2 mod -5) = (-1) * (-5) + (-3) = 2
+ (mod -2 5) 3 ; (-2 / 5) * 5 + (-2 mod 5) = (-1) * 5 + 3 = -2
+ (mod -2 -5) -2 ; (-2 / -5) * (-5) + (-2 mod -5) = 0 * (-5) + (-2) = -2
+
+ ; num = 0, div != 0
+ (mod 0 3) 0 ; (0 / 3) * 3 + (0 mod 3) = 0 * 3 + 0 = 0
+ (mod 0 -3) 0
+ )
+)
+
+;; rem & quot
+;; http://en.wikipedia.org/wiki/Remainder
+
+(deftest test-rem
+ ; wrong number of args
+ (is (thrown? IllegalArgumentException (rem)))
+ (is (thrown? IllegalArgumentException (rem 1)))
+ (is (thrown? IllegalArgumentException (rem 3 2 1)))
+
+ ; divide by zero
+ (is (thrown? ArithmeticException (rem 9 0)))
+ (is (thrown? ArithmeticException (rem 0 0)))
+
+ (are [x y] (= x y)
+ (rem 4 2) 0
+ (rem 3 2) 1
+ (rem 6 4) 2
+ (rem 0 5) 0
+
+ (rem 2 1/2) 0
+ (rem 2/3 1/2) 1/6
+ (rem 1 2/3) 1/3
+
+ (rem 4.0 2.0) 0.0
+ (rem 4.5 2.0) 0.5
+
+ ; |num| > |div|, num != k * div
+ (rem 42 5) 2 ; (8 * 5) + 2 == 42
+ (rem 42 -5) 2 ; (-8 * -5) + 2 == 42
+ (rem -42 5) -2 ; (-8 * 5) + -2 == -42
+ (rem -42 -5) -2 ; (8 * -5) + -2 == -42
+
+ ; |num| > |div|, num = k * div
+ (rem 9 3) 0
+ (rem 9 -3) 0
+ (rem -9 3) 0
+ (rem -9 -3) 0
+
+ ; |num| < |div|
+ (rem 2 5) 2
+ (rem 2 -5) 2
+ (rem -2 5) -2
+ (rem -2 -5) -2
+
+ ; num = 0, div != 0
+ (rem 0 3) 0
+ (rem 0 -3) 0
+ )
+)
+
+(deftest test-quot
+ ; wrong number of args
+ (is (thrown? IllegalArgumentException (quot)))
+ (is (thrown? IllegalArgumentException (quot 1)))
+ (is (thrown? IllegalArgumentException (quot 3 2 1)))
+
+ ; divide by zero
+ (is (thrown? ArithmeticException (quot 9 0)))
+ (is (thrown? ArithmeticException (quot 0 0)))
+
+ (are [x y] (= x y)
+ (quot 4 2) 2
+ (quot 3 2) 1
+ (quot 6 4) 1
+ (quot 0 5) 0
+
+ (quot 2 1/2) 4
+ (quot 2/3 1/2) 1
+ (quot 1 2/3) 1
+
+ (quot 4.0 2.0) 2.0
+ (quot 4.5 2.0) 2.0
+
+ ; |num| > |div|, num != k * div
+ (quot 42 5) 8 ; (8 * 5) + 2 == 42
+ (quot 42 -5) -8 ; (-8 * -5) + 2 == 42
+ (quot -42 5) -8 ; (-8 * 5) + -2 == -42
+ (quot -42 -5) 8 ; (8 * -5) + -2 == -42
+
+ ; |num| > |div|, num = k * div
+ (quot 9 3) 3
+ (quot 9 -3) -3
+ (quot -9 3) -3
+ (quot -9 -3) 3
+
+ ; |num| < |div|
+ (quot 2 5) 0
+ (quot 2 -5) 0
+ (quot -2 5) 0
+ (quot -2 -5) 0
+
+ ; num = 0, div != 0
+ (quot 0 3) 0
+ (quot 0 -3) 0
+ )
+)
+
+
+;; *** Predicates ***
+
+;; pos? zero? neg?
+
+(deftest test-pos?-zero?-neg?
+ (let [nums [[(byte 2) (byte 0) (byte -2)]
+ [(short 3) (short 0) (short -3)]
+ [(int 4) (int 0) (int -4)]
+ [(long 5) (long 0) (long -5)]
+ [(bigint 6) (bigint 0) (bigint -6)]
+ [(float 7) (float 0) (float -7)]
+ [(double 8) (double 0) (double -8)]
+ [(bigdec 9) (bigdec 0) (bigdec -9)]
+ [2/3 0 -2/3]]
+ pred-result [[pos? [true false false]]
+ [zero? [false true false]]
+ [neg? [false false true]]] ]
+ (doseq [pr pred-result]
+ (doseq [n nums]
+ (is (= (map (first pr) n) (second pr))
+ (pr-str (first pr) n))))))
+
+
+;; even? odd?
+
+(deftest test-even?
+ (are [x]
+ (even? -4)
+ (not (even? -3))
+ (even? 0)
+ (not (even? 5))
+ (even? 8))
+ (is (thrown? ArithmeticException (even? 1/2)))
+ (is (thrown? ArithmeticException (even? (double 10)))))
+
+(deftest test-odd?
+ (are [x]
+ (not (odd? -4))
+ (odd? -3)
+ (not (odd? 0))
+ (odd? 5)
+ (not (odd? 8)))
+ (is (thrown? ArithmeticException (odd? 1/2)))
+ (is (thrown? ArithmeticException (odd? (double 10)))))
+
diff --git a/test/clojure/test_clojure/other_functions.clj b/test/clojure/test_clojure/other_functions.clj
new file mode 100644
index 00000000..43214921
--- /dev/null
+++ b/test/clojure/test_clojure/other_functions.clj
@@ -0,0 +1,60 @@
+; Copyright (c) Rich Hickey. 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.
+
+; Author: Frantisek Sodomka
+
+
+(ns clojure.test-clojure.other-functions
+ (:use clojure.test))
+
+; http://clojure.org/other_functions
+
+; [= not= (tests in data_structures.clj and elsewhere)]
+
+
+(deftest test-identity
+ ; exactly 1 argument needed
+ (is (thrown? IllegalArgumentException (identity)))
+ (is (thrown? IllegalArgumentException (identity 1 2)))
+
+ (are [x] (= (identity 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} )
+
+ ; evaluation
+ (are [x y] (= (identity x) y)
+ (+ 1 2) 3
+ (> 5 0) true ))
+
+
+; time assert comment doc
+
+; partial
+; comp
+; complement
+; constantly
+
+; Printing
+; pr prn print println newline
+; pr-str prn-str print-str println-str [with-out-str (vars.clj)]
+
+; Regex Support
+; re-matcher re-find re-matches re-groups re-seq
+
diff --git a/test/clojure/test_clojure/parallel.clj b/test/clojure/test_clojure/parallel.clj
new file mode 100644
index 00000000..fb98d605
--- /dev/null
+++ b/test/clojure/test_clojure/parallel.clj
@@ -0,0 +1,29 @@
+; Copyright (c) Rich Hickey. 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.
+
+; Author: Frantisek Sodomka
+
+
+(ns clojure.test-clojure.parallel
+ (:use clojure.test))
+
+;; !! Tests for the parallel library will be in a separate file clojure_parallel.clj !!
+
+; future-call
+; future
+; pmap
+; pcalls
+; pvalues
+
+
+;; pmap
+;;
+(deftest pmap-does-its-thing
+ ;; regression fixed in r1218; was OutOfMemoryError
+ (is (= '(1) (pmap inc [0]))))
+
diff --git a/test/clojure/test_clojure/predicates.clj b/test/clojure/test_clojure/predicates.clj
new file mode 100644
index 00000000..8e68c757
--- /dev/null
+++ b/test/clojure/test_clojure/predicates.clj
@@ -0,0 +1,142 @@
+; Copyright (c) Rich Hickey. 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.
+
+; Author: Frantisek Sodomka
+
+;;
+;; Created 1/28/2009
+
+(ns clojure.test-clojure.predicates
+ (:use clojure.test))
+
+
+;; *** Type predicates ***
+
+(def myvar 42)
+
+(def sample-data {
+ :nil nil
+
+ :bool-true true
+ :bool-false false
+
+ :byte (byte 7)
+ :short (short 7)
+ :int (int 7)
+ :long (long 7)
+ :bigint (bigint 7)
+ :float (float 7)
+ :double (double 7)
+ :bigdec (bigdec 7)
+
+ :ratio 2/3
+
+ :character \a
+ :symbol 'abc
+ :keyword :kw
+
+ :empty-string ""
+ :empty-regex #""
+ :empty-list ()
+ :empty-lazy-seq (lazy-seq nil)
+ :empty-vector []
+ :empty-map {}
+ :empty-set #{}
+ :empty-array (into-array [])
+
+ :string "abc"
+ :regex #"a*b"
+ :list '(1 2 3)
+ :lazy-seq (lazy-seq [1 2 3])
+ :vector [1 2 3]
+ :map {:a 1 :b 2 :c 3}
+ :set #{1 2 3}
+ :array (into-array [1 2 3])
+
+ :fn (fn [x] (* 2 x))
+
+ :class java.util.Date
+ :object (new java.util.Date)
+
+ :var (var myvar)
+ :delay (delay (+ 1 2))
+})
+
+
+(def type-preds {
+ nil? [:nil]
+
+ true? [:bool-true]
+ false? [:bool-false]
+ ; boolean?
+
+ integer? [:byte :short :int :long :bigint]
+ float? [:float :double]
+ decimal? [:bigdec]
+ ratio? [:ratio]
+ rational? [:byte :short :int :long :bigint :ratio :bigdec]
+ number? [:byte :short :int :long :bigint :ratio :bigdec :float :double]
+
+ ; character?
+ symbol? [:symbol]
+ keyword? [:keyword]
+
+ string? [:empty-string :string]
+ ; regex?
+
+ list? [:empty-list :list]
+ vector? [:empty-vector :vector]
+ map? [:empty-map :map]
+ set? [:empty-set :set]
+
+ coll? [:empty-list :list
+ :empty-lazy-seq :lazy-seq
+ :empty-vector :vector
+ :empty-map :map
+ :empty-set :set]
+
+ seq? [:empty-list :list
+ :empty-lazy-seq :lazy-seq]
+ ; array?
+
+ fn? [:fn]
+ ifn? [:fn
+ :empty-vector :vector :empty-map :map :empty-set :set
+ :keyword :symbol :var]
+
+ class? [:class]
+ var? [:var]
+ delay? [:delay]
+})
+
+
+;; Test all type predicates against all data types
+;;
+(defn- get-fn-name [f]
+ (str
+ (apply str (nthnext (first (.split (str f) "_"))
+ (count "clojure.core$")))
+ "?"))
+
+(deftest test-type-preds
+ (doseq [tp type-preds]
+ (doseq [dt sample-data]
+ (if (some #(= % (first dt)) (second tp))
+ (is ((first tp) (second dt))
+ (pr-str (list (get-fn-name (first tp)) (second dt))))
+ (is (not ((first tp) (second dt)))
+ (pr-str (list 'not (list (get-fn-name (first tp)) (second dt)))))))))
+
+
+;; Additional tests:
+;; http://groups.google.com/group/clojure/browse_thread/thread/537761a06edb4b06/bfd4f0705b746a38
+;;
+(deftest test-string?-more
+ (are (not (string? _))
+ (new java.lang.StringBuilder "abc")
+ (new java.lang.StringBuffer "xyz")))
diff --git a/test/clojure/test_clojure/printer.clj b/test/clojure/test_clojure/printer.clj
new file mode 100644
index 00000000..ecee4b6e
--- /dev/null
+++ b/test/clojure/test_clojure/printer.clj
@@ -0,0 +1,83 @@
+; Copyright (c) Rich Hickey. 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.
+
+; Author: Stephen C. Gilardi
+
+;; clojure.test-clojure.printer
+;;
+;; scgilardi (gmail)
+;; Created 29 October 2008
+
+(ns clojure.test-clojure.printer
+ (:use clojure.test))
+
+(deftest print-length-empty-seq
+ (let [coll () val "()"]
+ (is (= val (binding [*print-length* 0] (print-str coll))))
+ (is (= val (binding [*print-length* 1] (print-str coll))))))
+
+(deftest print-length-seq
+ (let [coll (range 5)
+ length-val '((0 "(...)")
+ (1 "(0 ...)")
+ (2 "(0 1 ...)")
+ (3 "(0 1 2 ...)")
+ (4 "(0 1 2 3 ...)")
+ (5 "(0 1 2 3 4)"))]
+ (doseq [[length val] length-val]
+ (binding [*print-length* length]
+ (is (= val (print-str coll)))))))
+
+(deftest print-length-empty-vec
+ (let [coll [] val "[]"]
+ (is (= val (binding [*print-length* 0] (print-str coll))))
+ (is (= val (binding [*print-length* 1] (print-str coll))))))
+
+(deftest print-length-vec
+ (let [coll [0 1 2 3 4]
+ length-val '((0 "[...]")
+ (1 "[0 ...]")
+ (2 "[0 1 ...]")
+ (3 "[0 1 2 ...]")
+ (4 "[0 1 2 3 ...]")
+ (5 "[0 1 2 3 4]"))]
+ (doseq [[length val] length-val]
+ (binding [*print-length* length]
+ (is (= val (print-str coll)))))))
+
+(deftest print-level-seq
+ (let [coll '(0 (1 (2 (3 (4)))))
+ level-val '((0 "#")
+ (1 "(0 #)")
+ (2 "(0 (1 #))")
+ (3 "(0 (1 (2 #)))")
+ (4 "(0 (1 (2 (3 #))))")
+ (5 "(0 (1 (2 (3 (4)))))"))]
+ (doseq [[level val] level-val]
+ (binding [*print-level* level]
+ (is (= val (print-str coll)))))))
+
+(deftest print-level-length-coll
+ (let [coll '(if (member x y) (+ (first x) 3) (foo (a b c d "Baz")))
+ level-length-val
+ '((0 1 "#")
+ (1 1 "(if ...)")
+ (1 2 "(if # ...)")
+ (1 3 "(if # # ...)")
+ (1 4 "(if # # #)")
+ (2 1 "(if ...)")
+ (2 2 "(if (member x ...) ...)")
+ (2 3 "(if (member x y) (+ # 3) ...)")
+ (3 2 "(if (member x ...) ...)")
+ (3 3 "(if (member x y) (+ (first x) 3) ...)")
+ (3 4 "(if (member x y) (+ (first x) 3) (foo (a b c d ...)))")
+ (3 5 "(if (member x y) (+ (first x) 3) (foo (a b c d Baz)))"))]
+ (doseq [[level length val] level-length-val]
+ (binding [*print-level* level
+ *print-length* length]
+ (is (= val (print-str coll)))))))
diff --git a/test/clojure/test_clojure/reader.clj b/test/clojure/test_clojure/reader.clj
new file mode 100644
index 00000000..b04543a9
--- /dev/null
+++ b/test/clojure/test_clojure/reader.clj
@@ -0,0 +1,299 @@
+; Copyright (c) Rich Hickey. 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.
+
+; Author: Stephen C. Gilardi
+
+;;
+;; Tests for the Clojure functions documented at the URL:
+;;
+;; http://clojure.org/Reader
+;;
+;; scgilardi (gmail)
+;; Created 22 October 2008
+
+(ns clojure.test-clojure.reader
+ (:use clojure.test))
+
+;; Symbols
+
+(deftest Symbols
+ (is (= 'abc (symbol "abc")))
+ (is (= '*+!-_? (symbol "*+!-_?")))
+ (is (= 'abc:def:ghi (symbol "abc:def:ghi")))
+ (is (= 'abc/def (symbol "abc" "def")))
+ (is (= 'abc.def/ghi (symbol "abc.def" "ghi")))
+ (is (= 'abc/def.ghi (symbol "abc" "def.ghi")))
+ (is (= 'abc:def/ghi:jkl.mno (symbol "abc:def" "ghi:jkl.mno")))
+ (is (instance? clojure.lang.Symbol 'alphabet))
+ )
+
+;; Literals
+
+(deftest Literals
+ ; 'nil 'false 'true are reserved by Clojure and are not symbols
+ (is (= 'nil nil))
+ (is (= 'false false))
+ (is (= 'true true)) )
+
+;; Strings
+
+(deftest Strings
+ (is (= "abcde" (str \a \b \c \d \e)))
+ (is (= "abc
+ def" (str \a \b \c \newline \space \space \d \e \f)))
+ )
+
+;; Numbers
+
+(deftest Numbers
+
+ ; Read Integer
+ (is (instance? Integer 2147483647))
+ (is (instance? Integer +1))
+ (is (instance? Integer 1))
+ (is (instance? Integer +0))
+ (is (instance? Integer 0))
+ (is (instance? Integer -0))
+ (is (instance? Integer -1))
+ (is (instance? Integer -2147483648))
+
+ ; Read Long
+ (is (instance? Long 2147483648))
+ (is (instance? Long -2147483649))
+ (is (instance? Long 9223372036854775807))
+ (is (instance? Long -9223372036854775808))
+
+ ;; Numeric constants of different types don't wash out. Regression fixed in
+ ;; r1157. Previously the compiler saw 0 and 0.0 as the same constant and
+ ;; caused the sequence to be built of Doubles.
+ (let [x 0.0]
+ (let [sequence (loop [i 0 l '()]
+ (if (< i 5)
+ (recur (inc i) (conj l i))
+ l))]
+ (is (= [4 3 2 1 0] sequence))
+ (is (every? #(instance? Integer %)
+ sequence))))
+
+ ; Read BigInteger
+ (is (instance? BigInteger 9223372036854775808))
+ (is (instance? BigInteger -9223372036854775809))
+ (is (instance? BigInteger 10000000000000000000000000000000000000000000000000))
+ (is (instance? BigInteger -10000000000000000000000000000000000000000000000000))
+
+ ; Read Double
+ (is (instance? Double +1.0e+1))
+ (is (instance? Double +1.e+1))
+ (is (instance? Double +1e+1))
+
+ (is (instance? Double +1.0e1))
+ (is (instance? Double +1.e1))
+ (is (instance? Double +1e1))
+
+ (is (instance? Double +1.0e-1))
+ (is (instance? Double +1.e-1))
+ (is (instance? Double +1e-1))
+
+ (is (instance? Double 1.0e+1))
+ (is (instance? Double 1.e+1))
+ (is (instance? Double 1e+1))
+
+ (is (instance? Double 1.0e1))
+ (is (instance? Double 1.e1))
+ (is (instance? Double 1e1))
+
+ (is (instance? Double 1.0e-1))
+ (is (instance? Double 1.e-1))
+ (is (instance? Double 1e-1))
+
+ (is (instance? Double -1.0e+1))
+ (is (instance? Double -1.e+1))
+ (is (instance? Double -1e+1))
+
+ (is (instance? Double -1.0e1))
+ (is (instance? Double -1.e1))
+ (is (instance? Double -1e1))
+
+ (is (instance? Double -1.0e-1))
+ (is (instance? Double -1.e-1))
+ (is (instance? Double -1e-1))
+
+ (is (instance? Double +1.0))
+ (is (instance? Double +1.))
+
+ (is (instance? Double 1.0))
+ (is (instance? Double 1.))
+
+ (is (instance? Double +0.0))
+ (is (instance? Double +0.))
+
+ (is (instance? Double 0.0))
+ (is (instance? Double 0.))
+
+ (is (instance? Double -0.0))
+ (is (instance? Double -0.))
+
+ (is (instance? Double -1.0))
+ (is (instance? Double -1.))
+
+ ; Read BigDecimal
+ (is (instance? BigDecimal 9223372036854775808M))
+ (is (instance? BigDecimal -9223372036854775809M))
+ (is (instance? BigDecimal 2147483647M))
+ (is (instance? BigDecimal +1M))
+ (is (instance? BigDecimal 1M))
+ (is (instance? BigDecimal +0M))
+ (is (instance? BigDecimal 0M))
+ (is (instance? BigDecimal -0M))
+ (is (instance? BigDecimal -1M))
+ (is (instance? BigDecimal -2147483648M))
+
+ (is (instance? BigDecimal +1.0e+1M))
+ (is (instance? BigDecimal +1.e+1M))
+ (is (instance? BigDecimal +1e+1M))
+
+ (is (instance? BigDecimal +1.0e1M))
+ (is (instance? BigDecimal +1.e1M))
+ (is (instance? BigDecimal +1e1M))
+
+ (is (instance? BigDecimal +1.0e-1M))
+ (is (instance? BigDecimal +1.e-1M))
+ (is (instance? BigDecimal +1e-1M))
+
+ (is (instance? BigDecimal 1.0e+1M))
+ (is (instance? BigDecimal 1.e+1M))
+ (is (instance? BigDecimal 1e+1M))
+
+ (is (instance? BigDecimal 1.0e1M))
+ (is (instance? BigDecimal 1.e1M))
+ (is (instance? BigDecimal 1e1M))
+
+ (is (instance? BigDecimal 1.0e-1M))
+ (is (instance? BigDecimal 1.e-1M))
+ (is (instance? BigDecimal 1e-1M))
+
+ (is (instance? BigDecimal -1.0e+1M))
+ (is (instance? BigDecimal -1.e+1M))
+ (is (instance? BigDecimal -1e+1M))
+
+ (is (instance? BigDecimal -1.0e1M))
+ (is (instance? BigDecimal -1.e1M))
+ (is (instance? BigDecimal -1e1M))
+
+ (is (instance? BigDecimal -1.0e-1M))
+ (is (instance? BigDecimal -1.e-1M))
+ (is (instance? BigDecimal -1e-1M))
+
+ (is (instance? BigDecimal +1.0M))
+ (is (instance? BigDecimal +1.M))
+
+ (is (instance? BigDecimal 1.0M))
+ (is (instance? BigDecimal 1.M))
+
+ (is (instance? BigDecimal +0.0M))
+ (is (instance? BigDecimal +0.M))
+
+ (is (instance? BigDecimal 0.0M))
+ (is (instance? BigDecimal 0.M))
+
+ (is (instance? BigDecimal -0.0M))
+ (is (instance? BigDecimal -0.M))
+
+ (is (instance? BigDecimal -1.0M))
+ (is (instance? BigDecimal -1.M))
+)
+
+;; Characters
+
+(deftest t-Characters)
+
+;; nil
+
+(deftest t-nil)
+
+;; Booleans
+
+(deftest t-Booleans)
+
+;; Keywords
+
+(deftest t-Keywords)
+
+;; Lists
+
+(deftest t-Lists)
+
+;; Vectors
+
+(deftest t-Vectors)
+
+;; Maps
+
+(deftest t-Maps)
+
+;; Sets
+
+(deftest t-Sets)
+
+;; Macro characters
+
+;; Quote (')
+
+(deftest t-Quote)
+
+;; Character (\)
+
+(deftest t-Character)
+
+;; Comment (;)
+
+(deftest t-Comment)
+
+;; Meta (^)
+
+(deftest t-Meta)
+
+;; Deref (@)
+
+(deftest t-Deref)
+
+;; Dispatch (#)
+
+;; #{} - see Sets above
+
+;; Regex patterns (#"pattern")
+
+(deftest t-Regex)
+
+;; Metadata (#^)
+
+(deftest t-Metadata)
+
+;; Var-quote (#')
+
+(deftest t-Var-quote)
+
+;; Anonymous function literal (#())
+
+(deftest t-Anonymouns-function-literal)
+
+;; Syntax-quote (`, note, the "backquote" character), Unquote (~) and
+;; Unquote-splicing (~@)
+
+(deftest t-Syntax-quote
+ (are (= _1 _2)
+ `() () ; was NPE before SVN r1337
+ ))
+
+;; (read)
+;; (read stream)
+;; (read stream eof-is-error)
+;; (read stream eof-is-error eof-value)
+;; (read stream eof-is-error eof-value is-recursive)
+
+(deftest t-read)
diff --git a/test/clojure/test_clojure/refs.clj b/test/clojure/test_clojure/refs.clj
new file mode 100644
index 00000000..767a34dd
--- /dev/null
+++ b/test/clojure/test_clojure/refs.clj
@@ -0,0 +1,22 @@
+; Copyright (c) Rich Hickey. 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.
+
+; Author: Frantisek Sodomka
+
+
+(ns clojure.test-clojure.refs
+ (:use clojure.test))
+
+; http://clojure.org/refs
+
+; ref
+; deref, @-reader-macro
+; dosync io!
+; ensure ref-set alter commute
+; set-validator get-validator
+
diff --git a/test/clojure/test_clojure/sequences.clj b/test/clojure/test_clojure/sequences.clj
new file mode 100644
index 00000000..4f813cc6
--- /dev/null
+++ b/test/clojure/test_clojure/sequences.clj
@@ -0,0 +1,984 @@
+; Copyright (c) Rich Hickey. 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.
+
+; Author: Frantisek Sodomka
+
+
+(ns clojure.test-clojure.sequences
+ (:use clojure.test))
+
+
+;; *** Tests ***
+
+; TODO:
+; apply, map, reduce, filter, remove
+; and more...
+
+
+(deftest test-equality
+ ; lazy sequences
+ (are [x y] (= x y)
+ ; fixed SVN 1288 - LazySeq and EmptyList equals/equiv
+ ; http://groups.google.com/group/clojure/browse_frm/thread/286d807be9cae2a5#
+ (map inc nil) ()
+ (map inc ()) ()
+ (map inc []) ()
+ (map inc #{}) ()
+ (map inc {}) () ))
+
+
+(deftest test-lazy-seq
+ (are [x] (seq? x)
+ (lazy-seq nil)
+ (lazy-seq [])
+ (lazy-seq [1 2]))
+
+ (are [x y] (= x y)
+ (lazy-seq nil) ()
+ (lazy-seq [nil]) '(nil)
+
+ (lazy-seq ()) ()
+ (lazy-seq []) ()
+ (lazy-seq #{}) ()
+ (lazy-seq {}) ()
+ (lazy-seq "") ()
+ (lazy-seq (into-array [])) ()
+
+ (lazy-seq (list 1 2)) '(1 2)
+ (lazy-seq [1 2]) '(1 2)
+ (lazy-seq (sorted-set 1 2)) '(1 2)
+ (lazy-seq (sorted-map :a 1 :b 2)) '([:a 1] [:b 2])
+ (lazy-seq "abc") '(\a \b \c)
+ (lazy-seq (into-array [1 2])) '(1 2) ))
+
+
+(deftest test-seq
+ (is (not (seq? (seq []))))
+ (is (seq? (seq [1 2])))
+
+ (are [x y] (= x y)
+ (seq nil) nil
+ (seq [nil]) '(nil)
+
+ (seq ()) nil
+ (seq []) nil
+ (seq #{}) nil
+ (seq {}) nil
+ (seq "") nil
+ (seq (into-array [])) nil
+
+ (seq (list 1 2)) '(1 2)
+ (seq [1 2]) '(1 2)
+ (seq (sorted-set 1 2)) '(1 2)
+ (seq (sorted-map :a 1 :b 2)) '([:a 1] [:b 2])
+ (seq "abc") '(\a \b \c)
+ (seq (into-array [1 2])) '(1 2) ))
+
+
+(deftest test-cons
+ (is (thrown? IllegalArgumentException (cons 1 2)))
+ (are [x y] (= x y)
+ (cons 1 nil) '(1)
+ (cons nil nil) '(nil)
+
+ (cons \a nil) '(\a)
+ (cons \a "") '(\a)
+ (cons \a "bc") '(\a \b \c)
+
+ (cons 1 ()) '(1)
+ (cons 1 '(2 3)) '(1 2 3)
+
+ (cons 1 []) [1]
+ (cons 1 [2 3]) [1 2 3]
+
+ (cons 1 #{}) '(1)
+ (cons 1 (sorted-set 2 3)) '(1 2 3)
+
+ (cons 1 (into-array [])) '(1)
+ (cons 1 (into-array [2 3])) '(1 2 3) ))
+
+
+(deftest test-empty
+ (are [x y] (and (= (empty x) y)
+ (= (class (empty x)) (class y)))
+ nil nil
+
+ () ()
+ '(1 2) ()
+
+ [] []
+ [1 2] []
+
+ {} {}
+ {:a 1 :b 2} {}
+
+ #{} #{}
+ #{1 2} #{}
+
+ (seq ()) nil ; (seq ()) => nil
+ (seq '(1 2)) ()
+
+ (seq []) nil ; (seq []) => nil
+ (seq [1 2]) ()
+
+ (seq "") nil ; (seq "") => nil
+ (seq "ab") ()
+
+ (lazy-seq ()) ()
+ (lazy-seq '(1 2)) ()
+
+ (lazy-seq []) ()
+ (lazy-seq [1 2]) ()
+
+ ; non-coll, non-seq => nil
+ 42 nil
+ 1.2 nil
+ "abc" nil ))
+
+
+(deftest test-not-empty
+ ; empty coll/seq => nil
+ (are [x] (= (not-empty x) nil)
+ ()
+ []
+ {}
+ #{}
+ (seq ())
+ (seq [])
+ (lazy-seq ())
+ (lazy-seq []) )
+
+ ; non-empty coll/seq => identity
+ (are [x] (and (= (not-empty x) x)
+ (= (class (not-empty x)) (class x)))
+ '(1 2)
+ [1 2]
+ {:a 1}
+ #{1 2}
+ (seq '(1 2))
+ (seq [1 2])
+ (lazy-seq '(1 2))
+ (lazy-seq [1 2]) ))
+
+
+(deftest test-first
+ (is (thrown? IllegalArgumentException (first)))
+ (is (thrown? IllegalArgumentException (first true)))
+ (is (thrown? IllegalArgumentException (first false)))
+ (is (thrown? IllegalArgumentException (first 1)))
+ (is (thrown? IllegalArgumentException (first 1 2)))
+ (is (thrown? IllegalArgumentException (first \a)))
+ (is (thrown? IllegalArgumentException (first 's)))
+ (is (thrown? IllegalArgumentException (first :k)))
+ (are [x y] (= x y)
+ (first nil) nil
+
+ ; string
+ (first "") nil
+ (first "a") \a
+ (first "abc") \a
+
+ ; list
+ (first ()) nil
+ (first '(1)) 1
+ (first '(1 2 3)) 1
+
+ (first '(nil)) nil
+ (first '(1 nil)) 1
+ (first '(nil 2)) nil
+ (first '(())) ()
+ (first '(() nil)) ()
+ (first '(() 2 nil)) ()
+
+ ; vector
+ (first []) nil
+ (first [1]) 1
+ (first [1 2 3]) 1
+
+ (first [nil]) nil
+ (first [1 nil]) 1
+ (first [nil 2]) nil
+ (first [[]]) []
+ (first [[] nil]) []
+ (first [[] 2 nil]) []
+
+ ; set
+ (first #{}) nil
+ (first #{1}) 1
+ (first (sorted-set 1 2 3)) 1
+
+ (first #{nil}) nil
+ (first (sorted-set 1 nil)) nil
+ (first (sorted-set nil 2)) nil
+ (first #{#{}}) #{}
+ (first (sorted-set #{} nil)) nil
+ ;(first (sorted-set #{} 2 nil)) nil
+
+ ; map
+ (first {}) nil
+ (first (sorted-map :a 1)) '(:a 1)
+ (first (sorted-map :a 1 :b 2 :c 3)) '(:a 1)
+
+ ; array
+ (first (into-array [])) nil
+ (first (into-array [1])) 1
+ (first (into-array [1 2 3])) 1
+ (first (to-array [nil])) nil
+ (first (to-array [1 nil])) 1
+ (first (to-array [nil 2])) nil ))
+
+
+(deftest test-next
+ (is (thrown? IllegalArgumentException (next)))
+ (is (thrown? IllegalArgumentException (next true)))
+ (is (thrown? IllegalArgumentException (next false)))
+ (is (thrown? IllegalArgumentException (next 1)))
+ (is (thrown? IllegalArgumentException (next 1 2)))
+ (is (thrown? IllegalArgumentException (next \a)))
+ (is (thrown? IllegalArgumentException (next 's)))
+ (is (thrown? IllegalArgumentException (next :k)))
+ (are [x y] (= x y)
+ (next nil) nil
+
+ ; string
+ (next "") nil
+ (next "a") nil
+ (next "abc") '(\b \c)
+
+ ; list
+ (next ()) nil
+ (next '(1)) nil
+ (next '(1 2 3)) '(2 3)
+
+ (next '(nil)) nil
+ (next '(1 nil)) '(nil)
+ (next '(1 ())) '(())
+ (next '(nil 2)) '(2)
+ (next '(())) nil
+ (next '(() nil)) '(nil)
+ (next '(() 2 nil)) '(2 nil)
+
+ ; vector
+ (next []) nil
+ (next [1]) nil
+ (next [1 2 3]) [2 3]
+
+ (next [nil]) nil
+ (next [1 nil]) [nil]
+ (next [1 []]) [[]]
+ (next [nil 2]) [2]
+ (next [[]]) nil
+ (next [[] nil]) [nil]
+ (next [[] 2 nil]) [2 nil]
+
+ ; set
+ (next #{}) nil
+ (next #{1}) nil
+ (next (sorted-set 1 2 3)) '(2 3)
+
+ (next #{nil}) nil
+ (next (sorted-set 1 nil)) '(1)
+ (next (sorted-set nil 2)) '(2)
+ (next #{#{}}) nil
+ (next (sorted-set #{} nil)) '(#{})
+ ;(next (sorted-set #{} 2 nil)) #{}
+
+ ; map
+ (next {}) nil
+ (next (sorted-map :a 1)) nil
+ (next (sorted-map :a 1 :b 2 :c 3)) '((:b 2) (:c 3))
+
+ ; array
+ (next (into-array [])) nil
+ (next (into-array [1])) nil
+ (next (into-array [1 2 3])) '(2 3)
+
+ (next (to-array [nil])) nil
+ (next (to-array [1 nil])) '(nil)
+ ;(next (to-array [1 (into-array [])])) (list (into-array []))
+ (next (to-array [nil 2])) '(2)
+ (next (to-array [(into-array [])])) nil
+ (next (to-array [(into-array []) nil])) '(nil)
+ (next (to-array [(into-array []) 2 nil])) '(2 nil) ))
+
+
+(deftest test-last
+ (are [x y] (= x y)
+ (last nil) nil
+
+ ; list
+ (last ()) nil
+ (last '(1)) 1
+ (last '(1 2 3)) 3
+
+ (last '(nil)) nil
+ (last '(1 nil)) nil
+ (last '(nil 2)) 2
+ (last '(())) ()
+ (last '(() nil)) nil
+ (last '(() 2 nil)) nil
+
+ ; vector
+ (last []) nil
+ (last [1]) 1
+ (last [1 2 3]) 3
+
+ (last [nil]) nil
+ (last [1 nil]) nil
+ (last [nil 2]) 2
+ (last [[]]) []
+ (last [[] nil]) nil
+ (last [[] 2 nil]) nil
+
+ ; set
+ (last #{}) nil
+ (last #{1}) 1
+ (last (sorted-set 1 2 3)) 3
+
+ (last #{nil}) nil
+ (last (sorted-set 1 nil)) 1
+ (last (sorted-set nil 2)) 2
+ (last #{#{}}) #{}
+ (last (sorted-set #{} nil)) #{}
+ ;(last (sorted-set #{} 2 nil)) nil
+
+ ; map
+ (last {}) nil
+ (last (sorted-map :a 1)) [:a 1]
+ (last (sorted-map :a 1 :b 2 :c 3)) [:c 3]
+
+ ; string
+ (last "") nil
+ (last "a") \a
+ (last "abc") \c
+
+ ; array
+ (last (into-array [])) nil
+ (last (into-array [1])) 1
+ (last (into-array [1 2 3])) 3
+ (last (to-array [nil])) nil
+ (last (to-array [1 nil])) nil
+ (last (to-array [nil 2])) 2 ))
+
+
+;; (ffirst coll) = (first (first coll))
+;;
+(deftest test-ffirst
+ (is (thrown? IllegalArgumentException (ffirst)))
+ (are [x y] (= x y)
+ (ffirst nil) nil
+
+ (ffirst ()) nil
+ (ffirst '((1 2) (3 4))) 1
+
+ (ffirst []) nil
+ (ffirst [[1 2] [3 4]]) 1
+
+ (ffirst {}) nil
+ (ffirst {:a 1}) :a
+
+ (ffirst #{}) nil
+ (ffirst #{[1 2]}) 1 ))
+
+
+;; (fnext coll) = (first (next coll)) = (second coll)
+;;
+(deftest test-fnext
+ (is (thrown? IllegalArgumentException (fnext)))
+ (are [x y] (= x y)
+ (fnext nil) nil
+
+ (fnext ()) nil
+ (fnext '(1)) nil
+ (fnext '(1 2 3 4)) 2
+
+ (fnext []) nil
+ (fnext [1]) nil
+ (fnext [1 2 3 4]) 2
+
+ (fnext {}) nil
+ (fnext (sorted-map :a 1)) nil
+ (fnext (sorted-map :a 1 :b 2)) [:b 2]
+
+ (fnext #{}) nil
+ (fnext #{1}) nil
+ (fnext (sorted-set 1 2 3 4)) 2 ))
+
+
+;; (nfirst coll) = (next (first coll))
+;;
+(deftest test-nfirst
+ (is (thrown? IllegalArgumentException (nfirst)))
+ (are [x y] (= x y)
+ (nfirst nil) nil
+
+ (nfirst ()) nil
+ (nfirst '((1 2 3) (4 5 6))) '(2 3)
+
+ (nfirst []) nil
+ (nfirst [[1 2 3] [4 5 6]]) '(2 3)
+
+ (nfirst {}) nil
+ (nfirst {:a 1}) '(1)
+
+ (nfirst #{}) nil
+ (nfirst #{[1 2]}) '(2) ))
+
+
+;; (nnext coll) = (next (next coll))
+;;
+(deftest test-nnext
+ (is (thrown? IllegalArgumentException (nnext)))
+ (are [x y] (= x y)
+ (nnext nil) nil
+
+ (nnext ()) nil
+ (nnext '(1)) nil
+ (nnext '(1 2)) nil
+ (nnext '(1 2 3 4)) '(3 4)
+
+ (nnext []) nil
+ (nnext [1]) nil
+ (nnext [1 2]) nil
+ (nnext [1 2 3 4]) '(3 4)
+
+ (nnext {}) nil
+ (nnext (sorted-map :a 1)) nil
+ (nnext (sorted-map :a 1 :b 2)) nil
+ (nnext (sorted-map :a 1 :b 2 :c 3 :d 4)) '([:c 3] [:d 4])
+
+ (nnext #{}) nil
+ (nnext #{1}) nil
+ (nnext (sorted-set 1 2)) nil
+ (nnext (sorted-set 1 2 3 4)) '(3 4) ))
+
+
+(deftest test-nth
+ ; maps, sets are not supported
+ (is (thrown? UnsupportedOperationException (nth {} 0)))
+ (is (thrown? UnsupportedOperationException (nth {:a 1 :b 2} 0)))
+ (is (thrown? UnsupportedOperationException (nth #{} 0)))
+ (is (thrown? UnsupportedOperationException (nth #{1 2 3} 0)))
+
+ ; out of bounds
+ (is (thrown? IndexOutOfBoundsException (nth '() 0)))
+ (is (thrown? IndexOutOfBoundsException (nth '(1 2 3) 5)))
+ (is (thrown? IndexOutOfBoundsException (nth '() -1)))
+ (is (thrown? IndexOutOfBoundsException (nth '(1 2 3) -1)))
+
+ (is (thrown? IndexOutOfBoundsException (nth [] 0)))
+ (is (thrown? IndexOutOfBoundsException (nth [1 2 3] 5)))
+ (is (thrown? IndexOutOfBoundsException (nth [] -1)))
+ (is (thrown? ArrayIndexOutOfBoundsException (nth [1 2 3] -1))) ; ???
+
+ (is (thrown? ArrayIndexOutOfBoundsException (nth (into-array []) 0)))
+ (is (thrown? ArrayIndexOutOfBoundsException (nth (into-array [1 2 3]) 5)))
+ (is (thrown? ArrayIndexOutOfBoundsException (nth (into-array []) -1)))
+ (is (thrown? ArrayIndexOutOfBoundsException (nth (into-array [1 2 3]) -1)))
+
+ (is (thrown? StringIndexOutOfBoundsException (nth "" 0)))
+ (is (thrown? StringIndexOutOfBoundsException (nth "abc" 5)))
+ (is (thrown? StringIndexOutOfBoundsException (nth "" -1)))
+ (is (thrown? StringIndexOutOfBoundsException (nth "abc" -1)))
+
+ (is (thrown? IndexOutOfBoundsException (nth (java.util.ArrayList. []) 0)))
+ (is (thrown? IndexOutOfBoundsException (nth (java.util.ArrayList. [1 2 3]) 5)))
+ (is (thrown? ArrayIndexOutOfBoundsException (nth (java.util.ArrayList. []) -1))) ; ???
+ (is (thrown? ArrayIndexOutOfBoundsException (nth (java.util.ArrayList. [1 2 3]) -1))) ; ???
+
+ (are [x y] (= x y)
+ (nth '(1) 0) 1
+ (nth '(1 2 3) 0) 1
+ (nth '(1 2 3 4 5) 1) 2
+ (nth '(1 2 3 4 5) 4) 5
+ (nth '(1 2 3) 5 :not-found) :not-found
+
+ (nth [1] 0) 1
+ (nth [1 2 3] 0) 1
+ (nth [1 2 3 4 5] 1) 2
+ (nth [1 2 3 4 5] 4) 5
+ (nth [1 2 3] 5 :not-found) :not-found
+
+ (nth (into-array [1]) 0) 1
+ (nth (into-array [1 2 3]) 0) 1
+ (nth (into-array [1 2 3 4 5]) 1) 2
+ (nth (into-array [1 2 3 4 5]) 4) 5
+ (nth (into-array [1 2 3]) 5 :not-found) :not-found
+
+ (nth "a" 0) \a
+ (nth "abc" 0) \a
+ (nth "abcde" 1) \b
+ (nth "abcde" 4) \e
+ (nth "abc" 5 :not-found) :not-found
+
+ (nth (java.util.ArrayList. [1]) 0) 1
+ (nth (java.util.ArrayList. [1 2 3]) 0) 1
+ (nth (java.util.ArrayList. [1 2 3 4 5]) 1) 2
+ (nth (java.util.ArrayList. [1 2 3 4 5]) 4) 5
+ (nth (java.util.ArrayList. [1 2 3]) 5 :not-found) :not-found )
+
+ ; regex Matchers
+ (let [m (re-matcher #"(a)(b)" "ababaa")]
+ (re-find m) ; => ["ab" "a" "b"]
+ (are [x y] (= x y)
+ (nth m 0) "ab"
+ (nth m 1) "a"
+ (nth m 2) "b"
+ (nth m 3 :not-found) :not-found
+ (nth m -1 :not-found) :not-found )
+ (is (thrown? IndexOutOfBoundsException (nth m 3)))
+ (is (thrown? IndexOutOfBoundsException (nth m -1))))
+
+ (let [m (re-matcher #"c" "ababaa")]
+ (re-find m) ; => nil
+ (are [x y] (= x y)
+ (nth m 0 :not-found) :not-found
+ (nth m 2 :not-found) :not-found
+ (nth m -1 :not-found) :not-found )
+ (is (thrown? IllegalStateException (nth m 0)))
+ (is (thrown? IllegalStateException (nth m 2)))
+ (is (thrown? IllegalStateException (nth m -1)))))
+
+
+; distinct was broken for nil & false:
+; fixed in rev 1278:
+; http://code.google.com/p/clojure/source/detail?r=1278
+;
+(deftest test-distinct
+ (are [x y] (= x y)
+ (distinct ()) ()
+ (distinct '(1)) '(1)
+ (distinct '(1 2 3)) '(1 2 3)
+ (distinct '(1 2 3 1 1 1)) '(1 2 3)
+ (distinct '(1 1 1 2)) '(1 2)
+ (distinct '(1 2 1 2)) '(1 2)
+
+ (distinct []) ()
+ (distinct [1]) '(1)
+ (distinct [1 2 3]) '(1 2 3)
+ (distinct [1 2 3 1 2 2 1 1]) '(1 2 3)
+ (distinct [1 1 1 2]) '(1 2)
+ (distinct [1 2 1 2]) '(1 2)
+
+ (distinct "") ()
+ (distinct "a") '(\a)
+ (distinct "abc") '(\a \b \c)
+ (distinct "abcabab") '(\a \b \c)
+ (distinct "aaab") '(\a \b)
+ (distinct "abab") '(\a \b) )
+
+ (are [x] (= (distinct [x 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} ))
+
+
+(deftest test-interpose
+ (are [x y] (= x y)
+ (interpose 0 []) ()
+ (interpose 0 [1]) '(1)
+ (interpose 0 [1 2]) '(1 0 2)
+ (interpose 0 [1 2 3]) '(1 0 2 0 3) ))
+
+
+(deftest test-interleave
+ (are [x y] (= x y)
+ (interleave [1 2] [3 4]) '(1 3 2 4)
+
+ (interleave [1] [3 4]) '(1 3)
+ (interleave [1 2] [3]) '(1 3)
+
+ (interleave [] [3 4]) ()
+ (interleave [1 2] []) ()
+ (interleave [] []) () ))
+
+
+(deftest test-zipmap
+ (are [x y] (= x y)
+ (zipmap [:a :b] [1 2]) {:a 1 :b 2}
+
+ (zipmap [:a] [1 2]) {:a 1}
+ (zipmap [:a :b] [1]) {:a 1}
+
+ (zipmap [] [1 2]) {}
+ (zipmap [:a :b] []) {}
+ (zipmap [] []) {} ))
+
+
+(deftest test-concat
+ (are [x y] (= x y)
+ (concat) ()
+
+ (concat []) ()
+ (concat [1 2]) '(1 2)
+
+ (concat [1 2] [3 4]) '(1 2 3 4)
+ (concat [] [3 4]) '(3 4)
+ (concat [1 2] []) '(1 2)
+ (concat [] []) ()
+
+ (concat [1 2] [3 4] [5 6]) '(1 2 3 4 5 6) ))
+
+
+(deftest test-cycle
+ (are [x y] (= x y)
+ (cycle []) ()
+
+ (take 3 (cycle [1])) '(1 1 1)
+ (take 5 (cycle [1 2 3])) '(1 2 3 1 2)
+
+ (take 3 (cycle [nil])) '(nil nil nil) ))
+
+
+(deftest test-partition
+ (are [x y] (= x y)
+ (partition 2 [1 2 3]) '((1 2))
+ (partition 2 [1 2 3 4]) '((1 2) (3 4))
+ (partition 2 []) ()
+
+ (partition 2 3 [1 2 3 4 5 6 7]) '((1 2) (4 5))
+ (partition 2 3 [1 2 3 4 5 6 7 8]) '((1 2) (4 5) (7 8))
+ (partition 2 3 []) ()
+
+ (partition 1 []) ()
+ (partition 1 [1 2 3]) '((1) (2) (3))
+
+ (partition 5 [1 2 3]) ()
+
+; (partition 0 [1 2 3]) (repeat nil) ; infinite sequence of nil
+ (partition -1 [1 2 3]) ()
+ (partition -2 [1 2 3]) () ))
+
+
+(deftest test-reverse
+ (are [x y] (= x y)
+ (reverse nil) () ; since SVN 1294
+ (reverse []) ()
+ (reverse [1]) '(1)
+ (reverse [1 2 3]) '(3 2 1) ))
+
+
+(deftest test-take
+ (are [x y] (= x y)
+ (take 1 [1 2 3 4 5]) '(1)
+ (take 3 [1 2 3 4 5]) '(1 2 3)
+ (take 5 [1 2 3 4 5]) '(1 2 3 4 5)
+ (take 9 [1 2 3 4 5]) '(1 2 3 4 5)
+
+ (take 0 [1 2 3 4 5]) ()
+ (take -1 [1 2 3 4 5]) ()
+ (take -2 [1 2 3 4 5]) () ))
+
+
+(deftest test-drop
+ (are [x y] (= x y)
+ (drop 1 [1 2 3 4 5]) '(2 3 4 5)
+ (drop 3 [1 2 3 4 5]) '(4 5)
+ (drop 5 [1 2 3 4 5]) ()
+ (drop 9 [1 2 3 4 5]) ()
+
+ (drop 0 [1 2 3 4 5]) '(1 2 3 4 5)
+ (drop -1 [1 2 3 4 5]) '(1 2 3 4 5)
+ (drop -2 [1 2 3 4 5]) '(1 2 3 4 5) ))
+
+
+(deftest test-take-nth
+ (are [x y] (= x y)
+ (take-nth 1 [1 2 3 4 5]) '(1 2 3 4 5)
+ (take-nth 2 [1 2 3 4 5]) '(1 3 5)
+ (take-nth 3 [1 2 3 4 5]) '(1 4)
+ (take-nth 4 [1 2 3 4 5]) '(1 5)
+ (take-nth 5 [1 2 3 4 5]) '(1)
+ (take-nth 9 [1 2 3 4 5]) '(1)
+
+ ; infinite seq of 1s = (repeat 1)
+ ;(take-nth 0 [1 2 3 4 5])
+ ;(take-nth -1 [1 2 3 4 5])
+ ;(take-nth -2 [1 2 3 4 5])
+ ))
+
+
+(deftest test-take-while
+ (are [x y] (= x y)
+ (take-while pos? []) ()
+ (take-while pos? [1 2 3 4]) '(1 2 3 4)
+ (take-while pos? [1 2 3 -1]) '(1 2 3)
+ (take-while pos? [1 -1 2 3]) '(1)
+ (take-while pos? [-1 1 2 3]) ()
+ (take-while pos? [-1 -2 -3]) () ))
+
+
+(deftest test-drop-while
+ (are [x y] (= x y)
+ (drop-while pos? []) ()
+ (drop-while pos? [1 2 3 4]) ()
+ (drop-while pos? [1 2 3 -1]) '(-1)
+ (drop-while pos? [1 -1 2 3]) '(-1 2 3)
+ (drop-while pos? [-1 1 2 3]) '(-1 1 2 3)
+ (drop-while pos? [-1 -2 -3]) '(-1 -2 -3) ))
+
+
+(deftest test-butlast
+ (are [x y] (= x y)
+ (butlast []) nil
+ (butlast [1]) nil
+ (butlast [1 2 3]) '(1 2) ))
+
+
+(deftest test-drop-last
+ (are [x y] (= x y)
+ ; as butlast
+ (drop-last []) ()
+ (drop-last [1]) ()
+ (drop-last [1 2 3]) '(1 2)
+
+ ; as butlast, but lazy
+ (drop-last 1 []) ()
+ (drop-last 1 [1]) ()
+ (drop-last 1 [1 2 3]) '(1 2)
+
+ (drop-last 2 []) ()
+ (drop-last 2 [1]) ()
+ (drop-last 2 [1 2 3]) '(1)
+
+ (drop-last 5 []) ()
+ (drop-last 5 [1]) ()
+ (drop-last 5 [1 2 3]) ()
+
+ (drop-last 0 []) ()
+ (drop-last 0 [1]) '(1)
+ (drop-last 0 [1 2 3]) '(1 2 3)
+
+ (drop-last -1 []) ()
+ (drop-last -1 [1]) '(1)
+ (drop-last -1 [1 2 3]) '(1 2 3)
+
+ (drop-last -2 []) ()
+ (drop-last -2 [1]) '(1)
+ (drop-last -2 [1 2 3]) '(1 2 3) ))
+
+
+(deftest test-split-at
+ (is (vector? (split-at 2 [])))
+ (is (vector? (split-at 2 [1 2 3])))
+
+ (are [x y] (= x y)
+ (split-at 2 []) [() ()]
+ (split-at 2 [1 2 3 4 5]) [(list 1 2) (list 3 4 5)]
+
+ (split-at 5 [1 2 3]) [(list 1 2 3) ()]
+ (split-at 0 [1 2 3]) [() (list 1 2 3)]
+ (split-at -1 [1 2 3]) [() (list 1 2 3)]
+ (split-at -5 [1 2 3]) [() (list 1 2 3)] ))
+
+
+(deftest test-split-with
+ (is (vector? (split-with pos? [])))
+ (is (vector? (split-with pos? [1 2 -1 0 3 4])))
+
+ (are [x y] (= x y)
+ (split-with pos? []) [() ()]
+ (split-with pos? [1 2 -1 0 3 4]) [(list 1 2) (list -1 0 3 4)]
+
+ (split-with pos? [-1 2 3 4 5]) [() (list -1 2 3 4 5)]
+ (split-with number? [1 -2 "abc" \x]) [(list 1 -2) (list "abc" \x)] ))
+
+
+(deftest test-repeat
+ (is (thrown? IllegalArgumentException (repeat)))
+
+ ; infinite sequence => use take
+ (are [x y] (= x y)
+ (take 0 (repeat 7)) ()
+ (take 1 (repeat 7)) '(7)
+ (take 2 (repeat 7)) '(7 7)
+ (take 5 (repeat 7)) '(7 7 7 7 7) )
+
+ ; limited sequence
+ (are [x y] (= x y)
+ (repeat 0 7) ()
+ (repeat 1 7) '(7)
+ (repeat 2 7) '(7 7)
+ (repeat 5 7) '(7 7 7 7 7)
+
+ (repeat -1 7) ()
+ (repeat -3 7) () )
+
+ ; test different data types
+ (are [x] (= (repeat 3 x) (list x 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} ))
+
+
+(deftest test-range
+ (are [x y] (= x y)
+ (range 0) () ; exclusive end!
+ (range 1) '(0)
+ (range 5) '(0 1 2 3 4)
+
+ (range -1) ()
+ (range -3) ()
+
+ (range 2.5) '(0 1)
+ (range 7/3) '(0 1)
+
+ (range 0 3) '(0 1 2)
+ (range 0 1) '(0)
+ (range 0 0) ()
+ (range 0 -3) ()
+
+ (range 3 6) '(3 4 5)
+ (range 3 4) '(3)
+ (range 3 3) ()
+ (range 3 1) ()
+ (range 3 0) ()
+ (range 3 -2) ()
+
+ (range -2 5) '(-2 -1 0 1 2 3 4)
+ (range -2 0) '(-2 -1)
+ (range -2 -1) '(-2)
+ (range -2 -2) ()
+ (range -2 -5) ()
+
+ (range 3 9 0) ()
+ (range 3 9 1) '(3 4 5 6 7 8)
+ (range 3 9 2) '(3 5 7)
+ (range 3 9 3) '(3 6)
+ (range 3 9 10) '(3)
+ (range 3 9 -1) () ))
+
+
+(deftest test-empty?
+ (are [x] (empty? x)
+ nil
+ ()
+ (lazy-seq nil) ; => ()
+ []
+ {}
+ #{}
+ ""
+ (into-array []) )
+
+ (are [x] (not (empty? x))
+ '(1 2)
+ (lazy-seq [1 2])
+ [1 2]
+ {:a 1 :b 2}
+ #{1 2}
+ "abc"
+ (into-array [1 2]) ))
+
+
+(deftest test-every?
+ ; always true for nil or empty coll/seq
+ (are [x] (= (every? pos? x) true)
+ nil
+ () [] {} #{}
+ (lazy-seq [])
+ (into-array []) )
+
+ (are [x y] (= x y)
+ true (every? pos? [1])
+ true (every? pos? [1 2])
+ true (every? pos? [1 2 3 4 5])
+
+ false (every? pos? [-1])
+ false (every? pos? [-1 -2])
+ false (every? pos? [-1 -2 3])
+ false (every? pos? [-1 2])
+ false (every? pos? [1 -2])
+ false (every? pos? [1 2 -3])
+ false (every? pos? [1 2 -3 4]) )
+
+ (are [x y] (= x y)
+ true (every? #{:a} [:a :a])
+;! false (every? #{:a} [:a :b]) ; Issue 68: every? returns nil instead of false
+;! false (every? #{:a} [:b :b]) ; http://code.google.com/p/clojure/issues/detail?id=68
+ ))
+
+
+(deftest test-not-every?
+ ; always false for nil or empty coll/seq
+ (are [x] (= (not-every? pos? x) false)
+ nil
+ () [] {} #{}
+ (lazy-seq [])
+ (into-array []) )
+
+ (are [x y] (= x y)
+ false (not-every? pos? [1])
+ false (not-every? pos? [1 2])
+ false (not-every? pos? [1 2 3 4 5])
+
+ true (not-every? pos? [-1])
+ true (not-every? pos? [-1 -2])
+ true (not-every? pos? [-1 -2 3])
+ true (not-every? pos? [-1 2])
+ true (not-every? pos? [1 -2])
+ true (not-every? pos? [1 2 -3])
+ true (not-every? pos? [1 2 -3 4]) )
+
+ (are [x y] (= x y)
+ false (not-every? #{:a} [:a :a])
+ true (not-every? #{:a} [:a :b])
+ true (not-every? #{:a} [:b :b]) ))
+
+
+(deftest test-not-any?
+ ; always true for nil or empty coll/seq
+ (are [x] (= (not-any? pos? x) true)
+ nil
+ () [] {} #{}
+ (lazy-seq [])
+ (into-array []) )
+
+ (are [x y] (= x y)
+ false (not-any? pos? [1])
+ false (not-any? pos? [1 2])
+ false (not-any? pos? [1 2 3 4 5])
+
+ true (not-any? pos? [-1])
+ true (not-any? pos? [-1 -2])
+
+ false (not-any? pos? [-1 -2 3])
+ false (not-any? pos? [-1 2])
+ false (not-any? pos? [1 -2])
+ false (not-any? pos? [1 2 -3])
+ false (not-any? pos? [1 2 -3 4]) )
+
+ (are [x y] (= x y)
+ false (not-any? #{:a} [:a :a])
+ false (not-any? #{:a} [:a :b])
+ true (not-any? #{:a} [:b :b]) ))
+
+
+; TODO: some
+
diff --git a/test/clojure/test_clojure/special.clj b/test/clojure/test_clojure/special.clj
new file mode 100644
index 00000000..f3a8164c
--- /dev/null
+++ b/test/clojure/test_clojure/special.clj
@@ -0,0 +1,24 @@
+; Copyright (c) Rich Hickey. 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.
+
+; Author: Frantisek Sodomka
+
+;;
+;; Test special forms, macros and metadata
+;;
+
+(ns clojure.test-clojure.special
+ (:use clojure.test))
+
+; http://clojure.org/special_forms
+
+; let, letfn
+; quote
+; var
+; fn
+
diff --git a/test/clojure/test_clojure/test.clj b/test/clojure/test_clojure/test.clj
new file mode 100644
index 00000000..38cf802f
--- /dev/null
+++ b/test/clojure/test_clojure/test.clj
@@ -0,0 +1,113 @@
+; Copyright (c) Rich Hickey. 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_contrib/test_is.clj: unit tests for test_is.clj
+
+;; by Stuart Sierra
+;; January 16, 2009
+
+;; Thanks to Chas Emerick, Allen Rohner, and Stuart Halloway for
+;; contributions and suggestions.
+
+
+(ns clojure.test-clojure.test
+ (:use clojure.test))
+
+(deftest can-test-symbol
+ (let [x true]
+ (is x "Should pass"))
+ (let [x false]
+ (is x "Should fail")))
+
+(deftest can-test-boolean
+ (is true "Should pass")
+ (is false "Should fail"))
+
+(deftest can-test-nil
+ (is nil "Should fail"))
+
+(deftest can-test-=
+ (is (= 2 (+ 1 1)) "Should pass")
+ (is (= 3 (+ 2 2)) "Should fail"))
+
+(deftest can-test-instance
+ (is (instance? Integer (+ 2 2)) "Should pass")
+ (is (instance? Float (+ 1 1)) "Should fail"))
+
+(deftest can-test-thrown
+ (is (thrown? ArithmeticException (/ 1 0)) "Should pass")
+ ;; No exception is thrown:
+ (is (thrown? Exception (+ 1 1)) "Should fail")
+ ;; Wrong class of exception is thrown:
+ (is (thrown? ArithmeticException (throw (RuntimeException.))) "Should error"))
+
+(deftest can-test-thrown-with-msg
+ (is (thrown-with-msg? ArithmeticException #"Divide by zero" (/ 1 0)) "Should pass")
+ ;; Wrong message string:
+ (is (thrown-with-msg? ArithmeticException #"Something else" (/ 1 0)) "Should fail")
+ ;; No exception is thrown:
+ (is (thrown? Exception (+ 1 1)) "Should fail")
+ ;; Wrong class of exception is thrown:
+ (is (thrown-with-msg? IllegalArgumentException #"Divide by zero" (/ 1 0)) "Should error"))
+
+(deftest can-catch-unexpected-exceptions
+ (is (= 1 (throw (Exception.))) "Should error"))
+
+(deftest can-test-method-call
+ (is (.startsWith "abc" "a") "Should pass")
+ (is (.startsWith "abc" "d") "Should fail"))
+
+(deftest can-test-anonymous-fn
+ (is (#(.startsWith % "a") "abc") "Should pass")
+ (is (#(.startsWith % "d") "abc") "Should fail"))
+
+(deftest can-test-regexps
+ (is (re-matches #"^ab.*$" "abbabba") "Should pass")
+ (is (re-matches #"^cd.*$" "abbabba") "Should fail")
+ (is (re-find #"ab" "abbabba") "Should pass")
+ (is (re-find #"cd" "abbabba") "Should fail"))
+
+
+;; still have to declare the symbol before testing unbound symbols
+(declare does-not-exist)
+
+(deftest can-test-unbound-symbol
+ (is (= nil does-not-exist) "Should error"))
+
+(deftest can-test-unbound-function
+ (is (does-not-exist) "Should error"))
+
+
+;; Here, we create an alternate version of test-is/report, that
+;; compares the event with the message, then calls the original
+;; 'report' with modified arguments.
+
+(declare original-report)
+
+(defn custom-report [data]
+ (let [event (:type data)
+ msg (:message data)
+ expected (:expected data)
+ actual (:actual data)
+ passed (cond
+ (= event :fail) (= msg "Should fail")
+ (= event :pass) (= msg "Should pass")
+ (= event :error) (= msg "Should error")
+ :else true)]
+ (if passed
+ (original-report {:type :pass, :message msg,
+ :expected expected, :actual actual})
+ (original-report {:type :fail, :message (str msg " but got " event)
+ :expected expected, :actual actual}))))
+
+;; test-ns-hook will be used by test-is/test-ns to run tests in this
+;; namespace.
+(defn test-ns-hook []
+ (binding [original-report report
+ report custom-report]
+ (test-all-vars (find-ns 'clojure.test-clojure.test))))
diff --git a/test/clojure/test_clojure/test_fixtures.clj b/test/clojure/test_clojure/test_fixtures.clj
new file mode 100644
index 00000000..707dcc38
--- /dev/null
+++ b/test/clojure/test_clojure/test_fixtures.clj
@@ -0,0 +1,41 @@
+; Copyright (c) Rich Hickey. 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_is_fixtures.clj: unit tests for fixtures in test_is.clj
+
+;; by Stuart Sierra
+;; March 28, 2009
+
+(ns clojure.test-clojure.test-fixtures
+ (:use clojure.test))
+
+(declare *a* *b* *c* *d*)
+
+(defn fixture-a [f]
+ (binding [*a* 3] (f)))
+
+(defn fixture-b [f]
+ (binding [*b* 5] (f)))
+
+(defn fixture-c [f]
+ (binding [*c* 7] (f)))
+
+(defn fixture-d [f]
+ (binding [*d* 11] (f)))
+
+(use-fixtures :once fixture-a fixture-b)
+
+(use-fixtures :each fixture-c fixture-d)
+
+(deftest can-use-once-fixtures
+ (is (= 3 *a*))
+ (is (= 5 *b*)))
+
+(deftest can-use-each-fixtures
+ (is (= 7 *c*))
+ (is (= 11 *d*)))
diff --git a/test/clojure/test_clojure/test_utils.clj b/test/clojure/test_clojure/test_utils.clj
new file mode 100644
index 00000000..d1905100
--- /dev/null
+++ b/test/clojure/test_clojure/test_utils.clj
@@ -0,0 +1,33 @@
+; Copyright (c) Rich Hickey. 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.
+
+; Author: Frantisek Sodomka
+
+
+(ns clojure.test-clojure.test-utils)
+
+ (defn exception
+ "Use this function to ensure that execution of a program doesn't
+ reach certain point."
+ []
+ (throw (new Exception "Exception which should never occur")))
+
+
+;; (defmacro all-are
+;; "Test all-with-all.
+;; (all-are (= _1 _2)
+;; a b c)
+;; =>
+;; (do
+;; (is (= a b))
+;; (is (= a c))
+;; (is (= b c)))"
+;; [expr & args]
+;; (concat
+;; (list 'clojure.contrib.template/do-template (list 'clojure.test/is expr))
+;; (apply concat (combinations args 2)))))
diff --git a/test/clojure/test_clojure/vars.clj b/test/clojure/test_clojure/vars.clj
new file mode 100644
index 00000000..cbdc72d9
--- /dev/null
+++ b/test/clojure/test_clojure/vars.clj
@@ -0,0 +1,56 @@
+; Copyright (c) Rich Hickey. 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.
+
+; Author: Frantisek Sodomka
+
+
+(ns clojure.test-clojure.vars
+ (:use clojure.test))
+
+; http://clojure.org/vars
+
+; def
+; defn defn- defonce
+
+; declare intern binding find-var var
+
+(def a)
+(deftest test-binding
+ (are [_1 _2] (= _1 _2)
+ (eval `(binding [a 4] a)) 4 ; regression in Clojure SVN r1370
+ ))
+
+; with-local-vars var-get var-set alter-var-root [var? (predicates.clj)]
+; with-in-str with-out-str
+; with-open
+; with-precision
+
+(deftest test-with-precision
+ (are [x y] (= x y)
+ (with-precision 4 (+ 3.5555555M 1)) 4.556M
+ (with-precision 6 (+ 3.5555555M 1)) 4.55556M
+ (with-precision 6 :rounding CEILING (+ 3.5555555M 1)) 4.55556M
+ (with-precision 6 :rounding FLOOR (+ 3.5555555M 1)) 4.55555M
+ (with-precision 6 :rounding HALF_UP (+ 3.5555555M 1)) 4.55556M
+ (with-precision 6 :rounding HALF_DOWN (+ 3.5555555M 1)) 4.55556M
+ (with-precision 6 :rounding HALF_EVEN (+ 3.5555555M 1)) 4.55556M
+ (with-precision 6 :rounding UP (+ 3.5555555M 1)) 4.55556M
+ (with-precision 6 :rounding DOWN (+ 3.5555555M 1)) 4.55555M
+ (with-precision 6 :rounding UNNECESSARY (+ 3.5555M 1)) 4.5555M))
+
+(deftest test-settable-math-context
+ (is (=
+ (clojure.main/with-bindings
+ (set! *math-context* (java.math.MathContext. 8))
+ (+ 3.55555555555555M 1))
+ 4.5555556M)))
+
+; set-validator get-validator
+
+; doc find-doc test
+