Add libtest (#1112)
* Add add-libtest script and add 2 libraries with it * Add tests for 3 existing libraries
This commit is contained in:
parent
becdabe100
commit
4e7d04f672
12 changed files with 879 additions and 43 deletions
6
deps.edn
6
deps.edn
|
|
@ -61,7 +61,7 @@
|
|||
:sha "a4e5fb5383f5c0d83cb2d005181a35b76d8a136d"}
|
||||
cprop/cprop {:mvn/version "0.1.16"}
|
||||
comb/comb {:mvn/version "0.1.1"}
|
||||
mvxcvi/arrangement {:mvn/version "1.2.0"}
|
||||
mvxcvi/arrangement {:mvn/version "2.0.0"}
|
||||
org.clojure/data.zip {:mvn/version "1.0.0"}
|
||||
clojure-csv/clojure-csv {:mvn/version "2.0.2"}
|
||||
org.clojure/math.combinatorics {:mvn/version "0.1.6"}
|
||||
|
|
@ -101,7 +101,9 @@
|
|||
orchestra/orchestra {:mvn/version "2021.01.01-1"}
|
||||
expound/expound {:mvn/version "0.8.10"}
|
||||
integrant/integrant {:mvn/version "0.8.0"}
|
||||
com.stuartsierra/dependency {:mvn/version "1.0.0"}}
|
||||
com.stuartsierra/dependency {:mvn/version "1.0.0"}
|
||||
listora/again {:mvn/version "1.0.0"}
|
||||
org.clojure/tools.gitlibs {:mvn/version "2.4.172"}}
|
||||
:classpath-overrides {org.clojure/clojure nil
|
||||
org.clojure/spec.alpha nil}}
|
||||
:clj-nvd
|
||||
|
|
|
|||
|
|
@ -81,12 +81,19 @@ Test the native version:
|
|||
## Tests for Libraries
|
||||
|
||||
Babashka runs tests of libraries that are compatible with it through
|
||||
`script/run_lib_tests`. To add tests for a new library, do the following:
|
||||
`script/run_lib_tests`. To add tests for a new library that has a git repository
|
||||
and run them, use the script `add-libtest.clj` e.g. `script/add-libtest.clj
|
||||
'{listora/again {:mvn/version "1.0.0"}}' https://github.com/liwp/again --test`.
|
||||
|
||||
If the library you want to add doesn't work with the script, you can manually do the following:
|
||||
|
||||
* Add an entry for the library in `deps.edn` under the `:lib-tests` alias.
|
||||
* Create a directory for the library in `test-resources/lib_tests/` and copy its tests to there.
|
||||
* Add an entry in `run_all_libtests.clj` to run the added test namespaces.
|
||||
* Run the tests `script/lib_tests/run_all_libtests NS1 NS2`
|
||||
|
||||
Note: If you have to modify a test to have it work with bb, add an inline
|
||||
comment with prefix "TEST-FIX:" explaining what you did.
|
||||
|
||||
## Build
|
||||
|
||||
|
|
|
|||
86
script/add-libtest.clj
Executable file
86
script/add-libtest.clj
Executable file
|
|
@ -0,0 +1,86 @@
|
|||
#!/usr/bin/env bb
|
||||
;; Adds a library to bb-tested-libs.edn to be tested given a library version and
|
||||
;; git repository. Optionally takes a --test to then test the added library.
|
||||
|
||||
(ns add-libtest
|
||||
(:require [babashka.deps :as deps]
|
||||
[babashka.fs :as fs]
|
||||
[babashka.tasks :refer [shell]]
|
||||
[clojure.string :as str]
|
||||
[clojure.edn :as edn]))
|
||||
|
||||
(deps/add-deps '{:deps {org.clojure/tools.gitlibs {:mvn/version "2.4.172"}
|
||||
borkdude/rewrite-edn {:mvn/version "0.1.0"}}})
|
||||
|
||||
(require '[clojure.tools.gitlibs :as gl])
|
||||
(require '[borkdude.rewrite-edn :as r])
|
||||
|
||||
(defn- add-lib-to-deps
|
||||
[lib-name lib-coordinate]
|
||||
(let [nodes (-> "deps.edn" slurp r/parse-string)]
|
||||
(spit "deps.edn"
|
||||
(str (r/assoc-in nodes
|
||||
[:aliases :lib-tests :extra-deps (symbol lib-name)]
|
||||
lib-coordinate)))))
|
||||
|
||||
(defn- copy-tests
|
||||
[git-url lib-name]
|
||||
(let [lib-dir (or (gl/procure git-url lib-name "master")
|
||||
(gl/procure git-url lib-name "main"))
|
||||
test-dir (some #(when (fs/exists? (fs/file lib-dir %))
|
||||
(str (fs/file lib-dir %)))
|
||||
;; Search common test dirs
|
||||
["test"
|
||||
;; official clojure repos like https://github.com/clojure/tools.gitlibs
|
||||
"src/test/clojure"])]
|
||||
(shell "cp -R" (str test-dir fs/file-separator) "test-resources/lib_tests/")
|
||||
{:lib-dir lib-dir
|
||||
:test-dir test-dir}))
|
||||
|
||||
(defn- add-lib-to-tested-libs
|
||||
[lib-name git-url {:keys [lib-dir test-dir]}]
|
||||
(let [git-sha (fs/file-name lib-dir)
|
||||
; (str (fs/relativize lib-dir test-dir))
|
||||
relative-test-files (map #(str (fs/relativize test-dir %))
|
||||
(fs/glob test-dir "**/*.{clj,cljc}"))
|
||||
_ (when (empty? relative-test-files)
|
||||
(throw (ex-info "No test files found" {:test-dir test-dir})))
|
||||
namespaces (map #(-> %
|
||||
(str/replace fs/file-separator ".")
|
||||
(str/replace "_" "-")
|
||||
(str/replace-first #"\.clj(c?)$" "")
|
||||
symbol)
|
||||
relative-test-files)
|
||||
lib {:git-sha git-sha
|
||||
:git-url git-url
|
||||
:test-namespaces namespaces}
|
||||
nodes (-> "test-resources/lib_tests/bb-tested-libs.edn" slurp r/parse-string)]
|
||||
(spit "test-resources/lib_tests/bb-tested-libs.edn"
|
||||
(str (r/assoc-in nodes
|
||||
[(symbol lib-name)]
|
||||
lib)))
|
||||
namespaces))
|
||||
|
||||
(defn- run-command
|
||||
[args]
|
||||
(let [[deps-string git-url test-option] args
|
||||
deps-map (edn/read-string deps-string)
|
||||
_ (when (not= 1 (count deps-map))
|
||||
(throw (ex-info "Deps map must have one key" {})))
|
||||
lib-name (ffirst deps-map)
|
||||
lib-coordinate (deps-map lib-name)
|
||||
_ (add-lib-to-deps lib-name lib-coordinate)
|
||||
dirs (copy-tests git-url lib-name)
|
||||
namespaces (add-lib-to-tested-libs lib-name git-url dirs)]
|
||||
(println "Added lib" lib-name "which tests the following namespaces:" namespaces)
|
||||
(when (= "--test" test-option)
|
||||
(apply shell "script/lib_tests/run_all_libtests" namespaces))))
|
||||
|
||||
(defn main
|
||||
[args]
|
||||
(if (< (count args) 2)
|
||||
(println "Usage: bb add-libtest DEPS-MAP GIT-URL [--test]")
|
||||
(run-command args)))
|
||||
|
||||
(when (= *file* (System/getProperty "babashka.file"))
|
||||
(main *command-line-args*))
|
||||
334
test-resources/lib_tests/again/core_test.clj
Normal file
334
test-resources/lib_tests/again/core_test.clj
Normal file
|
|
@ -0,0 +1,334 @@
|
|||
(ns again.core-test
|
||||
(:require [again.core :as a :refer [with-retries]]
|
||||
[clojure.test :refer [is deftest testing]]
|
||||
[clojure.test.check.clojure-test :refer [defspec]]
|
||||
[clojure.test.check.generators :as gen]
|
||||
[clojure.test.check.properties :as prop]))
|
||||
|
||||
(defspec spec-max-retries
|
||||
200
|
||||
(prop/for-all
|
||||
[n gen/s-pos-int]
|
||||
(let [s (a/max-retries n (repeat 0))]
|
||||
(= (count s) n))))
|
||||
|
||||
(defspec spec-clamp-delay
|
||||
200
|
||||
(prop/for-all
|
||||
[n gen/s-pos-int
|
||||
max-delay gen/s-pos-int]
|
||||
(let [s (a/max-retries
|
||||
n
|
||||
;; The increment is picked so that we'll cross max-delay on delay 3
|
||||
(a/clamp-delay max-delay (a/additive-strategy 0 (/ max-delay 2))))]
|
||||
(every? #(<= % max-delay) s))))
|
||||
|
||||
(defspec spec-max-delay
|
||||
200
|
||||
(prop/for-all
|
||||
[n gen/s-pos-int
|
||||
max-delay gen/s-pos-int]
|
||||
(let [s (a/max-retries
|
||||
n
|
||||
(a/max-delay max-delay (a/additive-strategy 0 (/ max-delay 10))))]
|
||||
(and (= (count s) (min n 10))
|
||||
(every? #(<= % max-delay) s)))))
|
||||
|
||||
(defspec spec-max-duration
|
||||
200
|
||||
(prop/for-all
|
||||
[d gen/s-pos-int]
|
||||
(let [s (take (* 2 d) (a/max-duration d (a/constant-strategy 1)))]
|
||||
(and (= (count s) d)
|
||||
(= (reduce + s) d)))))
|
||||
|
||||
(deftest test-max-duration
|
||||
(testing "with not enough delays to satisfy specified duration"
|
||||
(is (= (a/max-duration 10000 [0]) [0]))))
|
||||
|
||||
(defspec spec-constant-strategy
|
||||
200
|
||||
(prop/for-all
|
||||
[n gen/s-pos-int
|
||||
delay gen/pos-int]
|
||||
(let [s (a/max-retries n (a/constant-strategy delay))]
|
||||
(and (= (count s) n)
|
||||
(= (set s) #{delay})))))
|
||||
|
||||
(defspec spec-immediate-strategy
|
||||
200
|
||||
(prop/for-all
|
||||
[n gen/s-pos-int]
|
||||
(let [s (a/max-retries n (a/immediate-strategy))]
|
||||
(and (= (count s) n)
|
||||
(= (set s) #{0})))))
|
||||
|
||||
(defspec spec-additive-strategy
|
||||
200
|
||||
(prop/for-all
|
||||
[n gen/s-pos-int
|
||||
initial-delay gen/pos-int
|
||||
increment gen/pos-int]
|
||||
(let [s (a/max-retries n (a/additive-strategy initial-delay increment))
|
||||
p (fn [[a b]] (= (+ a increment) b))]
|
||||
(and (= (count s) n)
|
||||
(= (first s) initial-delay)
|
||||
(every? p (partition 2 1 s))))))
|
||||
|
||||
(defspec spec-multiplicative-strategy
|
||||
200
|
||||
(prop/for-all
|
||||
[n gen/s-pos-int
|
||||
initial-delay gen/s-pos-int
|
||||
delay-multiplier (gen/elements [1.0 1.1 1.3 1.6 2.0 3.0 5.0 9.0 14.0 20.0])]
|
||||
(let [s (a/max-retries
|
||||
n
|
||||
(a/multiplicative-strategy initial-delay delay-multiplier))
|
||||
p (fn [[a b]] (= (* a delay-multiplier) b))]
|
||||
(and (= (count s) n)
|
||||
(= (first s) initial-delay)
|
||||
(every? p (partition 2 1 s))))))
|
||||
|
||||
(defspec spec-randomize-delay
|
||||
200
|
||||
(prop/for-all
|
||||
[rand-factor (gen/elements [0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9])
|
||||
delay gen/s-pos-int]
|
||||
(let [randomize-delay #'again.core/randomize-delay
|
||||
min-delay (bigint (* delay (- 1 rand-factor)))
|
||||
max-delay (bigint (inc (* delay (+ 1 rand-factor))))
|
||||
rand-delay (randomize-delay rand-factor delay)]
|
||||
(and (<= 0 rand-delay)
|
||||
(<= min-delay rand-delay max-delay)))))
|
||||
|
||||
(defspec spec-randomize-strategy
|
||||
200
|
||||
(prop/for-all
|
||||
[n gen/s-pos-int
|
||||
rand-factor (gen/elements [0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9])]
|
||||
(let [initial-delay 1000
|
||||
s (a/max-retries
|
||||
n
|
||||
(a/randomize-strategy
|
||||
rand-factor
|
||||
(a/constant-strategy initial-delay)))
|
||||
min-delay (bigint (* initial-delay (- 1 rand-factor)))
|
||||
max-delay (bigint (inc (* initial-delay (+ 1 rand-factor))))]
|
||||
(every? #(<= min-delay % max-delay) s))))
|
||||
|
||||
(deftest test-stop-strategy
|
||||
(is (empty? (a/stop-strategy)) "stop strategy has no delays"))
|
||||
|
||||
(defn new-failing-fn
|
||||
"Returns a map consisting of the following fields:
|
||||
- `f` - a function that will succeed on the `n`th call
|
||||
- `attempts` - an atom counting the number of executions of `f`
|
||||
- `exception` - the exception that `f` throws until it succeeds"
|
||||
[& [n]]
|
||||
(let [n (or n Integer/MAX_VALUE)
|
||||
attempts (atom 0)
|
||||
exception (Exception. "retry")
|
||||
f #(let [i (swap! attempts inc)]
|
||||
(if (< i n)
|
||||
(throw exception)
|
||||
i))]
|
||||
{:attempts attempts :exception exception :f f}))
|
||||
|
||||
(defn new-callback-fn
|
||||
"Returns a map consisting of the following fields:
|
||||
- `callback` - a callback function to pass to `with-retries` that will fail
|
||||
the operation early after the `n`th call
|
||||
- `args` - an atom recording the arguments passed to `callback`"
|
||||
[& [n]]
|
||||
(let [n (or n Integer/MAX_VALUE)
|
||||
attempts (atom 0)
|
||||
args (atom [])
|
||||
callback #(let [i (swap! attempts inc)]
|
||||
(swap! args conj %)
|
||||
(when (< n i)
|
||||
::a/fail))]
|
||||
{:args args :callback callback}))
|
||||
|
||||
(defspec spec-with-retries
|
||||
200
|
||||
(prop/for-all
|
||||
[strategy (gen/vector gen/s-pos-int)]
|
||||
(let [{:keys [attempts f]} (new-failing-fn)
|
||||
delays (atom [])]
|
||||
(with-redefs [a/sleep #(swap! delays conj %)]
|
||||
(try
|
||||
(with-retries strategy (f))
|
||||
(catch Exception _)))
|
||||
|
||||
(and (= @attempts (inc (count strategy)))
|
||||
(= @delays strategy)))))
|
||||
|
||||
(deftest test-with-retries
|
||||
(with-redefs [a/sleep (constantly nil)]
|
||||
(testing "with-retries"
|
||||
(testing "with non-nil return value"
|
||||
(is (= (with-retries [] :ok) :ok) "returns form value"))
|
||||
|
||||
(testing "with nil return value"
|
||||
(is (nil? (with-retries [] nil)) "returns form value"))
|
||||
|
||||
(testing "with user-context"
|
||||
(let [context {:a :b}
|
||||
{:keys [args callback]} (new-callback-fn)
|
||||
options {::a/callback callback
|
||||
::a/strategy []
|
||||
::a/user-context context}
|
||||
_ (with-retries options :ok)]
|
||||
(is (= (count @args) 1) "calls callback hook once")
|
||||
(is (= (::a/user-context (first @args)) context)
|
||||
"calls callback hook with user context")))
|
||||
|
||||
(testing "with success on first try"
|
||||
(let [{:keys [attempts f]} (new-failing-fn 1)
|
||||
{:keys [args callback]} (new-callback-fn)]
|
||||
(with-retries
|
||||
{::a/callback callback
|
||||
::a/strategy []}
|
||||
(f))
|
||||
(is (= @attempts 1) "executes operation once")
|
||||
(is (= (count @args) 1) "calls callback hook once")
|
||||
(is (= (first @args)
|
||||
{::a/attempts 1
|
||||
::a/slept 0
|
||||
::a/status :success})
|
||||
"calls callback hook with success")))
|
||||
|
||||
(testing "with success on second try"
|
||||
(let [{:keys [attempts exception f]} (new-failing-fn 2)
|
||||
{:keys [args callback]} (new-callback-fn)]
|
||||
(with-retries
|
||||
{::a/callback callback
|
||||
::a/strategy [12]}
|
||||
(f))
|
||||
(is (= @attempts 2) "executes operation twice")
|
||||
(is (= (count @args) 2) "calls callback hook twice")
|
||||
(is (= (first @args)
|
||||
{::a/attempts 1
|
||||
::a/exception exception
|
||||
::a/slept 0
|
||||
::a/status :retry})
|
||||
"calls callback hook with failure")
|
||||
(is (= (second @args)
|
||||
{::a/attempts 2
|
||||
::a/slept 12
|
||||
::a/status :success})
|
||||
"calls callback hook with success")))
|
||||
|
||||
(testing "with permanent failure"
|
||||
(let [{:keys [exception f]} (new-failing-fn)
|
||||
{:keys [args callback]} (new-callback-fn)]
|
||||
(is (thrown?
|
||||
Exception
|
||||
(with-retries
|
||||
{::a/callback callback
|
||||
::a/strategy [123]}
|
||||
(f)))
|
||||
"throws exception")
|
||||
|
||||
(is (= (count @args) 2) "calls callback hook twice")
|
||||
(is (= (first @args)
|
||||
{::a/attempts 1
|
||||
::a/exception exception
|
||||
::a/slept 0
|
||||
::a/status :retry})
|
||||
"calls callback hook with failure")
|
||||
(is (= (second @args)
|
||||
{::a/attempts 2
|
||||
::a/exception exception
|
||||
::a/slept 123
|
||||
::a/status :failure})
|
||||
"calls callback hook with permanent failure")))
|
||||
|
||||
(testing "with early failure"
|
||||
(let [{:keys [exception f]} (new-failing-fn)
|
||||
{:keys [args callback]} (new-callback-fn 1)]
|
||||
(is (thrown?
|
||||
Exception
|
||||
(with-retries
|
||||
{::a/callback callback
|
||||
::a/strategy [1 2 3]}
|
||||
(f)))
|
||||
"throws exception")
|
||||
|
||||
(is (= (count @args) 2) "calls callback hook three twice")
|
||||
(is (= (first @args)
|
||||
{::a/attempts 1
|
||||
::a/exception exception
|
||||
::a/slept 0
|
||||
::a/status :retry})
|
||||
"first callback call")
|
||||
(is (= (second @args)
|
||||
{::a/attempts 2
|
||||
::a/exception exception
|
||||
::a/slept 1
|
||||
::a/status :retry})
|
||||
"last callback call"))))))
|
||||
|
||||
(defmulti log-attempt ::a/status)
|
||||
|
||||
(defmethod log-attempt :retry [s]
|
||||
(if (< (count @(::a/user-context s)) 1)
|
||||
(swap! (::a/user-context s) conj :retry)
|
||||
(do
|
||||
(swap! (::a/user-context s) conj :fail)
|
||||
::a/fail)))
|
||||
|
||||
(defmethod log-attempt :success [s]
|
||||
(swap! (::a/user-context s) conj :success))
|
||||
|
||||
(defmethod log-attempt :failure [s]
|
||||
(swap! (::a/user-context s) conj :failure))
|
||||
|
||||
(defmethod log-attempt :default [s] (assert false))
|
||||
|
||||
(deftest test-multimethod-callback
|
||||
(with-redefs [a/sleep (constantly nil)]
|
||||
(testing "multi-method-callback"
|
||||
(testing "with success"
|
||||
(let [{:keys [f]} (new-failing-fn 2)
|
||||
user-context (atom [])]
|
||||
(with-retries
|
||||
{::a/callback log-attempt
|
||||
::a/strategy [1 2]
|
||||
::a/user-context user-context}
|
||||
(f))
|
||||
(is (= (count @user-context) 2) "multimethod is called twice")
|
||||
(is (= (first @user-context) :retry) "first call is a retry")
|
||||
(is (= (second @user-context) :success) "second call is a success")))
|
||||
|
||||
(testing "with failure"
|
||||
(let [{:keys [exception f]} (new-failing-fn)
|
||||
user-context (atom [])]
|
||||
(try
|
||||
(with-retries
|
||||
{::a/callback log-attempt
|
||||
::a/strategy [1]
|
||||
::a/user-context user-context}
|
||||
(f))
|
||||
(catch Exception e
|
||||
(is (= e exception) "Unexpected exception")))
|
||||
(is (= (count @user-context) 2) "multimethod is called twice")
|
||||
(is (= (first @user-context) :retry) "first call is a retry")
|
||||
(is (= (second @user-context) :failure) "second call is a failure")))
|
||||
|
||||
(testing "with early failure"
|
||||
(let [{:keys [exception f]} (new-failing-fn)
|
||||
user-context (atom [])]
|
||||
(try
|
||||
(with-retries
|
||||
{::a/callback log-attempt
|
||||
::a/strategy [1 2]
|
||||
::a/user-context user-context}
|
||||
(f))
|
||||
(catch Exception e
|
||||
(is (= e exception) "Unexpected exception")))
|
||||
(is (= (count @user-context) 2) "multimethod is called three times")
|
||||
(is (= (first @user-context) :retry) "first call is a retry")
|
||||
(is (= (second @user-context) :fail) "second call is a fail"))))))
|
||||
|
||||
|
||||
82
test-resources/lib_tests/arrangement/core_test.cljc
Normal file
82
test-resources/lib_tests/arrangement/core_test.cljc
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
(ns arrangement.core-test
|
||||
(:require
|
||||
[arrangement.core :as order]
|
||||
[clojure.test :refer [deftest is]]))
|
||||
|
||||
|
||||
(defn- is-sorted
|
||||
[& values]
|
||||
(dotimes [_ 10]
|
||||
(is (= values (sort order/rank (shuffle values))))))
|
||||
|
||||
|
||||
(deftest primitive-ordering
|
||||
(is-sorted
|
||||
nil false true 0 \a "a" :a 'a))
|
||||
|
||||
|
||||
(deftest number-ordering
|
||||
(is-sorted
|
||||
-123 0.0 3.14159M #?(:clj 37/8) 4096N))
|
||||
|
||||
|
||||
(deftest string-ordering
|
||||
(is-sorted
|
||||
"alpha" "alphabet" "beta" "omega"))
|
||||
|
||||
|
||||
(deftest keyword-ordering
|
||||
(is-sorted
|
||||
:foo :zap :a-ns/baz :my-ns/bar))
|
||||
|
||||
|
||||
(deftest symbol-ordering
|
||||
(is-sorted
|
||||
'x 'y 'aaa/foo 'z/bar))
|
||||
|
||||
|
||||
(deftest sequence-ordering
|
||||
(is-sorted
|
||||
'(1 2 3)
|
||||
[1 2 3]
|
||||
[1 2 3 4]
|
||||
[1 2 4]
|
||||
[1 \2 "3"]
|
||||
[\1]))
|
||||
|
||||
|
||||
(deftest set-ordering
|
||||
(is-sorted
|
||||
#{:one}
|
||||
#{:two}
|
||||
#{:zzz}
|
||||
#{:one :two}
|
||||
#{:one :zzz}
|
||||
#{:a :e :f}
|
||||
#{:b :c :d}))
|
||||
|
||||
|
||||
(deftest map-ordering
|
||||
(is-sorted
|
||||
{:a 1}
|
||||
{:a 2}
|
||||
{:b 1})
|
||||
(is-sorted
|
||||
{:x 1}
|
||||
{:a 1, :q 2}
|
||||
{:a 1, :b 2, :c 3})
|
||||
(is-sorted
|
||||
{:a 1, :b 2}
|
||||
{:a 1, :b :*}
|
||||
{:x 1, :y 2}
|
||||
{:a 1, :b 8.0, :c 'x}))
|
||||
|
||||
|
||||
#?(:clj
|
||||
(deftest class-ordering
|
||||
(is-sorted
|
||||
;; TEST-FIX: bb doesn't have java.util.Currency/getInstance
|
||||
#_(java.util.Currency/getInstance "JPY")
|
||||
#_(java.util.Currency/getInstance "USD")
|
||||
(java.util.Date. 1234567890)
|
||||
(java.util.Date. 1234567891))))
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
(ns babashka.run-all-libtests
|
||||
(:require [clojure.java.io :as io]
|
||||
[clojure.string :as str]
|
||||
[clojure.edn :as edn]
|
||||
[clojure.test :as t]))
|
||||
|
||||
#_(require 'clojure.spec.alpha)
|
||||
|
|
@ -13,17 +14,14 @@
|
|||
(or (empty? ns-args)
|
||||
(contains? ns-args ns)))
|
||||
|
||||
(defmacro test-namespaces [& namespaces]
|
||||
(let [namespaces (map second namespaces)
|
||||
namespaces (seq (filter test-namespace? namespaces))
|
||||
quoted-namespaces (map #(list 'quote %) namespaces)
|
||||
requires (map #(list 'require %) quoted-namespaces)]
|
||||
(when (seq requires)
|
||||
`(do
|
||||
~@requires
|
||||
(let [m# (t/run-tests ~@quoted-namespaces)]
|
||||
(swap! status (fn [status#]
|
||||
(merge-with + status# (dissoc m# :type)))))))))
|
||||
(defn test-namespaces [& namespaces]
|
||||
(let [namespaces (seq (filter test-namespace? namespaces))]
|
||||
(when (seq namespaces)
|
||||
(doseq [n namespaces]
|
||||
(require n))
|
||||
(let [m (apply t/run-tests namespaces)]
|
||||
(swap! status (fn [status]
|
||||
(merge-with + status (dissoc m :type))))))))
|
||||
|
||||
(def windows? (-> (System/getProperty "os.name")
|
||||
(str/lower-case)
|
||||
|
|
@ -61,41 +59,13 @@
|
|||
(require '[cprop.source :refer [from-env]])
|
||||
(println (:cprop-env (from-env)))
|
||||
|
||||
;;;; comb
|
||||
|
||||
;; TODO: port to test-namespaces
|
||||
|
||||
(require '[comb.template :as template])
|
||||
(prn (template/eval "<% (dotimes [x 3] %>foo<% ) %>"))
|
||||
(prn (template/eval "Hello <%= name %>" {:name "Alice"}))
|
||||
(def hello
|
||||
(template/fn [name] "Hello <%= name %>"))
|
||||
(prn (hello "Alice"))
|
||||
|
||||
;;;; arrangement
|
||||
|
||||
;; TODO: port to test-namespaces
|
||||
|
||||
(require '[arrangement.core :as order])
|
||||
(prn (sort order/rank ['a false 2 :b nil 3.14159
|
||||
"c" true \d [3 2] #{:one :two}
|
||||
[3 1 2] #{:three}]))
|
||||
|
||||
;;;; clj-yaml
|
||||
|
||||
(test-namespaces 'clj-yaml.core-test)
|
||||
|
||||
;;;; clojure-csv
|
||||
|
||||
;; TODO: port to test-namespaces
|
||||
|
||||
(require '[clojure-csv.core :as csv])
|
||||
;; TODO: convert to test
|
||||
(prn (csv/write-csv (csv/parse-csv "a,b,c\n1,2,3")))
|
||||
|
||||
;;;; clojure.data.zip
|
||||
|
||||
;; TODO: port to test-namespaces
|
||||
;; TODO: port to test-namespaces. Blocked until clojure.xml is supported
|
||||
|
||||
(require '[clojure.data.xml :as xml])
|
||||
(require '[clojure.zip :as zip])
|
||||
|
|
@ -276,6 +246,10 @@
|
|||
|
||||
(test-namespaces 'com.stuartsierra.dependency-test)
|
||||
|
||||
(let [lib-tests (edn/read-string (slurp (io/resource "bb-tested-libs.edn")))]
|
||||
(doseq [{tns :test-namespaces} (vals lib-tests)]
|
||||
(apply test-namespaces tns)))
|
||||
|
||||
;;;; final exit code
|
||||
|
||||
(let [{:keys [:test :fail :error] :as m} @status]
|
||||
|
|
|
|||
8
test-resources/lib_tests/bb-tested-libs.edn
Normal file
8
test-resources/lib_tests/bb-tested-libs.edn
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
;; These libraries are tested against babashka and have been added by
|
||||
;; script/add-libtest.clj
|
||||
{listora/again
|
||||
{:git-sha "b1a6793f0deaa3cc016eee7626097ba8bf36ba10", :git-url "https://github.com/liwp/again", :test-namespaces (again.core-test)}
|
||||
org.clojure/tools.gitlibs {:git-sha "9f98af7631e34983d5b0886e1ab6eadc3856290b", :git-url "https://github.com/clojure/tools.gitlibs", :test-namespaces (clojure.tools.test-gitlibs clojure.tools.gitlibs.test-impl)}
|
||||
comb/comb {:git-sha "625a63a9c040fa4a2b3153d8c84d08dc2fc8f660", :git-url "https://github.com/weavejester/comb", :test-namespaces (comb.test.template)}
|
||||
mvxcvi/arrangement {:git-sha "360d29e7ae81abbf986b5a8e272f2086227d038d", :git-url "https://github.com/greglook/clj-arrangement", :test-namespaces (arrangement.core-test)}
|
||||
clojure-csv/clojure-csv {:git-sha "b6bb882a3a9ac1f82e06eb2262ae7c8141935228", :git-url "https://github.com/davidsantiago/clojure-csv", :test-namespaces (clojure-csv.test.utils clojure-csv.test.core)}}
|
||||
36
test-resources/lib_tests/clojure/tools/gitlibs/test_impl.clj
Normal file
36
test-resources/lib_tests/clojure/tools/gitlibs/test_impl.clj
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
(ns clojure.tools.gitlibs.test-impl
|
||||
(:require
|
||||
[clojure.test :refer :all]
|
||||
[clojure.tools.gitlibs.impl :as impl]))
|
||||
|
||||
(deftest test-clean-url
|
||||
(are [url expected-path]
|
||||
(= expected-path (#'impl/clean-url url))
|
||||
|
||||
;; url formats - don't use user or port
|
||||
"ssh://git@gitlab.com:3333/org/repo.git" "ssh/gitlab.com/org/repo"
|
||||
"ssh://git@gitlab.org.net/org/repo.git" "ssh/gitlab.org.net/org/repo"
|
||||
"ssh://user@host.xz/~user/repo.git/" "ssh/host.xz/_TILDE_user/repo"
|
||||
"https://github.com/org/repo.git" "https/github.com/org/repo"
|
||||
"git://host.xz/path/to/repo.git/" "git/host.xz/path/to/repo"
|
||||
|
||||
;; scp style url (most common github ssh url format)
|
||||
"git@github.com:org/repo.git" "ssh/github.com/org/repo"
|
||||
"git@github.com:dotted.org/dotted.repo.git" "ssh/github.com/dotted.org/dotted.repo"
|
||||
"host.xz:~user/path/to/repo.git/" "ssh/host.xz/_TILDE_user/path/to/repo"
|
||||
|
||||
;; file scheme
|
||||
"file:///Users/me/code/repo.git" "file/Users/me/code/repo"
|
||||
"file://../foo.git" "file/REL/_DOTDOT_/foo"
|
||||
"file://~/path/repo.git" "file/REL/_TILDE_/path/repo"
|
||||
|
||||
;; file repos - handle relative vs absolute, handle . .. ~
|
||||
"/Users/me/code/repo.git" "file/Users/me/code/repo"
|
||||
"../foo.git" "file/REL/_DOTDOT_/foo"
|
||||
"./foo.git" "file/REL/_DOT_/foo"
|
||||
"~user/foo.git" "file/REL/_TILDE_user/foo"
|
||||
|
||||
;; git - unknown transport with url rewrite in gitconfig (unusual, but do something useful)
|
||||
"work:repo.git" "ssh/work/repo"))
|
||||
|
||||
|
||||
48
test-resources/lib_tests/clojure/tools/test_gitlibs.clj
Normal file
48
test-resources/lib_tests/clojure/tools/test_gitlibs.clj
Normal file
|
|
@ -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.
|
||||
|
||||
(ns clojure.tools.test-gitlibs
|
||||
(:require
|
||||
[clojure.java.io :as jio]
|
||||
[clojure.test :refer :all]
|
||||
[clojure.tools.gitlibs :as gl]))
|
||||
|
||||
(def repo-url "https://github.com/clojure/spec.alpha.git")
|
||||
|
||||
(deftest test-resolve
|
||||
(is (= (gl/resolve repo-url "739c1af5")
|
||||
"739c1af56dae621aedf1bb282025a0d676eff713")))
|
||||
|
||||
(deftest test-procure
|
||||
(let [wt1 (gl/procure repo-url 'org.clojure/spec.alpha "739c1af")
|
||||
wt2 (gl/procure repo-url 'org.clojure/spec.alpha "6a56327")]
|
||||
(is (.exists (jio/file (gl/cache-dir) "_repos" "https" "github.com" "clojure" "spec.alpha")))
|
||||
(is (= wt1 (.getAbsolutePath (jio/file (gl/cache-dir) "libs" "org.clojure" "spec.alpha" "739c1af56dae621aedf1bb282025a0d676eff713"))))
|
||||
(is (= wt2 (.getAbsolutePath (jio/file (gl/cache-dir) "libs" "org.clojure" "spec.alpha" "6a56327446c909db0d11ecf93a3c3d659b739be9"))))))
|
||||
|
||||
(deftest test-descendant-fixed
|
||||
(is (= (gl/descendant repo-url ["607aef0" "739c1af"])
|
||||
"739c1af56dae621aedf1bb282025a0d676eff713"))
|
||||
(is (= (gl/descendant repo-url ["739c1af" "607aef0"])
|
||||
"739c1af56dae621aedf1bb282025a0d676eff713"))
|
||||
(is (= (gl/descendant repo-url ["607aef0" "607aef0"])
|
||||
"607aef0643f6cf920293130d45e6160d93fda908"))
|
||||
|
||||
(is (nil? (gl/descendant repo-url nil)))
|
||||
(is (nil? (gl/descendant repo-url [])))
|
||||
(is (nil? (gl/descendant repo-url ["abcdef" "123456"]))))
|
||||
|
||||
(deftest test-descendant-combos
|
||||
(let [m (gl/resolve repo-url "master")
|
||||
m' (gl/resolve repo-url "master~1")
|
||||
m'' (gl/resolve repo-url "master~2")]
|
||||
(are [rs d] (= d (gl/descendant repo-url rs))
|
||||
[m] m
|
||||
[m m''] m
|
||||
[m' m''] m'
|
||||
[m'' m' m] m)))
|
||||
132
test-resources/lib_tests/clojure_csv/test/core.clj
Normal file
132
test-resources/lib_tests/clojure_csv/test/core.clj
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
(ns clojure-csv.test.core
|
||||
(:import [java.io StringReader])
|
||||
(:use clojure.test
|
||||
clojure.java.io
|
||||
clojure-csv.core))
|
||||
|
||||
(deftest basic-functionality
|
||||
(is (= [["a" "b" "c"]] (parse-csv "a,b,c")))
|
||||
(is (= [["" ""]] (parse-csv ",")))
|
||||
(is (= [["a" "b"]] (parse-csv "a,b\r\n"))) ;; Linebreak on eof won't add line.
|
||||
(is (= [] (parse-csv ""))))
|
||||
|
||||
(deftest alternate-sources
|
||||
(is (= [["a" "b" "c"]] (parse-csv (StringReader. "a,b,c"))))
|
||||
(is (= [["" ""]] (parse-csv (StringReader. ","))))
|
||||
(is (= [] (parse-csv (StringReader. ""))))
|
||||
(is (= [["First", "Second"]] (parse-csv
|
||||
(reader (.toCharArray "First,Second"))))))
|
||||
|
||||
(deftest quoting
|
||||
(is (= [[""]] (parse-csv "\"")))
|
||||
(is (= [["\""]] (parse-csv "\"\"\"")))
|
||||
(is (= [["Before", "\"","After"]] (parse-csv "Before,\"\"\"\",After")))
|
||||
(is (= [["Before", "", "After"]] (parse-csv "Before,\"\",After")))
|
||||
(is (= [["", "start&end", ""]] (parse-csv "\"\",\"start&end\",\"\"")))
|
||||
(is (= [[",", "\"", ",,", ",,,"]]
|
||||
(parse-csv "\",\",\"\"\"\",\",,\",\",,,\"")))
|
||||
(is (= [["quoted", "\",\"", "comma"]]
|
||||
(parse-csv "quoted,\"\"\",\"\"\",comma")))
|
||||
(is (= [["Hello"]] (parse-csv "\"Hello\"")))
|
||||
(is (thrown? Exception (dorun (parse-csv "\"Hello\" \"Hello2\""))))
|
||||
(is (thrown? Exception (dorun (parse-csv "\"Hello\" \"Hello2\" \"Hello3\""))))
|
||||
(is (thrown? Exception (dorun (parse-csv "\"Hello\",\"Hello2\" \"Hello3\""))))
|
||||
(is (= [["Hello\"Hello2"]] (parse-csv "\"Hello\"\"Hello2\"")))
|
||||
(is (thrown? Exception (dorun (parse-csv "\"Hello\"Hello2"))))
|
||||
(is (= [["Hello"]] (parse-csv "\"Hello"))))
|
||||
|
||||
(deftest newlines
|
||||
(is (= [["test1","test2"] ["test3","test4"]]
|
||||
(parse-csv "test1,test2\ntest3,test4")))
|
||||
(is (= [["test1","test2"] ["test3","test4"]]
|
||||
(parse-csv "test1,test2\r\ntest3,test4")))
|
||||
(is (= [["embedded","line\nbreak"]] (parse-csv "embedded,\"line\nbreak\"")))
|
||||
(is (= [["embedded", "line\r\nbreak"]]
|
||||
(parse-csv "embedded,\"line\r\nbreak\""))))
|
||||
|
||||
(deftest writing
|
||||
(is (= "test1,test2\n" (write-csv [["test1" "test2"]])))
|
||||
(is (= "test1,test2\ntest3,test4\n"
|
||||
(write-csv [["test1" "test2"] ["test3" "test4"]])))
|
||||
(is (= "quoted:,\"line\nfeed\"\n"
|
||||
(write-csv [["quoted:" "line\nfeed"]])))
|
||||
(is (= "quoted:,\"carriage\rreturn\"\n"
|
||||
(write-csv [["quoted:" "carriage\rreturn"]])))
|
||||
(is (= "quoted:,\"embedded,comma\"\n"
|
||||
(write-csv [["quoted:" "embedded,comma"]])))
|
||||
(is (= "quoted:,\"escaped\"\"quotes\"\"\"\n"
|
||||
(write-csv [["quoted:" "escaped\"quotes\""]]))))
|
||||
|
||||
(deftest force-quote-on-output
|
||||
(is (= "test1,test2\n" (write-csv [["test1" "test2"]])))
|
||||
(is (= "test1,test2\n" (write-csv [["test1" "test2"]] :force-quote false)))
|
||||
(is (= "\"test1\",\"test2\"\n" (write-csv [["test1" "test2"]]
|
||||
:force-quote true)))
|
||||
(is (= "stillquoted:,\"needs,quote\"\n"
|
||||
(write-csv [["stillquoted:" "needs,quote"]]
|
||||
:force-quote false)))
|
||||
(is (= "\"allquoted:\",\"needs,quote\"\n"
|
||||
(write-csv [["allquoted:" "needs,quote"]]
|
||||
:force-quote true))))
|
||||
|
||||
(deftest alternate-delimiters
|
||||
(is (= [["First", "Second"]]
|
||||
(parse-csv "First\tSecond" :delimiter \tab)))
|
||||
(is (= "First\tSecond\n"
|
||||
(write-csv [["First", "Second"]] :delimiter \tab)))
|
||||
(is (= "First\tSecond,Third\n"
|
||||
(write-csv [["First", "Second,Third"]] :delimiter \tab)))
|
||||
(is (= "First\t\"Second\tThird\"\n"
|
||||
(write-csv [["First", "Second\tThird"]] :delimiter \tab))))
|
||||
|
||||
(deftest alternate-quote-char
|
||||
(is (= [["a", "b", "c"]]
|
||||
(parse-csv "a,|b|,c" :quote-char \|)))
|
||||
(is (= [["a", "b|c", "d"]]
|
||||
(parse-csv "a,|b||c|,d" :quote-char \|)))
|
||||
(is (= [["a", "b\"\nc", "d"]]
|
||||
(parse-csv "a,|b\"\nc|,d" :quote-char \|)))
|
||||
(is (= "a,|b||c|,d\n"
|
||||
(write-csv [["a", "b|c", "d"]] :quote-char \|)))
|
||||
(is (= "a,|b\nc|,d\n"
|
||||
(write-csv [["a", "b\nc", "d"]] :quote-char \|)))
|
||||
(is (= "a,b\"c,d\n"
|
||||
(write-csv [["a", "b\"c", "d"]] :quote-char \|))))
|
||||
|
||||
(deftest strictness
|
||||
(is (thrown? Exception (dorun (parse-csv "a,b,c,\"d" :strict true))))
|
||||
(is (thrown? Exception (dorun (parse-csv "a,b,c,d\"e" :strict true))))
|
||||
(is (= [["a","b","c","d"]]
|
||||
(parse-csv "a,b,c,\"d" :strict false)))
|
||||
(is (= [["a","b","c","d"]]
|
||||
(parse-csv "a,b,c,\"d\"" :strict true)))
|
||||
(is (= [["a","b","c","d\""]]
|
||||
(parse-csv "a,b,c,d\"" :strict false)))
|
||||
(is (= [["120030" "BLACK COD FILET MET VEL \"MSC\"" "KG" "0" "1"]]
|
||||
(parse-csv "120030;BLACK COD FILET MET VEL \"MSC\";KG;0;1"
|
||||
:strict false :delimiter \;))))
|
||||
|
||||
(deftest reader-cases
|
||||
;; reader will be created and closed in with-open, but used outside.
|
||||
;; this is actually a java.io.IOException, but thrown at runtime so...
|
||||
;; TEST-FIX: bb throws IOException instead of RuntimeException
|
||||
(is (thrown? java.io.IOException
|
||||
(dorun (with-open [sr (StringReader. "a,b,c")]
|
||||
(parse-csv sr))))))
|
||||
|
||||
(deftest custom-eol
|
||||
;; Test the use of this option.
|
||||
(is (= [["a" "b"] ["c" "d"]] (parse-csv "a,b\rc,d" :end-of-line "\r")))
|
||||
(is (= [["a" "b"] ["c" "d"]] (parse-csv "a,babcc,d" :end-of-line "abc")))
|
||||
;; The presence of an end-of-line option turns off the parsing of \n and \r\n
|
||||
;; as EOLs, so they can appear unquoted in fields when they do not interfere
|
||||
;; with the EOL.
|
||||
(is (= [["a" "b\n"] ["c" "d"]] (parse-csv "a,b\n\rc,d" :end-of-line "\r")))
|
||||
(is (= [["a" "b"] ["\nc" "d"]] (parse-csv "a,b\r\nc,d" :end-of-line "\r")))
|
||||
;; Custom EOL can still be quoted into a field.
|
||||
(is (= [["a" "b\r"] ["c" "d"]] (parse-csv "a,\"b\r\"\rc,d"
|
||||
:end-of-line "\r")))
|
||||
(is (= [["a" "bHELLO"] ["c" "d"]] (parse-csv "a,\"bHELLO\"HELLOc,d"
|
||||
:end-of-line "HELLO")))
|
||||
(is (= [["a" "b\r"] ["c" "d"]] (parse-csv "a,|b\r|\rc,d"
|
||||
:end-of-line "\r" :quote-char \|))))
|
||||
112
test-resources/lib_tests/clojure_csv/test/utils.clj
Normal file
112
test-resources/lib_tests/clojure_csv/test/utils.clj
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
(ns clojure-csv.test.utils
|
||||
"Some whitebox testing of the private utility functions used in core."
|
||||
(:import [java.io StringReader])
|
||||
;; TEST-FIX: Had to require since use caused conflict which bb failed on
|
||||
(:require [clojure-csv.core])
|
||||
(:use clojure.test
|
||||
clojure.java.io))
|
||||
|
||||
(def default-options {:delimiter \, :quote-char \"
|
||||
:strict false :end-of-line nil})
|
||||
|
||||
(deftest eol-at-reader-pos?
|
||||
;; Testing the private function to check for EOLs
|
||||
(is (= true (#'clojure-csv.core/eol-at-reader-pos? (StringReader. "\n") nil)))
|
||||
(is (= true (#'clojure-csv.core/eol-at-reader-pos? (StringReader. "\r\n")
|
||||
nil)))
|
||||
(is (= true (#'clojure-csv.core/eol-at-reader-pos? (StringReader. "\nabc")
|
||||
nil)))
|
||||
(is (= true (#'clojure-csv.core/eol-at-reader-pos? (StringReader. "\r\nabc")
|
||||
nil)))
|
||||
(is (= false (#'clojure-csv.core/eol-at-reader-pos? (StringReader. "\r\tabc")
|
||||
nil)))
|
||||
;; Testing for user-specified EOLs
|
||||
(is (= true (#'clojure-csv.core/eol-at-reader-pos? (StringReader. "abc")
|
||||
"abc")))
|
||||
(is (= true (#'clojure-csv.core/eol-at-reader-pos? (StringReader. "abcdef")
|
||||
"abc")))
|
||||
(is (= false (#'clojure-csv.core/eol-at-reader-pos? (StringReader. "ab")
|
||||
"abc"))))
|
||||
|
||||
(deftest skip-past-eol
|
||||
(is (= (int \c)
|
||||
(let [rdr (StringReader. "\nc")]
|
||||
(#'clojure-csv.core/skip-past-eol rdr)
|
||||
(.read rdr))))
|
||||
(is (= (int \c)
|
||||
(let [rdr (StringReader. "\r\nc")]
|
||||
(#'clojure-csv.core/skip-past-eol rdr)
|
||||
(.read rdr))))
|
||||
(is (= (int \c)
|
||||
(let [rdr (StringReader. "QQQc")]
|
||||
(#'clojure-csv.core/skip-past-eol rdr "QQQ")
|
||||
(.read rdr)))))
|
||||
|
||||
(deftest read-unquoted-field
|
||||
(let [{:keys [delimiter quote-char strict end-of-line]} default-options]
|
||||
(is (= "abc" (#'clojure-csv.core/read-unquoted-field
|
||||
(StringReader. "abc,def")
|
||||
delimiter quote-char strict end-of-line)))
|
||||
(is (= "abc" (#'clojure-csv.core/read-unquoted-field
|
||||
(StringReader. "abc")
|
||||
delimiter quote-char strict end-of-line)))
|
||||
(is (= "abc" (#'clojure-csv.core/read-unquoted-field
|
||||
(StringReader. "abc\n")
|
||||
delimiter quote-char strict end-of-line)))
|
||||
(is (= "abc" (#'clojure-csv.core/read-unquoted-field
|
||||
(StringReader. "abc\r\n")
|
||||
delimiter quote-char strict end-of-line)))
|
||||
(is (= "abc" (#'clojure-csv.core/read-unquoted-field
|
||||
(StringReader. "abcQQQ")
|
||||
delimiter quote-char strict "QQQ")))
|
||||
(is (= "abc\n" (#'clojure-csv.core/read-unquoted-field
|
||||
(StringReader. "abc\nQQQ")
|
||||
delimiter quote-char strict "QQQ")))
|
||||
(is (= "abc\"" (#'clojure-csv.core/read-unquoted-field
|
||||
(StringReader. "abc\",")
|
||||
delimiter quote-char strict end-of-line)))
|
||||
(is (= "" (#'clojure-csv.core/read-unquoted-field
|
||||
(StringReader. ",,,")
|
||||
delimiter quote-char strict end-of-line)))
|
||||
(is (thrown? java.lang.Exception
|
||||
(#'clojure-csv.core/read-unquoted-field
|
||||
(StringReader. "abc\",")
|
||||
delimiter quote-char true end-of-line)))))
|
||||
|
||||
(deftest escaped-quote-at-reader-pos?
|
||||
(is (= true (#'clojure-csv.core/escaped-quote-at-reader-pos?
|
||||
(StringReader. "\"\"")
|
||||
(int \"))))
|
||||
(is (= true (#'clojure-csv.core/escaped-quote-at-reader-pos?
|
||||
(StringReader. "\"\"abc")
|
||||
(int \"))))
|
||||
(is (= false (#'clojure-csv.core/escaped-quote-at-reader-pos?
|
||||
(StringReader. "\"abc")
|
||||
(int \"))))
|
||||
(is (= false (#'clojure-csv.core/escaped-quote-at-reader-pos?
|
||||
(StringReader. "abc")
|
||||
(int \")))))
|
||||
|
||||
(deftest read-quoted-field
|
||||
(let [{:keys [delimiter quote-char strict]} default-options
|
||||
delimiter (int delimiter)
|
||||
quote-char (int quote-char)]
|
||||
(is (= "abc" (#'clojure-csv.core/read-quoted-field
|
||||
(StringReader. "\"abc\"")
|
||||
delimiter quote-char strict)))
|
||||
(is (= "abc" (#'clojure-csv.core/read-quoted-field
|
||||
(StringReader. "\"abc\",def")
|
||||
delimiter quote-char strict)))
|
||||
(is (= "ab\"c" (#'clojure-csv.core/read-quoted-field
|
||||
(StringReader. "\"ab\"\"c\"")
|
||||
delimiter quote-char strict)))
|
||||
(is (= "ab\nc" (#'clojure-csv.core/read-quoted-field
|
||||
(StringReader. "\"ab\nc\"")
|
||||
delimiter quote-char strict)))
|
||||
(is (= "ab,c" (#'clojure-csv.core/read-quoted-field
|
||||
(StringReader. "\"ab,c\"")
|
||||
delimiter quote-char strict)))
|
||||
(is (thrown? java.lang.Exception
|
||||
(#'clojure-csv.core/read-quoted-field
|
||||
(StringReader. "\"abc")
|
||||
delimiter quote-char true)))))
|
||||
15
test-resources/lib_tests/comb/test/template.clj
Normal file
15
test-resources/lib_tests/comb/test/template.clj
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
(ns comb.test.template
|
||||
(:use clojure.test)
|
||||
(:require [comb.template :as t] :reload))
|
||||
|
||||
(deftest eval-test
|
||||
(is (= (t/eval "foo") "foo"))
|
||||
(is (= (t/eval "<%= 10 %>") "10"))
|
||||
(is (= (t/eval "<%= x %>" {:x "foo"}) "foo"))
|
||||
(is (= (t/eval "<%=x%>" {:x "foo"}) "foo"))
|
||||
(is (= (t/eval "<% (doseq [x xs] %>foo<%= x %> <% ) %>" {:xs [1 2 3]})
|
||||
"foo1 foo2 foo3 ")))
|
||||
|
||||
(deftest fn-test
|
||||
(is (= ((t/fn [x] "foo<%= x %>") "bar")
|
||||
"foobar")))
|
||||
Loading…
Reference in a new issue