unit-test/0000755000076500000240000000000011027555740012001 5ustar shanestaffunit-test/explore-clojure.clj0000644000076500000240000000606111027555740015615 0ustar shanestaff;; explore-clojure.clj ;; ;; Copyright (c) Shane Celis. ;; ;; The use and distribution terms for this software are covered by the ;; Common Public License 1.0 (http://opensource.org/licenses/cpl.php) ;; which can be found in the file CPL.TXT 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. ;; This is just some exploratory programming of clojure encapsulated ;; as tests. (clojure/refer 'unit-test) (deftest test-shadow-fns [] (assert-true (= 3 (+ 1 2))) (let [+ (fn [& xs] 4)] ;; Cool. I can shadow functions. Expected for a Lisp-1, but I like ;; seeing it for myself. (assert-true (= 4 (+ 1 2))))) (deftest test-assert-equal [] (assert-equal 3 (+ 1 2)) (assert-fail (assert-equal 4 (+ 1 2) "we expect this failure")) (assert-fail (assert-equal 4 (+ 1 2)) )) (deftest test-split-with [] "split-with doesn't work the way I'd expect" (let [[string other] (split-with string? [1 "2" 3 "4"])] (assert-equal nil string) (assert-equal [1 "2" 3 "4"] other))) (deftest test-maps [] (let [h {:a 1 :b 2 :c 3}] (assert-equal 1 (h :a)) (assert-equal 1 (:a h)) (assert-equal {:a 1 :b 2 :c 4} (assoc h :c 4)) )) (deftest test-apply-map-macros ;; XXX - deftest doesn't work with string documents. FIX ME. ;; "This is interesting, one can apply and map macros, which ;; both provide strange results, but one can then evaluate those ;; results and get the right result. I'm not sure if it was ;; intentional, but I think it's an interesting 'feature'." [] (assert-true (not= false (apply and '(true false)))) (assert-true (= false (eval (apply and '(true false))))) (assert-true (not= true (apply and '(true true)))) (assert-true (= true (eval (apply and '(true true))))) ;; You can even map the macros, but then you have to map the evaluations. (assert-true (not= '(true false) (map and '(true false) '(true true)))) (assert-true (= '(true false) (map eval (map and '(true false) '(true true))))) ) (deftest test-reduce [] (let [a [1 2 3] f (fn [s n] (str s n)) g (fn [n s] (str s n)) ] (assert-equal 6 (reduce + a)) (assert-equal 6 (reduce + 0 a)) (assert-equal 7 (reduce + 1 a)) (assert-equal "7" (str 7)) (assert-equal "begin123" (reduce f "begin" a)) (assert-equal "321begin" (reduce g "begin" a)) )) (deftest test-local-vars [] (let [f (fn [y] (var-set y (inc @y)))] (with-local-vars [x 1] (assert-equal 1 @x) ; (set! '@x 2) (var-set x 2) (assert-equal 2 @x) (f x) (assert-equal 3 @x) ))) (defn collector [] (with-local-vars [l '()] (fn [x] (if (= x :list) (var-get l) (var-set l (cons x @l)))))) (deftest test-collector [] ;; Nope. Doesn't work the way I expected. (assert-expect Exception (let [f (collector)] (assert-equal '() (f :list))))) unit-test/Makefile0000644000076500000240000000006411027555740013441 0ustar shanestaffREADME.html: README markdown README > README.html unit-test/README0000644000076500000240000000520711027555740012665 0ustar shanestaffUnit Test Framework for Clojure =============================== Written by Shane Celis on 2008-06-22 This document describes a unit test framework for Clojure. It is a [xUnit framework][1] in the same vein as [JUnit][2]. Download -------- Here is the tarball [unit-test_v0.1.0.tgz](/clojure/unit-test_v0.1.0.tgz). Examples -------- I think it is best illustrated with some simple code examples. (in-ns 'user) (refer 'unit-test) (deftest my-example-test [] (let [x 1] (assert-equal 1 x "x is NOT one!"))) One can then run the tests like this: user> (run-all-tests) . Tests run 1 failures 0 errors 0 nil The output is very terse. This is typical for passing unit tests. One does not want to print out anything unless something fails. Let us create a new test that will fail to show what its output will look like. (deftest my-failing-example-test [] (let [x 1] (assert-equal 1 (inc x) "is NOT one!"))) Running it produces this output: user> (run-all-tests) ..F Tests run 2 failures 1 errors 0 Failures: 1) Expected: 1 but was: 2 <- (inc x) is NOT one! clojure.fns.user.my_failing_example_test__2889.invoke(readme-examples.clj:45) nil The failure message shows what value was expected, what value was produced, and thanks to macros what the expression was that produced that value and the message. The failure also produces a stack trace. The stack trace shown has been filtered of all Java files, code from `boot.clj` and `unit-test.clj`, so that it hopefully identifies only the code that is pertinent to the failing test. The filters on the stack trace can be modified by changing the `ignore-files` definition. Finally, let me demonstrate a test that produces an error, i.e. an exception. (deftest my-error-example-test [] (let [x 1] (cast String x))) Its output: user> (run-all-tests) ..E.F Tests run 3 failures 1 errors 1 Failures: 1) Expected: 1 but was: 2 <- (inc x) is NOT one! clojure.fns.user.my_failing_example_test__2900.invoke(readme-examples.clj:45) Errors: 1) java.lang.ClassCastException clojure.fns.user.my_error_example_test__2903.invoke(readme-examples.clj:27) nil Conclusion ---------- I hope that is enough to allow one to pick up this unit-test framework for Clojure and write some unit tests. This introduction was very quick, so please see the links listed above for a more thorough introduction to unit testing. Look at `explore-clojure.clj` for some examples of unit tests. [1]: http://en.wikipedia.org/wiki/XUnit [2]: http://www.junit.org/ unit-test/readme-examples.clj0000644000076500000240000000144111027555740015544 0ustar shanestaff;; readme-examples.clj ;; ;; Copyright (c) Shane Celis. ;; ;; The use and distribution terms for this software are covered by the ;; Common Public License 1.0 (http://opensource.org/licenses/cpl.php) ;; which can be found in the file CPL.TXT 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. ;; This is code that is demonstrated in the README file. (in-ns 'user) (refer 'unit-test) (deftest my-example-test [] (let [x 1] (assert-equal 1 x "x is NOT one!"))) (deftest my-failing-example-test [] (let [x 1] (assert-equal 1 (inc x) "(inc x) is NOT one!"))) (deftest my-error-example-test [] (let [x 1] (cast String x))) unit-test/README.html0000644000076500000240000000544611027555740013635 0ustar shanestaff

Unit Test Framework for Clojure

Written by Shane Celis on 2008-06-22

This document describes a unit test framework for Clojure. It is a xUnit framework in the same vein as JUnit.

Download

Here is the tarball unit-test_v0.1.0.tgz.

Examples

I think it is best illustrated with some simple code examples.

 (in-ns 'user)
 (refer 'unit-test)
 (deftest my-example-test []
   (let [x 1]
     (assert-equal 1 x "x is NOT one!")))

One can then run the tests like this:

user> (run-all-tests)
.
Tests run 1 failures 0 errors 0
nil

The output is very terse. This is typical for passing unit tests. One does not want to print out anything unless something fails. Let us create a new test that will fail to show what its output will look like.

 (deftest my-failing-example-test []
   (let [x 1]
     (assert-equal 1 (inc x) "is NOT one!")))

Running it produces this output:

user> (run-all-tests)
..F
Tests run 2 failures 1 errors 0
Failures:
1) Expected: 1 but was: 2 <- (inc x) is NOT one!
     clojure.fns.user.my_failing_example_test__2889.invoke(readme-examples.clj:45)
nil

The failure message shows what value was expected, what value was produced, and thanks to macros what the expression was that produced that value and the message.

The failure also produces a stack trace. The stack trace shown has been filtered of all Java files, code from boot.clj and unit-test.clj, so that it hopefully identifies only the code that is pertinent to the failing test. The filters on the stack trace can be modified by changing the ignore-files definition.

Finally, let me demonstrate a test that produces an error, i.e. an exception.

(deftest my-error-example-test []
  (let [x 1]
    (cast String x)))

Its output:

user> (run-all-tests)
..E.F
Tests run 3 failures 1 errors 1
Failures:
1) Expected: 1 but was: 2 <- (inc x) is NOT one!
    clojure.fns.user.my_failing_example_test__2900.invoke(readme-examples.clj:45)
Errors:
1) java.lang.ClassCastException
    clojure.fns.user.my_error_example_test__2903.invoke(readme-examples.clj:27)
nil

Conclusion

I hope that is enough to allow one to pick up this unit-test framework for Clojure and write some unit tests. This introduction was very quick, so please see the links listed above for a more thorough introduction to unit testing. Look at explore-clojure.clj for some examples of unit tests.

unit-test/unit-test-examples.clj0000644000076500000240000000333711027555740016251 0ustar shanestaff;; unit-test-examples.clj ;; ;; Copyright (c) Shane Celis. ;; ;; The use and distribution terms for this software are covered by the ;; Common Public License 1.0 (http://opensource.org/licenses/cpl.php) ;; which can be found in the file CPL.TXT 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. ;; This test demonstrates a number of simple tests, and also exercises ;; the UI in terms of what it shows for failures and errors. (in-ns 'unit-test-examples) (clojure/refer 'clojure) (clojure/refer 'unit-test) (deftest good-test [] (assert-equal 1 1)) (deftest failing-test [] (assert-equal 1 (+ 1 1))) (deftest error-test [] (throw (new Exception "I am an exception in error-test."))) (deftest catching-test [] (assert-expect Exception (do (throw (new Exception "I am an error in catching."))) "Didn't get an exception")) (deftest failing-catching-test [] (assert-expect java.lang.AssertionError (do (throw (new Exception "I am an error in failing-catching-test."))) "Didn't get an exception")) (deftest test-assertions [] (let [x 1 y 2 z 1 a "A" b "B" c "A"] (assert-equal x z) (assert-not-equal 1 2) (assert-same x x) (assert-same x z) ;; <-- that's a little bit of a surprise. (assert-same "7" "7") (assert-not-same "7" (str 7)) (assert-same c a) (assert-nil nil) (assert-not-nil x) (assert-true true) (assert-true (= 1 1)) (assert-true "hi") (assert-not-true false) )) unit-test/unit-test-test.clj0000644000076500000240000000447211027555740015413 0ustar shanestaff;; unit-test-test.clj ;; ;; Copyright (c) Shane Celis. ;; ;; The use and distribution terms for this software are covered by the ;; Common Public License 1.0 (http://opensource.org/licenses/cpl.php) ;; which can be found in the file CPL.TXT 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. ;; All right. Here's where we go meta. This tests the unit-test ;; framework. It's a nice demonstration of the framework being ;; flexible enough to test itself. (in-ns 'unit-test-test) (clojure/refer 'clojure) (clojure/refer 'unit-test) (clojure/refer 'unit-test-examples) (defn result-count [test-result] ;; There's a map map waiting to bust out from this code. {:tests (count (:tests test-result)) :failures (count (:failures test-result)) :errors (count (:errors test-result))}) (defn run [& tests] (result-count (exec-tests tests))) (defn assert-result [t f e r & msgs] (assert-equal t (:tests r) (str msgs)) (assert-equal f (:failures r) (str msgs)) (assert-equal e (:errors r) (str msgs)) ) (deftest test-good-test [] (let [r (run #'good-test)] (assert-result 1 0 0 r))) (deftest test-failing-test [] (let [r (run #'failing-test)] (assert-result 1 1 0 r))) (deftest test-error-test [] (let [r (run #'error-test)] (assert-result 1 0 1 r))) (deftest test-catching-test [] (let [r (run #'catching-test)] (assert-result 1 0 0 r))) (deftest test-failing-catching-test [] (let [r (run #'failing-catching-test)] (assert-result 1 0 1 r))) (deftest test-all-combo [] (let [r (run #'good-test #'failing-test #'error-test #'catching-test #'failing-catching-test)] (assert-result 5 1 2 r))) (deftest test-failing-assertions [] (let [x 1 y 2 z 1] (assert-fail-each ;; These assertions are all failing assertions--that are caught (assert-equal x y) (assert-equal 2 1) (assert-same x y) (assert-not-same x x) (assert-not-same x z) ;; <-- that's a little bit of a surprise. (assert-not-same "7" "7") (assert-same "7" (str 7)) (assert-nil x) (assert-not-nil nil) (assert-true false) (assert-true (= 1 2)) (assert-false "hi") (assert-not-true true) ))) unit-test/unit-test.clj0000644000076500000240000002056411027555740014436 0ustar shanestaff;; unit-test.clj ;; ;; Copyright (c) Shane Celis. ;; ;; The use and distribution terms for this software are covered by the ;; Common Public License 1.0 (http://opensource.org/licenses/cpl.php) ;; which can be found in the file CPL.TXT 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. ;; This library is an xUnit unit testing framework for Clojure. (in-ns 'unit-test) (clojure/refer 'clojure) (def #^{:doc "Ignore stack traces from these patterns"}ignore-files [".*\\.java" "swank-clojure\\.clj" "boot\\.clj" "unit-test\\.clj"]) (defmacro deftest "Defines a test by adding a :unit-test tag to the function's meta data." [name parameters & body] `(defn ~name {:unit-test true} ~parameters ~@body)) (defstruct #^{:doc "Stores the tests executed; failures and errors are lists of throwables."} test-result :tests :failures :errors) (defn init-test-result "Returns an initialized test-result map." [] (struct-map test-result :tests '() :failures '() :errors '())) (defn fail "Fail a test returning a message." ([] (throw (new java.lang.AssertionError "Assert failed!"))) ([& msgs] (throw (new java.lang.AssertionError (apply str msgs))))) (defmacro assert-equal "Passes if expected is equal to actual." [expected actual & msgs] `(let [e# ~expected a# ~actual] (when-not (= e# a#) (fail "Expected: " (pr-str e#) " but was: " (pr-str a#) " <- " (pr-str '~actual) " " ~@msgs)))) (defmacro assert-not-equal "Passes if expected is not equal to actual." [expected actual & msgs] `(let [e# ~expected a# ~actual] (when-not (not= e# a#) (fail "Did not expect: " (pr-str e#) " but was: " (pr-str a#) " <- " (pr-str '~actual) " " ~@msgs)))) (defmacro assert-same "Passes if expected is identical to actual." [expected actual & msgs] `(let [e# ~expected a# ~actual] (when-not (identical? e# a#) (fail "Expected same: " (pr-str e#) " but was: " (pr-str a#) " <- " (pr-str '~actual) " " ~@msgs)))) (defmacro assert-not-same "Passes if expected is not identical to actual." [expected actual & msgs] `(let [e# ~expected a# ~actual] (when-not (not (identical? e# a#)) (fail "Did not expect same: " (pr-str e#) " but was: " (pr-str a#) " <- " (pr-str '~actual) " " ~@msgs)))) (defmacro assert-nil "Passes if actual is nil." [actual & msgs] `(let [a# ~actual] (when-not (nil? a#) (fail "Expected nil but was: " (pr-str a#) " <- " (pr-str '~actual) " " ~@msgs)))) (defmacro assert-not-nil "Passes if actual is not nil." [actual & msgs] `(let [a# ~actual] (when-not (not (nil? a#)) (fail "Expected not nil but was: " (pr-str a#) " <- " (pr-str '~actual) " " ~@msgs)))) (defmacro assert-true "Passes if actual is true." [actual & msgs] `(let [a# ~actual] (when-not a# (fail "Expected true but was: " (pr-str a#) " <- " (pr-str '~actual) " " ~@msgs)))) (defmacro assert-not-true "Passes if actual is not true (synonym for assert-false)." [actual & msgs] `(let [a# ~actual] (when-not (not a#) (fail "Expected not true but was: " (pr-str a#) " <- " (pr-str '~actual) " " ~@msgs)))) (defmacro assert-false "Passes if actual is false (synonym for assert-not-true)." [actual & msgs] `(let [a# ~actual] (when-not (not a#) (fail "Expected false but was: " (pr-str a#) " <- " (pr-str '~actual) " " ~@msgs)))) (defmacro assert-expect "Passes if the expr produces the expected exception." ([exception expr] `(assert-expect ~exception ~expr "Did not get expected exception " ~exception)) ([exception expr & msgs] `(let [v# (try ~expr (catch ~exception e# ;;good :caught-one ))] (when-not (= v# :caught-one) (fail ~@msgs))))) (defmacro assert-fail "Passes if the expr produces a failure." [expr & msgs] `(assert-expect java.lang.AssertionError ~expr ~@msgs)) (defmacro assert-fail-each "Passes if all expressions produce a failure." [& exprs] `(do ~@(map (partial list 'assert-fail) exprs))) ;; (defmacro defassert [name args hash] ;; `(defmacro ~name ~args ;; (when-not (apply (fn ~args (:test ~hash)) ~args) ;; (fail (apply (fn ~args (:msg ~hash)) ~args))))) (defn rpartial "Like partial but arguments are appended from the end not the beginning." [f & x] (fn [& y] (apply f (concat y x)))) (defn all-tests "Returns all the tests in the given namespace or in the current namespace." ([] (all-tests (ns-name *ns*))) ([ns-sym] (let [ns (or (find-ns ns-sym) (throw (new Exception "No such namespace"))) fns (map second (ns-interns ns)) metas (map meta fns) tests (filter (comp (rpartial contains? :unit-test) second) (map list fns metas))] (map first tests)))) ;; (defn mapn [f & xs] ;; (loop [ys xs] ;; (when-not (some nil? ys) ;; (apply f (map first ys)) ;; (recur (map rest ys))))) (defn to-list "Converts a Java array to a list." [arr] (map (partial aget arr) (range (alength arr)))) ;; ah, didn't see interpose. ;(defn join-with [delim list] ; (apply str (rest (interleave (repeat delim) list)))) (defn filter-stacktrace "Filters a stacktrace removing file patterns defined in ignore-files." [t] (let [es (to-list (. t getStackTrace)) cljs (filter (comp not nil? (memfn getFileName)) es) ignore-regex (str "(" (apply str (interpose "|" ignore-files)) ")") ignore-pattern (re-pattern ignore-regex) junk (filter (comp not (partial re-matches ignore-pattern) (memfn getFileName)) cljs) ] junk)) (defn assoc-append "Appends an element to a map's list for a particular key." [map key val] (assoc map key (cons val (map key)))) (defn show-stacktraces "Shows a stack trace that has been filtered to hopefully show only the useful information." [failures] (let [f (fn [failure n] (println (str (inc n) ")") (if (instance? java.lang.AssertionError failure) (. failure getMessage) (. failure toString))) (doall (map (partial println " ") (filter-stacktrace failure))))] (doall (map f failures (range (count failures)))) )) (defn show-test-result "Prints the contents of a test result in human readable format." [tresult] (let [tests (:tests tresult) failures (:failures tresult) errors (:errors tresult)] (newline) (println "Tests run" (count tests) "failures" (count failures) "errors" (count errors)) (when (> (count failures) 0) (println "Failures:") (show-stacktraces (reverse failures))) (when (> (count errors) 0) (println "Errors:") (show-stacktraces (reverse errors))) )) (defn run-test "Runs one test and appends the results to the given test-result or a new test-result." ([test] (run-test test (init-test-result))) ([test test-result] (let [r (try (do (print ".") (test) test-result) (catch java.lang.AssertionError a (print "F") (assoc-append test-result :failures a) ) (catch Throwable t (print "E") (assoc-append test-result :errors t) ) )] (assoc-append r :tests test)))) (defn my-split-with "Splits a collection exhaustively into a [matching not-matching] vector." [pred coll] [(filter pred coll) (filter (comp not pred) coll)]) (defn run-tests "Runs the given tests or runs all the tests given from (all-tests)" ([] (run-tests (all-tests))) ([tests] (let [tresult (reduce #(run-test %2 %1) (init-test-result) tests)] (show-test-result tresult) (flush)))) (defn run-all-tests "Runs all the tests in the given or current namespace." ([] (run-all-tests (ns-name *ns*))) ([ns-sym] (run-tests (all-tests ns-sym)))) (defn exec-tests "Runs the tests and returns the test result without any printing." ([] (exec-tests (all-tests))) ([tests] (binding [print (fn [& x])] (reduce #(run-test %2 %1) (init-test-result) tests) )))