2017-10-20 18:00:47 +03:00
|
|
|
(defmodule IO
|
|
|
|
(defn color-table []
|
|
|
|
[[@"black" @"30"]
|
|
|
|
[@"red" @"31"]
|
|
|
|
[@"green" @"32"]
|
|
|
|
[@"yellow" @"33"]
|
|
|
|
[@"blue" @"34"]
|
|
|
|
[@"magenta" @"35"]
|
|
|
|
[@"cyan" @"36"]
|
|
|
|
[@"white" @"37"]
|
|
|
|
[@"reset" @"0"]
|
|
|
|
[@"none" @"0"]
|
|
|
|
[@"bold" @"1"]
|
|
|
|
[@"italic" @"3"]
|
|
|
|
[@"underline" @"4"]
|
|
|
|
[@"blink-slow" @"5"]
|
|
|
|
[@"blink-rapid" @"6"]
|
|
|
|
[@"bg-black" @"40"]
|
|
|
|
[@"bg-red" @"41"]
|
|
|
|
[@"bg-green" @"42"]
|
|
|
|
[@"bg-yellow" @"43"]
|
|
|
|
[@"bg-blue" @"44"]
|
|
|
|
[@"bg-magenta" @"45"]
|
|
|
|
[@"bg-cyan" @"46"]
|
|
|
|
[@"bg-white" @"47"]])
|
|
|
|
|
|
|
|
(def len-color-table 23) ; should be a count-macro
|
|
|
|
|
|
|
|
(defn color-name-to-ansi [cname]
|
|
|
|
(let [res @""]
|
|
|
|
(do
|
|
|
|
(for [i 0 len-color-table]
|
|
|
|
(if (String.= cname (Array.nth (Array.nth &(color-table) i) 0))
|
|
|
|
(set! &res @(Array.nth (Array.nth &(color-table) i) 1))
|
|
|
|
()))
|
|
|
|
(String.append @"\x1b[" (String.append res @"m")))))
|
|
|
|
|
|
|
|
|
|
|
|
(defn color [cname]
|
|
|
|
(print &(color-name-to-ansi cname)))
|
|
|
|
)
|
|
|
|
|
|
|
|
(defmodule Test
|
|
|
|
(deftype State [passed Int, failed Int])
|
|
|
|
|
2017-10-24 14:52:32 +03:00
|
|
|
(defn handler [state expected actual descr what op str]
|
2017-10-20 18:00:47 +03:00
|
|
|
(if (op expected actual)
|
|
|
|
(do
|
|
|
|
(IO.color "green")
|
|
|
|
(IO.println &(string-join @"Test '" @descr @"' passed"))
|
|
|
|
(IO.color "reset")
|
|
|
|
(State.update-passed (State.copy state) Int.inc))
|
|
|
|
(do
|
|
|
|
(IO.color "red")
|
2017-11-15 16:06:49 +03:00
|
|
|
(IO.println &(string-join @"Test '" @descr @"' failed:"))
|
|
|
|
(IO.print &(string-join @"\tExpected " @what @": '"))
|
2017-10-20 18:00:47 +03:00
|
|
|
(IO.print &(str expected))
|
|
|
|
(IO.println &(string-join @"', actual value: '" (str actual) @"'"))
|
|
|
|
(IO.color "reset")
|
|
|
|
(State.update-failed (State.copy state) Int.inc))))
|
|
|
|
|
2017-10-24 14:52:32 +03:00
|
|
|
(defn assert-equal [state x y descr op str]
|
|
|
|
(handler state x y descr "value" op str))
|
2017-10-20 18:00:47 +03:00
|
|
|
|
|
|
|
(defn assert-str-equal [state x y descr]
|
2017-10-24 14:52:32 +03:00
|
|
|
(assert-equal state x y descr String.= String.str))
|
2017-10-20 18:00:47 +03:00
|
|
|
|
|
|
|
(defn assert-int-equal [state x y descr]
|
2017-10-24 14:52:32 +03:00
|
|
|
(assert-equal state x y descr Int.= Int.str))
|
2017-10-20 18:00:47 +03:00
|
|
|
|
|
|
|
(defn assert-bool-equal [state x y descr]
|
2017-10-24 14:52:32 +03:00
|
|
|
(assert-equal state x y descr Bool.= Bool.str))
|
2017-10-20 18:00:47 +03:00
|
|
|
|
2017-10-24 14:52:32 +03:00
|
|
|
(defn assert-not-equal [state x y descr op str]
|
|
|
|
(handler state x y descr "not value" op str))
|
2017-10-20 18:00:47 +03:00
|
|
|
|
|
|
|
(defn assert-bool-not-equal [state x y descr]
|
2017-10-24 14:52:32 +03:00
|
|
|
(assert-equal state x y descr Bool./= Bool.str))
|
2017-10-20 18:00:47 +03:00
|
|
|
|
|
|
|
(defn assert-str-not-equal [state x y descr]
|
2017-10-24 14:52:32 +03:00
|
|
|
(assert-equal state x y descr String./= String.str))
|
2017-10-20 18:00:47 +03:00
|
|
|
|
|
|
|
(defn assert-int-not-equal [state x y descr]
|
2017-10-24 14:52:32 +03:00
|
|
|
(assert-equal state x y descr Int./= Int.str))
|
2017-10-20 18:00:47 +03:00
|
|
|
|
|
|
|
(defn assert-true [state x descr]
|
|
|
|
(assert-bool-equal state true x descr))
|
|
|
|
|
|
|
|
(defn assert-false [state x descr]
|
|
|
|
(assert-bool-equal state false x descr))
|
|
|
|
|
|
|
|
(defn reset [state]
|
|
|
|
(State.set-failed (State.set-passed state 0) 0))
|
|
|
|
|
|
|
|
(defn print-test-results [state]
|
|
|
|
(let [passed (State.passed state)
|
|
|
|
failed (State.failed state)]
|
|
|
|
(do
|
|
|
|
(IO.println "Results:")
|
|
|
|
(if (Int.> (Int.+ passed failed) 0)
|
|
|
|
(do
|
|
|
|
(IO.color "green")
|
|
|
|
(if (Int.> passed 0) (IO.print &(String.append @"\t|" (String.repeat passed "="))) ())
|
|
|
|
(if (Int.= failed 0) (IO.print "|") ())
|
|
|
|
(IO.color "red")
|
|
|
|
(if (Int.= passed 0) (IO.print "\t|") ())
|
|
|
|
(if (Int.> failed 0) (IO.print &(String.append (String.repeat failed "=") @"|")) ())
|
|
|
|
(IO.println ""))
|
|
|
|
())
|
|
|
|
(IO.color "green")
|
|
|
|
(IO.print "\tPassed: ")
|
|
|
|
(IO.print &(Int.str passed))
|
|
|
|
(IO.color "red")
|
|
|
|
(IO.print "\tFailed: ")
|
|
|
|
(IO.println &(Int.str failed))
|
|
|
|
(IO.color "reset")
|
|
|
|
(State.copy state))))
|
|
|
|
)
|
|
|
|
|
|
|
|
(defdynamic with-test-internal [name forms]
|
|
|
|
(if (= (count forms) 1)
|
|
|
|
(list (list 'set! (list 'ref name) (list 'ref (car forms))))
|
|
|
|
(cons (list 'set! (list 'ref name) (list 'ref (car forms)))
|
|
|
|
(with-test-internal name (cdr forms)))))
|
|
|
|
|
|
|
|
|
|
|
|
(defmacro with-test [name :rest forms]
|
|
|
|
(list 'let [name &(Test.State.init 0 0)]
|
2017-11-22 15:48:58 +03:00
|
|
|
(cons-last
|
|
|
|
(list 'Test.State.failed name)
|
|
|
|
(cons 'do (with-test-internal name forms)))))
|
2017-10-20 18:00:47 +03:00
|
|
|
|
|
|
|
(defmacro deftest [name state-name :rest forms]
|
|
|
|
(list 'defn name []
|
|
|
|
(list 'let [state-name &(Test.State.init 0 0)]
|
|
|
|
(cons-last
|
|
|
|
(list Test.print-test-results state-name)
|
|
|
|
(cons 'do (with-test-internal state-name forms))))))
|