From 901ea41f202dafa5e58e7625c01581bfb6d9eaf5 Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Tue, 11 Aug 2020 12:07:29 -0400 Subject: [PATCH] Add lib tests for bond (#524) * Add lib-tests for bond * Mention bond and add instructions for adding libtests * Tweak lib test to detect exception that bb throws --- deps.edn | 3 +- doc/dev.md | 10 ++ doc/libraries.md | 12 +- .../lib_tests/babashka/run_all_libtests.clj | 3 + .../lib_tests/bond/test/assertions.cljc | 51 +++++++++ test-resources/lib_tests/bond/test/james.cljc | 108 ++++++++++++++++++ .../lib_tests/bond/test/target.cljc | 32 ++++++ 7 files changed, 214 insertions(+), 5 deletions(-) create mode 100644 test-resources/lib_tests/bond/test/assertions.cljc create mode 100644 test-resources/lib_tests/bond/test/james.cljc create mode 100644 test-resources/lib_tests/bond/test/target.cljc diff --git a/deps.edn b/deps.edn index fe1307cc..3ad86dc3 100644 --- a/deps.edn +++ b/deps.edn @@ -55,4 +55,5 @@ aero/aero {:mvn/version "1.1.6"} org.clojure/data.generators {:mvn/version "1.0.0"} honeysql/honeysql {:mvn/version "1.0.444"} - minimallist/minimallist {:mvn/version "0.0.6"}}}}} + minimallist/minimallist {:mvn/version "0.0.6"} + circleci/bond {:mvn/version "0.4.0"}}}}} \ No newline at end of file diff --git a/doc/dev.md b/doc/dev.md index 50c9dcb5..2a087d91 100644 --- a/doc/dev.md +++ b/doc/dev.md @@ -41,6 +41,16 @@ Test the native version: BABASHKA_TEST_ENV=native script/test +## 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: + +* 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. + + ## Build See [build.md](build.md). diff --git a/doc/libraries.md b/doc/libraries.md index 98d8fc37..d944a7cd 100644 --- a/doc/libraries.md +++ b/doc/libraries.md @@ -195,8 +195,8 @@ $ bb "(use 'doric.core) (println (table [:a :b :c] [{:a 1 :b 2 :c 3} {:a 4 :b 5 ### [clojure.data.zip](https://github.com/clojure/data.zip) -Utilities for clojure.zip, among other things a more fluent way to work -with xml. +Utilities for clojure.zip, among other things a more fluent way to work +with xml. Small sample: ``` clojure @@ -249,6 +249,10 @@ Random data generators Turn Clojure data structures into SQL +### [bond](https://github.com/circleci/bond) + +Spying and stubbing library, primarily intended for tests. + ## Pods [Babashka pods](https://github.com/babashka/babashka.pods) are programs that can @@ -322,7 +326,7 @@ A wee multi-threaded web server ### [covid19-babashka](https://github.com/agrison/covid19-babashka) -A babashka script to obtain covid-19 related information. +A babashka script to obtain covid-19 related information. ### [bb-spotify](https://github.com/kolharsam/bb-spotify) @@ -333,7 +337,7 @@ Contol your spotify player using babashka. [Internal tooling](https://github.com/borkdude/babashka/issues/457#issuecomment-636739415) used by Lambda Island projects. Noteworthy: a [babashka-compatible hiccup -script](https://github.com/lambdaisland/open-source/blob/2cfde3dfb460e72f047bf94e6f5ec7f519c6d7a0/src/lioss/hiccup.clj). +script](https://github.com/lambdaisland/open-source/blob/2cfde3dfb460e72f047bf94e6f5ec7f519c6d7a0/src/lioss/hiccup.clj). There's also [subshell](https://github.com/lambdaisland/open-source/blob/master/src/lioss/subshell.clj) diff --git a/test-resources/lib_tests/babashka/run_all_libtests.clj b/test-resources/lib_tests/babashka/run_all_libtests.clj index fb4d620f..c410abb3 100644 --- a/test-resources/lib_tests/babashka/run_all_libtests.clj +++ b/test-resources/lib_tests/babashka/run_all_libtests.clj @@ -178,6 +178,9 @@ (test-namespaces 'minimallist.core-test) +;;;; bond +(test-namespaces 'bond.test.james) + ;;;; final exit code (let [{:keys [:test :fail :error] :as m} @status] diff --git a/test-resources/lib_tests/bond/test/assertions.cljc b/test-resources/lib_tests/bond/test/assertions.cljc new file mode 100644 index 00000000..f8e48523 --- /dev/null +++ b/test-resources/lib_tests/bond/test/assertions.cljc @@ -0,0 +1,51 @@ +(ns bond.test.assertions + (:require #?(:clj [clojure.test :refer (deftest is testing)]) + [bond.assertions :as assertions] + [bond.james :as bond :include-macros true] + [bond.test.target :as target]) + #?(:cljs (:require-macros [cljs.test :refer (is deftest testing)]))) + +(deftest called?-works + (testing "a spy was called directly" + (bond/with-spy [target/foo] + (let [_ (target/foo 1)] + (is (assertions/called? target/foo))))) + + (testing "a spy was called indirectly" + (bond/with-spy [target/foo] + (let [_ (target/foo-caller 1)] + (is (assertions/called? target/foo))))) + + (testing "a spy was not called" + (bond/with-spy [target/foo] + (is (not (assertions/called? target/foo)))))) + +(deftest called-times?-works + (testing "the number of times a spy was called" + (bond/with-spy [target/foo] + (let [_ (target/foo-caller 1)] + (is (assertions/called-times? target/foo 1 ))) + (let [_ (target/foo 2)] + (is (assertions/called-times? target/foo 2))))) + + (testing "the number of times a spy was not called" + (bond/with-spy [target/foo] + (let [_ (target/foo-caller 1)] + (is (not (assertions/called-times? target/foo 2)))) + (let [_ (target/foo-caller 2)] + (is (not (assertions/called-times? target/foo 1))))))) + +(deftest called-with-args?-works + (testing "an assertion for calling a spy with args" + (bond/with-spy [target/foo] + (let [_ (target/foo-caller 1)] + (is (assertions/called-with-args? target/foo [[1]])) + (is (not (assertions/called-with-args? target/foo [[2]]))) + (is (not (assertions/called-with-args? target/bar [[1]]))) + (is (not (assertions/called-with-args? target/foo [[1 2]])))))) + + (testing "an assertion for calling a spy multiple times with args" + (bond/with-spy [target/foo] + (let [_ (do (target/foo-caller 1) + (target/foo-caller 2))] + (is (assertions/called-with-args? target/foo [[1] [2]])))))) diff --git a/test-resources/lib_tests/bond/test/james.cljc b/test-resources/lib_tests/bond/test/james.cljc new file mode 100644 index 00000000..4a112f32 --- /dev/null +++ b/test-resources/lib_tests/bond/test/james.cljc @@ -0,0 +1,108 @@ +(ns bond.test.james + "Copy of https://github.com/circleci/bond/blob/6e044e6b4ea034c2e7b7c0f835976770341a5f7b/test/bond/test/james.cljc +with :include-macros removed because it's not supported by bb. Also modified spy-logs-args-and-results to + throw exception that bb throws." + (:require #?(:clj [clojure.test :refer (deftest is testing)]) + [bond.james :as bond] + [bond.test.target :as target]) + #?(:cljs (:require-macros [cljs.test :refer (is deftest testing)]))) + +(deftest spy-logs-args-and-results + (bond/with-spy [target/foo] + (is (= 2 (target/foo 1))) + (is (= 4 (target/foo 2))) + (is (= [{:args [1] :return 2} + {:args [2] :return 4}] + (bond/calls target/foo))) + ;; cljs doesn't throw ArityException + #?(:clj (let [exception (is (thrown? Exception (target/foo 3 4)))] + (is (= {:args [3 4] :throw exception} + (-> target/foo bond/calls last))))))) + +(deftest spy-can-spy-private-fns + (bond/with-spy [target/private-foo] + (is (= 4 (#'target/private-foo 2))) + (is (= 6 (#'target/private-foo 3))) + (is (= [{:args [2] :return 4} + {:args [3] :return 6}] + (bond/calls #'target/private-foo))))) + +(deftest stub-works + (is (= "" + (with-out-str + (bond/with-stub [target/bar] + (target/bar 3)))))) + +(deftest stub-works-with-private-fn + (testing "without replacement" + (bond/with-stub [target/private-foo] + (is (nil? (#'target/private-foo 3))) + (is (= [3] (-> #'target/private-foo bond/calls first :args))))) + (testing "with replacement" + (bond/with-stub [[target/private-foo (fn [x] (* x x))]] + (is (= 9 (#'target/private-foo 3))) + (is (= [3] (-> #'target/private-foo bond/calls first :args)))))) + +(deftest stub-with-replacement-works + (bond/with-stub [target/foo + [target/bar #(str "arg is " %)]] + (testing "stubbing works" + (is (nil? (target/foo 4))) + (is (= "arg is 3" (target/bar 3)))) + (testing "spying works" + (is (= [4] (-> target/foo bond/calls first :args))) + (is (= [3] (-> target/bar bond/calls first :args)))))) + + +(deftest iterator-style-stubbing-works + (bond/with-stub [target/foo + [target/bar [#(str "first arg is " %) + #(str "second arg is " %) + #(str "third arg is " %)]]] + (testing "stubbing works" + (is (nil? (target/foo 4))) + (is (= "first arg is 3" (target/bar 3))) + (is (= "second arg is 4" (target/bar 4))) + (is (= "third arg is 5" (target/bar 5)))) + (testing "spying works" + (is (= [4] (-> target/foo bond/calls first :args))) + (is (= [3] (-> target/bar bond/calls first :args))) + (is (= [4] (-> target/bar bond/calls second :args))) + (is (= [5] (-> target/bar bond/calls last :args)))))) + +(deftest stub!-complains-loudly-if-there-is-no-arglists + (is (thrown? #?(:clj IllegalArgumentException :cljs js/Error) + (bond/with-stub! [[target/without-arglists (constantly 42)]] + (is false))))) + +(deftest stub!-throws-arity-exception + (bond/with-stub! [[target/foo (constantly 9)]] + (is (= 9 (target/foo 12))) + (is (= [{:args [12] :return 9}] (bond/calls target/foo)))) + (bond/with-stub! [target/bar + target/quuk + [target/quux (fn [_ _ & x] x)]] + (is (thrown? #?(:clj clojure.lang.ArityException :cljs js/Error) + (target/bar 1 2))) + (is (thrown? #?(:clj clojure.lang.ArityException :cljs js/Error) + (target/quuk 1))) + (is (= [6 5] (target/quux 8 7 6 5))))) + +(deftest spying-entire-namespaces-works + (bond/with-spy-ns [bond.test.target] + (target/foo 1) + (target/foo 2) + (is (= [{:args [1] :return 2} + {:args [2] :return 4}] + (bond/calls target/foo))) + (is (= 0 (-> target/bar bond/calls count))))) + +(deftest stubbing-entire-namespaces-works + (testing "without replacements" + (bond/with-stub-ns [bond.test.target] + (is (nil? (target/foo 10))) + (is (= [10] (-> target/foo bond/calls first :args))))) + (testing "with replacements" + (bond/with-stub-ns [[bond.test.target (constantly 3)]] + (is (= 3 (target/foo 10))) + (is (= [10] (-> target/foo bond/calls first :args)))))) diff --git a/test-resources/lib_tests/bond/test/target.cljc b/test-resources/lib_tests/bond/test/target.cljc new file mode 100644 index 00000000..2c33cd84 --- /dev/null +++ b/test-resources/lib_tests/bond/test/target.cljc @@ -0,0 +1,32 @@ +(ns bond.test.target) + +(defn foo + [x] + (* 2 x)) + +(defn- private-foo + [x] + (* 2 x)) + +(defn foo-caller [x] + (foo x)) + +(defn bar + [x] + (println "bar!") (* 2 x)) + +(defn quux + [a b & c] + c) + +(defn quuk + [a b & c] + c) + +(defmacro baz + [x] + `(* ~x 2)) + +(def without-arglists + (fn [x] + (* 2 x)))