diff --git a/deps.edn b/deps.edn index bac671ac..031f8252 100644 --- a/deps.edn +++ b/deps.edn @@ -69,16 +69,16 @@ henryw374/cljc.java-time {:git/url "https://github.com/henryw374/cljc.java-time.git" :sha "e3d184b78e933322b3fcaa6ca66cbb8f42a6b35c"} - camel-snake-kebab/camel-snake-kebab {:mvn/version "0.4.1"} + camel-snake-kebab/camel-snake-kebab {:mvn/version "0.4.2"} aero/aero {:mvn/version "1.1.6"} org.clojure/data.generators {:mvn/version "1.0.0"} honeysql/honeysql {:mvn/version "1.0.444"} com.github.seancorfield/honeysql {:mvn/version "2.0.0-rc2"} - minimallist/minimallist {:mvn/version "0.0.6"} - circleci/bond {:mvn/version "0.4.0"} - version-clj/version-clj {:mvn/version "2.0.1"} + minimallist/minimallist {:mvn/version "0.0.10"} + circleci/bond {:mvn/version "0.6.0"} + version-clj/version-clj {:mvn/version "2.0.2"} gaka/gaka {:mvn/version "0.3.0"} - failjure/failjure {:mvn/version "2.1.1"} + failjure/failjure {:mvn/version "2.2.0"} io.helins/binf {:mvn/version "1.1.0-beta0"} rm-hull/jasentaa {:mvn/version "0.2.5"} slingshot/slingshot {:mvn/version "0.12.2"} diff --git a/script/add-libtest.clj b/script/add-libtest.clj index d44e549e..969ccd79 100755 --- a/script/add-libtest.clj +++ b/script/add-libtest.clj @@ -6,6 +6,7 @@ (:require [babashka.deps :as deps] [babashka.fs :as fs] [babashka.tasks :refer [shell]] + [org.httpkit.client :as http] [clojure.string :as str] [clojure.java.io :as io] [clojure.tools.cli :as cli] @@ -53,7 +54,7 @@ (let [nodes (-> "deps.edn" slurp r/parse-string)] (spit "deps.edn" (str (r/assoc-in nodes - [:aliases :lib-tests :extra-deps (symbol lib-name)] + [:aliases :lib-tests :extra-deps lib-name] lib-coordinate))))) (defn- copy-tests @@ -102,14 +103,46 @@ lib))) namespaces)) -(defn- add-libtest* - [args options] - (let [[deps-string git-url] args - deps-map (edn/read-string deps-string) +(defn- fetch-artifact + [artifact] + (let [url (str "https://clojars.org/api/artifacts/" artifact) + _ (println (str "GET " url "...")) + resp @(http/get url {:headers {"Accept" "application/edn"}})] + (if (= 200 (:status resp)) + (-> resp :body slurp edn/read-string) + (error (str "Response failed and returned " (pr-str resp)))))) + +(defn- deps-to-lib-name-and-coordinate + [deps-string] + (let [deps-map (edn/read-string deps-string) _ (when (not= 1 (count deps-map)) (error "Deps map must have one key")) lib-name (ffirst deps-map) - lib-coordinate (deps-map lib-name) + lib-coordinate (deps-map lib-name)] + [lib-name lib-coordinate])) + +(defn- get-lib-map + [deps-string options] + ;; if deps-string is artifact name + (if (re-matches #"\S+/\S+" deps-string) + (let [artifact-edn (fetch-artifact deps-string)] + {:lib-name (symbol deps-string) + :lib-coordinate {:mvn/version (:latest_version artifact-edn)} + :git-url (or (:git-url options) (:homepage artifact-edn))}) + (let [deps-map (edn/read-string deps-string)] + (when (not= 1 (count deps-map)) + (error "Deps map must have one key")) + {:lib-name (ffirst deps-map) + :lib-coordinate (-> deps-map vals first) + :git-url (:git-url options)}))) + +(defn- add-libtest* + [args options] + (let [[artifact-or-deps-string] args + {:keys [lib-name lib-coordinate git-url]} + (get-lib-map artifact-or-deps-string options) + _ (when (nil? git-url) + (error "git-url is required. Please specify with --git-url")) _ (add-lib-to-deps lib-name lib-coordinate) dirs (copy-tests git-url lib-name options) namespaces (add-lib-to-tested-libs lib-name git-url dirs options)] @@ -119,8 +152,8 @@ (defn add-libtest [{:keys [arguments options summary]}] - (if (or (< (count arguments) 2) (:help options)) - (print-summary "DEPS-MAP GIT-URL " summary) + (if (or (< (count arguments) 1) (:help options)) + (print-summary "ARTIFACT-OR-DEPS-MAP " summary) (add-libtest* arguments options))) (def cli-options @@ -129,7 +162,8 @@ ;; https://github.com/weavejester/environ/tree/master/environ used this option ["-d" "--directory DIRECTORY" "Directory where library is located"] ;; https://github.com/reifyhealth/specmonstah used this option - ["-b" "--branch BRANCH" "Default branch for git url"]]) + ["-b" "--branch BRANCH" "Default branch for git url"] + ["-g" "--git-url GITURL" "Git url for artifact. Defaults to homepage on clojars"]]) (when (= *file* (System/getProperty "babashka.file")) (run-command add-libtest *command-line-args* cli-options)) diff --git a/test-resources/lib_tests/aero/core_test.cljc b/test-resources/lib_tests/aero/core_test.cljc index aabbae06..62b552d8 100644 --- a/test-resources/lib_tests/aero/core_test.cljc +++ b/test-resources/lib_tests/aero/core_test.cljc @@ -13,7 +13,7 @@ goog.string.format [cljs.tools.reader.reader-types :refer [source-logging-push-back-reader]]])) - ;; TODO: + ;; BB-TEST-PATCH #_#?(:clj (:import [aero.core Deferred]))) (defn env [s] @@ -38,6 +38,8 @@ (if (= value :favorite) :chocolate :vanilla)) (deftest basic-test + ;; BB-TEST-PATCH: This and several other test files were changed to work with + ;; our dir structure (let [config (read-config "test-resources/lib_tests/aero/config.edn")] (is (= "Hello World!" (:greeting config)))) (testing "Reading empty config returns nil" diff --git a/test-resources/lib_tests/aero/lumo_test.cljs b/test-resources/lib_tests/aero/lumo_test.cljs new file mode 100644 index 00000000..365e61c9 --- /dev/null +++ b/test-resources/lib_tests/aero/lumo_test.cljs @@ -0,0 +1,23 @@ +(ns aero.lumo-test + (:require + aero.core-test + [cljs.test :refer-macros [deftest is testing run-tests]])) + +(def resolve-p (atom nil)) + +(def p (new js/Promise (fn [resolve reject] + (reset! resolve-p resolve)))) + +(defmethod cljs.test/report [:cljs.test/default :end-run-tests] + [m] + (@resolve-p m)) + +(defn -main [& argv] + (println "Testing with lumo") + (run-tests 'aero.core-test) + (-> p + (.then (fn [m] + (.exit (js/require "process") + (if (cljs.test/successful? m) + 0 + 1)))))) diff --git a/test-resources/lib_tests/babashka/run_all_libtests.clj b/test-resources/lib_tests/babashka/run_all_libtests.clj index a3511e78..ae3d2fb6 100644 --- a/test-resources/lib_tests/babashka/run_all_libtests.clj +++ b/test-resources/lib_tests/babashka/run_all_libtests.clj @@ -115,39 +115,10 @@ (test-doric-cyclic-dep-problem) (test-namespaces 'doric.test.core)) -;;;; cljc-java-time - -(test-namespaces 'cljc.java-time-test) - -;;;; camel-snake-kebab - -(test-namespaces 'camel-snake-kebab.core-test) - -;;;; aero - -(test-namespaces 'aero.core-test) - -;;;; clojure.data.generators - -(test-namespaces 'clojure.data.generators-test) - ;;;; honeysql (test-namespaces 'honeysql.core-test 'honeysql.format-test) -;;;; minimallist - -(test-namespaces 'minimallist.core-test) - -;;;; bond -(test-namespaces 'bond.test.james) - -;;;; version-clj -(test-namespaces 'version-clj.compare-test - 'version-clj.core-test - 'version-clj.split-test - 'version-clj.via-use-test) - ;;;; httpkit client (test-namespaces 'httpkit.client-test) @@ -168,10 +139,6 @@ (test-namespaces 'test-check.smoke-test) -(test-namespaces 'gaka.core-test) - -(test-namespaces 'failjure.test-core) - (test-namespaces 'rewrite-clj.parser-test 'rewrite-clj.node-test 'rewrite-clj.zip-test @@ -184,23 +151,10 @@ (test-namespaces 'selmer.core-test) (test-namespaces 'selmer.our-test) -(test-namespaces 'jasentaa.position-test - 'jasentaa.worked-example-1 - 'jasentaa.worked-example-2 - 'jasentaa.collections-test - 'jasentaa.parser.basic-test - 'jasentaa.parser.combinators-test) - (test-namespaces 'honey.sql-test 'honey.sql.helpers-test 'honey.sql.postgres-test) -(test-namespaces 'slingshot.slingshot-test - 'slingshot.support-test - ;; TODO: - ;; 'slingshot.test-test - ) - (test-namespaces 'omniconf.core-test) (test-namespaces 'crispin.core-test) @@ -222,8 +176,6 @@ ;; namespaces to see if they at least load correctly (test-namespaces 'java-http-clj.smoke-test) -(test-namespaces 'component.component-test) - (test-namespaces 'clj-commons.digest-test) (test-namespaces 'hato.client-test) diff --git a/test-resources/lib_tests/bb-tested-libs.edn b/test-resources/lib_tests/bb-tested-libs.edn index 5d77fd29..3e7c9d5f 100644 --- a/test-resources/lib_tests/bb-tested-libs.edn +++ b/test-resources/lib_tests/bb-tested-libs.edn @@ -20,4 +20,18 @@ ;; BB-TEST-PATCH: Removed markdown.md-file-test b/c tests hardcode path to test ;; files. Removed markdown.benchmark b/c it depends on criterium which isn't bb compatible markdown-clj/markdown-clj {:git-sha "ac245d3049afa25a6d41fcb5ba5a268f52c610e4", :git-url "https://github.com/yogthos/markdown-clj", :test-namespaces (markdown.md-test)} - org.clojure/tools.namespace {:git-sha "a13b037215e21a2e71aa34b27e1dd52c801a2a7b", :git-url "https://github.com/babashka/tools.namespace", :test-namespaces (clojure.tools.namespace.test-helpers clojure.tools.namespace.dependency-test clojure.tools.namespace.find-test clojure.tools.namespace.move-test clojure.tools.namespace.parse-test clojure.tools.namespace.dir-test), :branch "babashka"}} + org.clojure/tools.namespace {:git-sha "a13b037215e21a2e71aa34b27e1dd52c801a2a7b", :git-url "https://github.com/babashka/tools.namespace", :test-namespaces (clojure.tools.namespace.test-helpers clojure.tools.namespace.dependency-test clojure.tools.namespace.find-test clojure.tools.namespace.move-test clojure.tools.namespace.parse-test clojure.tools.namespace.dir-test), :branch "babashka"} + com.stuartsierra/component {:git-sha "9f9653d1d95644e3c30beadf8c8811f86758ea23", :git-url "https://github.com/stuartsierra/component", :test-namespaces (com.stuartsierra.component-test)} + slingshot/slingshot {:git-sha "6961ab0593ab9633c15b7697ffd43823090720be", :git-url "https://github.com/scgilardi/slingshot", :test-namespaces (slingshot.slingshot-test slingshot.support-test slingshot.test-test)} + rm-hull/jasentaa {:git-sha "f52a0e75cbdf1d2b72d9604232db264ff6473f12", :git-url "https://github.com/rm-hull/jasentaa", :test-namespaces (jasentaa.position-test jasentaa.worked-example-2 jasentaa.collections-test jasentaa.parser.basic-test jasentaa.parser.combinators-test jasentaa.test-helpers jasentaa.worked-example-1)} + failjure/failjure {:git-sha "c6e528c1eda6ad5eaab0f1fb2a97e766bf41fdd5", :git-url "https://github.com/adambard/failjure", :test-namespaces (failjure.test-core)} + gaka/gaka {:git-sha "2f264758881d6dc586b948ca8757134675f542a7", :git-url "https://github.com/cdaddr/gaka", :test-namespaces (gaka.core-test)} + version-clj/version-clj {:git-sha "9d86cd870f7e435fd6d593cb689790a22d8040a6", :git-url "https://github.com/xsc/version-clj", :test-namespaces (version-clj.compare-test version-clj.split-test version-clj.core-test version-clj.via-use-test)} + circleci/bond {:git-sha "0d389cfb4628341824bddbe8bf102f15ad25ad0d", :git-url "https://github.com/circleci/bond", :test-namespaces (bond.assertions-test bond.james-test bond.target-data)} + ;; BB-TEST-PATCH: minimallist.generator-test excluded because generator ns can't be required + minimallist/minimallist {:git-sha "f10ebbd3c2b93e7579295618a7ed1e870c489bc4", :git-url "https://github.com/green-coder/minimallist", :test-namespaces (minimallist.util-test minimallist.core-test), :branch "all-work-and-no-play"} + aero/aero {:git-sha "743e9bc495425b4a4a7c780f5e4b09f6680b4e7a", :git-url "http://github.com/juxt/aero", :test-namespaces (aero.core-test)} + org.clojure/data.generators {:git-sha "bf65f99aa9dcabed7de7c09b74d71db208cf61ee", :git-url "https://github.com/clojure/data.generators", :test-namespaces (clojure.data.generators-test)} + camel-snake-kebab/camel-snake-kebab {:git-sha "d072c7fd242ab0becd4bb265622ded415f2a4b68", :git-url "https://github.com/clj-commons/camel-snake-kebab", :test-namespaces (camel-snake-kebab.internals.string-separator-test camel-snake-kebab.extras-test camel-snake-kebab.core-test)} + ;; BB-TEST-PATCH: Removed cljs-test-opts.edn + henryw374/cljc.java-time {:git-sha "b9da12ea25e80a0e284a5bffd88ebcbf18fc3bf7", :git-url "https://github.com/henryw374/cljc.java-time", :test-namespaces (cljc.java-time-test)}} diff --git a/test-resources/lib_tests/bond/assertions_test.clj b/test-resources/lib_tests/bond/assertions_test.clj new file mode 100644 index 00000000..1969600a --- /dev/null +++ b/test-resources/lib_tests/bond/assertions_test.clj @@ -0,0 +1,121 @@ +(ns bond.assertions-test + (:require [clojure.test :refer (deftest is testing)] + [bond.assertions :as assertions] + [bond.james :as bond :include-macros true] + [bond.target-data :as target])) + +(deftest called?-works + (testing "a spy was called directly" + (bond/with-spy [target/foo] + (target/foo 1) + (is (assertions/called? target/foo)))) + + (testing "a spy was called indirectly" + (bond/with-spy [target/foo] + (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))))) + + (testing "called? fails when its argument is not spied" + (is (thrown? IllegalArgumentException + (assertions/called? target/foo))))) + +(deftest called-times?-works + (testing "the number of times a spy was called" + (bond/with-spy [target/foo] + (target/foo-caller 1) + (is (assertions/called-times? target/foo 1)) + (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] + (target/foo-caller 1) + (is (not (assertions/called-times? target/foo 2))) + (target/foo-caller 2) + (is (not (assertions/called-times? target/foo 1))))) + + (testing "called-times? fails when its argument is not spied" + (is (thrown? IllegalArgumentException + (assertions/called-times? target/foo 0))))) + +(deftest called-with-args?-works + (testing "an assertion for calling a spy with args" + (bond/with-spy [target/foo + target/bar] + (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] + (target/foo-caller 1) + (target/foo-caller 2) + (is (assertions/called-with-args? target/foo [[1] [2]])))) + + (testing "called-with-args? fails when its argument is not spied" + (is (thrown? IllegalArgumentException + (assertions/called-with-args? target/foo []))))) + +(deftest called-once-with-args?-works + (testing "an assertion for calling a spy once with args" + (bond/with-spy [target/foo] + (target/foo 1) + (is (assertions/called-once-with-args? target/foo [1])) + (is (not (assertions/called-once-with-args? target/foo [2]))))) + + (testing "an assertion for calling a spy twice with args" + (bond/with-spy [target/foo] + (target/foo 1) + (target/foo 2) + (is (not (assertions/called-once-with-args? target/foo [1]))) + (is (not (assertions/called-once-with-args? target/foo [2]))))) + + (testing "an assertion for calling a spy indirectly once with args" + (bond/with-spy [target/foo] + (target/foo-caller 1) + (is (assertions/called-once-with-args? target/foo [1])) + (is (not (assertions/called-once-with-args? target/foo [2]))))) + + (testing "an assertion for a spy that was not called" + (bond/with-spy [target/foo] + (is (not (assertions/called-once-with-args? target/foo []))))) + + (testing "called-once-with-args? fails when its argument is not spied" + (is (thrown? IllegalArgumentException + (assertions/called-once-with-args? target/foo []))))) + +(deftest called-at-least-once-with-args?-works + (testing "an assertion for calling a spy multiple times" + (bond/with-spy [target/foo] + (target/foo 1) + (target/foo 2) + (is (assertions/called-at-least-once-with-args? target/foo [1])) + (is (assertions/called-at-least-once-with-args? target/foo [2])) + (is (not (assertions/called-at-least-once-with-args? target/foo [3]))))) + + (testing "an assertion for calling a spy multiple times with the same value" + (bond/with-spy [target/foo] + (target/foo 1) + (target/foo 1) + (is (assertions/called-at-least-once-with-args? target/foo [1])) + (is (not (assertions/called-at-least-once-with-args? target/foo [2]))))) + + (testing "an assertion for calling a spy once" + (bond/with-spy [target/foo] + (target/foo 1) + (is (assertions/called-at-least-once-with-args? target/foo [1])) + (is (not (assertions/called-at-least-once-with-args? target/foo [2]))))) + + (testing "an assertion for a spy that was not called" + (bond/with-spy [target/foo] + (is (not (assertions/called-at-least-once-with-args? target/foo []))))) + + (testing "called-at-least-once-with-args? fails when its argument is not spied" + (is (thrown? IllegalArgumentException + (assertions/called-at-least-once-with-args? target/foo []))))) diff --git a/test-resources/lib_tests/bond/james_test.clj b/test-resources/lib_tests/bond/james_test.clj new file mode 100644 index 00000000..f6a5696f --- /dev/null +++ b/test-resources/lib_tests/bond/james_test.clj @@ -0,0 +1,109 @@ +(ns bond.james-test + {:clj-kondo/config {:linters {:private-call {:level :off} + :invalid-arity {:level :off}}}} + (:require [clojure.test :refer (deftest is testing)] + [bond.james :as bond :include-macros true] + [bond.target-data :as target])) + +(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))) + (let [exception (is (thrown? clojure.lang.ArityException (target/foo 3 4)))] + (is (= {:args [3 4] :throw exception} + (-> target/foo bond/calls last)))))) + +(deftest calls-fails-on-unspied-fns + (is (thrown? IllegalArgumentException + (bond/calls target/foo)))) + +(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? IllegalArgumentException + (bond/with-stub! [[target/without-arglists (constantly 42)]] + (throw (Exception. "shouldn't get here")))))) + +(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? clojure.lang.ArityException + (target/bar 1 2))) + (is (thrown? clojure.lang.ArityException + (target/quuk 1))) + (is (= [6 5] (target/quux 8 7 6 5))))) + +(deftest spying-entire-namespaces-works + (bond/with-spy-ns [bond.target-data] + (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.target-data] + (is (nil? (target/foo 10))) + (is (= [10] (-> target/foo bond/calls first :args))))) + (testing "with replacements" + (bond/with-stub-ns [[bond.target-data (constantly 3)]] + (is (= 3 (target/foo 10))) + (is (= [10] (-> target/foo bond/calls first :args)))))) diff --git a/test-resources/lib_tests/bond/target_data.clj b/test-resources/lib_tests/bond/target_data.clj new file mode 100644 index 00000000..986a06de --- /dev/null +++ b/test-resources/lib_tests/bond/target_data.clj @@ -0,0 +1,35 @@ +(ns bond.target-data + "Reference def targets for bond to test against." + {:clj-kondo/config {:linters {:unused-binding {:level :off} + :unused-private-var {:level :off}}}}) + +(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))) diff --git a/test-resources/lib_tests/camel_snake_kebab/core_test.cljc b/test-resources/lib_tests/camel_snake_kebab/core_test.cljc index ab65cb53..cf426706 100644 --- a/test-resources/lib_tests/camel_snake_kebab/core_test.cljc +++ b/test-resources/lib_tests/camel_snake_kebab/core_test.cljc @@ -47,7 +47,11 @@ (testing "handling of blank input string" (is (= "" (csk/->kebab-case ""))) - (is (= "" (csk/->kebab-case " "))))) + (is (= "" (csk/->kebab-case " ")))) + + (testing "handling of input consisting of only separator(s)" + (is (= "" (csk/->kebab-case "a" :separator \a))) + (is (= "" (csk/->kebab-case "aa" :separator \a))))) (deftest http-header-case-test (are [x y] (= x (csk/->HTTP-Header-Case y)) diff --git a/test-resources/lib_tests/camel_snake_kebab/extras_test.cljc b/test-resources/lib_tests/camel_snake_kebab/extras_test.cljc new file mode 100644 index 00000000..81d0c08f --- /dev/null +++ b/test-resources/lib_tests/camel_snake_kebab/extras_test.cljc @@ -0,0 +1,16 @@ +(ns camel-snake-kebab.extras-test + (:require [camel-snake-kebab.core :as csk] + [camel-snake-kebab.extras :refer [transform-keys]] + #?(:clj [clojure.test :refer :all] + :cljs [cljs.test :refer-macros [deftest testing is are]]))) + +(deftest transform-keys-test + (are [x y] (= x (transform-keys csk/->kebab-case-keyword y)) + nil nil + {} {} + [] [] + {:total-books 0 :all-books []} {'total_books 0 "allBooks" []} + [{:the-author "Dr. Seuss" :the-title "Green Eggs and Ham"}] + [{'the-Author "Dr. Seuss" "The_Title" "Green Eggs and Ham"}] + {:total-books 1 :all-books [{:the-author "Dr. Seuss" :the-title "Green Eggs and Ham"}]} + {'total_books 1 "allBooks" [{'THE_AUTHOR "Dr. Seuss" "the_Title" "Green Eggs and Ham"}]})) diff --git a/test-resources/lib_tests/camel_snake_kebab/internals/string_separator_test.cljc b/test-resources/lib_tests/camel_snake_kebab/internals/string_separator_test.cljc new file mode 100644 index 00000000..31a5704a --- /dev/null +++ b/test-resources/lib_tests/camel_snake_kebab/internals/string_separator_test.cljc @@ -0,0 +1,41 @@ +(ns camel-snake-kebab.internals.string-separator-test + (:require [camel-snake-kebab.internals.string-separator :refer [split generic-separator]] + #?(:clj [clojure.test :refer :all] + :cljs [cljs.test :refer-macros [deftest testing is are]]))) + +(deftest split-test + (testing "regex, string and character separators" + (are [sep] + (and (= ["foo" "bar"] (split sep "foo.bar")) + (= [""] (split sep ""))) + #"\." "." \.)) + + (testing "input consisting of separator(s)" + (is (empty? (split "x" "x"))) + (is (empty? (split "x" "xx")))) + + (testing "generic separator" + (are [x y] + (= x (split generic-separator y)) + + [""] "" + [""] " " + ["x"] " x " + + ["foo" "bar"] "foo bar" + ["foo" "bar"] "foo\n\tbar" + ["foo" "bar"] "foo-bar" + ["foo" "Bar"] "fooBar" + ["Foo" "Bar"] "FooBar" + ["foo" "bar"] "foo_bar" + ["FOO" "BAR"] "FOO_BAR" + + ["räksmörgås"] "räksmörgås" + + ["IP" "Address"] "IPAddress" + + ["Adler" "32"] "Adler32" + ["Inet" "4" "Address"] "Inet4Address" + ["Arc" "2" "D"] "Arc2D" + ["a" "123b"] "a123b" + ["A" "123" "B"] "A123B"))) diff --git a/test-resources/lib_tests/camel_snake_kebab/test_runner.cljs b/test-resources/lib_tests/camel_snake_kebab/test_runner.cljs new file mode 100644 index 00000000..20b094bd --- /dev/null +++ b/test-resources/lib_tests/camel_snake_kebab/test_runner.cljs @@ -0,0 +1,10 @@ +(ns camel-snake-kebab.test-runner + (:require [cljs.test :as test] + [doo.runner :refer-macros [doo-all-tests doo-tests]] + [camel-snake-kebab.core-test] + [camel-snake-kebab.extras-test] + [camel-snake-kebab.internals.string-separator-test])) + +(doo-tests 'camel-snake-kebab.core-test + 'camel-snake-kebab.extras-test + 'camel-snake-kebab.internals.string-separator-test) diff --git a/test-resources/lib_tests/clojure/data/generators_test.clj b/test-resources/lib_tests/clojure/data/generators_test.clj index 8fa89e88..00628d83 100644 --- a/test-resources/lib_tests/clojure/data/generators_test.clj +++ b/test-resources/lib_tests/clojure/data/generators_test.clj @@ -32,4 +32,4 @@ (gen/reservoir-sample 10 coll)) sample-2 (binding [gen/*rnd* (java.util.Random. n)] (gen/reservoir-sample 10 coll))] - (is (= sample-1 sample-2))))) \ No newline at end of file + (is (= sample-1 sample-2))))) diff --git a/test-resources/lib_tests/com/stuartsierra/component_test.clj b/test-resources/lib_tests/com/stuartsierra/component_test.clj new file mode 100644 index 00000000..00602462 --- /dev/null +++ b/test-resources/lib_tests/com/stuartsierra/component_test.clj @@ -0,0 +1,307 @@ +(ns com.stuartsierra.component-test + (:require [clojure.test :refer (deftest is are)] + [clojure.set :refer (map-invert)] + [com.stuartsierra.component :as component])) + +(def ^:dynamic *log* nil) + +(defn- log [& args] + (when (thread-bound? #'*log*) + (set! *log* (conj *log* args)))) + +(defn- ordering + "Given an ordered collection of messages, returns a map from the + head of each message to its index position in the collection." + [log] + (into {} (map-indexed (fn [i [message & _]] [message i]) log))) + +(defn before? + "In the collection of messages, does the message beginning with + symbol a come before the message begging with symbol b?" + [log sym-a sym-b] + (let [order (ordering log)] + (< (get order sym-a) (get order sym-b)))) + +(defn started? [component] + (true? (::started? component))) + +(defn stopped? [component] + (false? (::started? component))) + +(defrecord ComponentA [state] + component/Lifecycle + (start [this] + (log 'ComponentA.start this) + (assoc this ::started? true)) + (stop [this] + (log 'ComponentA.stop this) + (assoc this ::started? false))) + +(defn component-a [] + (->ComponentA (rand-int Integer/MAX_VALUE))) + +(defrecord ComponentB [state a] + component/Lifecycle + (start [this] + (log 'ComponentB.start this) + (assert (started? a)) + (assoc this ::started? true)) + (stop [this] + (log 'ComponentB.stop this) + (assert (started? a)) + (assoc this ::started? false))) + +(defn component-b [] + (component/using + (map->ComponentB {:state (rand-int Integer/MAX_VALUE)}) + [:a])) + +(defrecord ComponentC [state a b] + component/Lifecycle + (start [this] + (log 'ComponentC.start this) + (assert (started? a)) + (assert (started? b)) + (assoc this ::started? true)) + (stop [this] + (log 'ComponentC.stop this) + (assert (started? a)) + (assert (started? b)) + (assoc this ::started? false))) + +(defn component-c [] + (component/using + (map->ComponentC {:state (rand-int Integer/MAX_VALUE)}) + [:a :b])) + +(defrecord ComponentD [state my-c b] + component/Lifecycle + (start [this] + (log 'ComponentD.start this) + (assert (started? b)) + (assert (started? my-c)) + (assoc this ::started? true)) + (stop [this] + (log 'ComponentD.stop this) + (assert (started? b)) + (assert (started? my-c)) + (assoc this ::started? false))) + +(defn component-d [] + (map->ComponentD {:state (rand-int Integer/MAX_VALUE)})) + +(defrecord ComponentE [state] + component/Lifecycle + (start [this] + (log 'ComponentE.start this) + (assoc this ::started? true)) + (stop [this] + (log 'ComponentE.stop this) + (assoc this ::started? false))) + +(defn component-e [] + (map->ComponentE {:state (rand-int Integer/MAX_VALUE)})) + +(defrecord System1 [d a e c b] ; deliberately scrambled order + component/Lifecycle + (start [this] + (log 'System1.start this) + (component/start-system this)) + (stop [this] + (log 'System1.stop this) + (component/stop-system this))) + +(defn system-1 [] + (map->System1 {:a (component-a) + :b (component-b) + :c (component-c) + :d (component/using (component-d) + {:b :b + :my-c :c}) + :e (component-e)})) + +(defmacro with-log [& body] + `(binding [*log* []] + ~@body + *log*)) + +(deftest components-start-in-order + (let [log (with-log (component/start (system-1)))] + (are [k1 k2] (before? log k1 k2) + 'ComponentA.start 'ComponentB.start + 'ComponentA.start 'ComponentC.start + 'ComponentB.start 'ComponentC.start + 'ComponentC.start 'ComponentD.start + 'ComponentB.start 'ComponentD.start))) + +(deftest all-components-started + (let [system (component/start (system-1))] + (doseq [component (vals system)] + (is (started? component))))) + +(deftest all-components-stopped + (let [system (component/stop (component/start (system-1)))] + (doseq [component (vals system)] + (is (stopped? component))))) + +(deftest dependencies-satisfied + (let [system (component/start (component/start (system-1)))] + (are [keys] (started? (get-in system keys)) + [:b :a] + [:c :a] + [:c :b] + [:d :my-c]))) + +(defrecord ErrorStartComponentC [state error a b] + component/Lifecycle + (start [this] + (throw error)) + (stop [this] + this)) + +(defn error-start-c [error] + (component/using + (map->ErrorStartComponentC {:error error}) + [:a :b])) + +(defn setup-error + ([] + (setup-error (ex-info "Boom!" {}))) + ([error] + (try (component/start + (assoc (system-1) :c (error-start-c error))) + (catch Exception e e)))) + +(deftest error-thrown-with-partial-system + (let [ex (setup-error)] + (is (started? (-> ex ex-data :system :b :a))))) + +(deftest error-thrown-with-component-dependencies + (let [ex (setup-error)] + (is (started? (-> ex ex-data :component :a))) + (is (started? (-> ex ex-data :component :b))))) + +(deftest error-thrown-with-cause + (let [error (ex-info "Boom!" {}) + ex (setup-error error)] + (is (identical? error (.getCause ^Exception ex))))) + +(deftest error-is-from-component + (let [error (ex-info "Boom!" {}) + ex (setup-error error)] + (is (component/ex-component? ex)))) + +(deftest error-is-not-from-component + (is (not (component/ex-component? (ex-info "Boom!" {}))))) + +(deftest remove-components-from-error + (let [error (ex-info (str (rand-int Integer/MAX_VALUE)) {}) + ^Exception ex (setup-error error) + ^Exception ex-without (component/ex-without-components ex)] + (is (contains? (ex-data ex) :component)) + (is (contains? (ex-data ex) :system)) + (is (not (contains? (ex-data ex-without) :component))) + (is (not (contains? (ex-data ex-without) :system))) + (is (= (.getMessage ex) + (.getMessage ex-without))) + (is (= (.getCause ex) + (.getCause ex-without))) + (is (java.util.Arrays/equals + (.getStackTrace ex) + (.getStackTrace ex-without))))) + +(defrecord System2b [one] + component/Lifecycle + (start [this] + (assert (started? (get-in one [:b :a]))) + this) + (stop [this] + (assert (started? (get-in one [:b :a]))) + this)) + +(defn system-2 [] + (component/system-map :alpha (system-1) + :beta (component/using (->System2b nil) + {:one :alpha}))) + +(deftest composed-systems + (let [system (component/start (system-2))] + (is (started? (get-in system [:beta :one :d :my-c]))))) + +(defn increment-all-components [system] + (component/update-system + system (keys system) update-in [:n] inc)) + +(defn assert-increments [system] + (are [n keys] (= n (get-in system keys)) + 11 [:a :n] + 11 [:b :a :n] + 11 [:c :a :n] + 11 [:c :b :a :n] + 11 [:e :d :b :a :n] + 21 [:b :n] + 21 [:c :b :n] + 21 [:d :b :n] + 31 [:c :n] + 41 [:d :n] + 51 [:e :n])) + +(deftest update-with-custom-function-on-maps + (let [system {:a {:n 10} + :b (component/using {:n 20} [:a]) + :c (component/using {:n 30} [:a :b]) + :d (component/using {:n 40} [:a :b]) + :e (component/using {:n 50} [:b :c :d])}] + (assert-increments (increment-all-components system)))) + +(deftest t-system-using + (let [dependency-map {:b [:a] + :c [:a :b] + :d {:a :a :b :b} + :e [:b :c :d]} + system {:a {:n 10} + :b {:n 20} + :c {:n 30} + :d {:n 40} + :e {:n 50}} + system (component/system-using system dependency-map)] + (assert-increments (increment-all-components system)))) + +(defrecord ComponentWithoutLifecycle [state]) + +;; BB-TEST-PATCH: No implementation of method errors for start and stop +#_(deftest component-without-lifecycle + (let [c (->ComponentWithoutLifecycle nil)] + (is (= c (component/start c))) + (is (= c (component/stop c))))) + +(defrecord ComponentReturningNil [state] + component/Lifecycle + (start [this] + nil) + (stop [this] + nil)) + +(deftest component-returning-nil + (let [a (->ComponentReturningNil nil) + s (component/system-map :a a :b (component-b)) + e (try (component/start s) + false + (catch Exception e e))] + (is (= ::component/nil-component (:reason (ex-data e)))))) + +(deftest missing-dependency-error + (let [system-key ::system-b + local-key ::local-b + a (component/using (component-a) {local-key system-key}) + system (component/system-map + :a a) + e (try (component/start system) + false + (catch Exception e e)) + data (ex-data e)] + (is (= ::component/missing-dependency (:reason data))) + (is (= system-key (:system-key data))) + (is (= local-key (:dependency-key data))) + (is (= a (:component data))) + (is (= system (:system data))))) diff --git a/test-resources/lib_tests/component/component_test.clj b/test-resources/lib_tests/component/component_test.clj deleted file mode 100644 index 32b715f8..00000000 --- a/test-resources/lib_tests/component/component_test.clj +++ /dev/null @@ -1,41 +0,0 @@ -(ns component.component-test - (:require [clojure.test :refer [deftest is testing]] - [com.stuartsierra.component :as component])) - - -(def syslog (atom [])) - -(defn log [msg] - (swap! syslog conj msg)) - -(defrecord FakeDB [state] - component/Lifecycle - (start [_] - (log "start DB")) - (stop [_] - (log "stop DB"))) - -(defrecord FakeApp [db] - component/Lifecycle - (start [_] - (log "start app")) - (stop [_] - (log "stop app"))) - -(defn base-app [] - (map->FakeApp {})) - -(def sm - (component/system-map - :db (->FakeDB :foo) - :app (component/using (base-app) [:db]))) - -(component/start sm) - -;; do useful stuff here - -(component/stop sm) - -(deftest ordering-test - (testing "components are started and stopped in expected order" - (is (= ["start DB" "start app" "stop app" "stop DB"] @syslog)))) diff --git a/test-resources/lib_tests/failjure/runner.cljs b/test-resources/lib_tests/failjure/runner.cljs new file mode 100644 index 00000000..5b334cbc --- /dev/null +++ b/test-resources/lib_tests/failjure/runner.cljs @@ -0,0 +1,5 @@ +(ns failjure.runner + (:require [doo.runner :refer-macros [doo-tests]] + [failjure.test-core])) + +(doo-tests 'failjure.test-core) diff --git a/test-resources/lib_tests/gaka/core_test.clj b/test-resources/lib_tests/gaka/core_test.clj index 622c4756..7305fdbc 100644 --- a/test-resources/lib_tests/gaka/core_test.clj +++ b/test-resources/lib_tests/gaka/core_test.clj @@ -1,7 +1,6 @@ (ns gaka.core-test - (:require [clojure.test :refer [deftest is are]] - [gaka.core :refer [css compile* inline-css render-rule]] - )) + (:use gaka.core + clojure.test)) (defmacro =? [& body] `(are [x# y#] (= x# y#) @@ -194,3 +193,4 @@ (is (re-find #"^(color: red; border: 1;|border: 1; color: red;)$" (inline-css {:color :red :border 1})))) + diff --git a/test-resources/lib_tests/minimallist/core_test.cljc b/test-resources/lib_tests/minimallist/core_test.cljc index d86176f1..1faaaa23 100644 --- a/test-resources/lib_tests/minimallist/core_test.cljc +++ b/test-resources/lib_tests/minimallist/core_test.cljc @@ -40,6 +40,16 @@ [1] [2] + (-> (h/fn int?) + (h/with-condition (h/fn odd?))) + [1] + [2] + + (-> (h/fn symbol?) + (h/with-condition (h/fn (complement #{'if 'val})))) + ['a] + ['if] + ;; enum (h/enum #{1 "2" :3}) [1 "2" :3] @@ -79,8 +89,7 @@ {:a 1, :b 'bar, [1 2 3] "soleil !"}] ;; map, keys and values - (h/map-of (h/fn keyword?) - (h/fn int?)) + (h/map-of (h/vector (h/fn keyword?) (h/fn int?))) [{} {:a 1, :b 2}] [{:a 1, :b "2"} [[:a 1] [:b 2]] {true 1, false 2}] @@ -89,6 +98,10 @@ ['(1 2 3) [1 2 3] `(1 2 ~3)] ['(1 :a) #{1 2 3} {:a 1, :b 2, :c 3}] + (h/sequence-of (h/fn char?)) + ["" "hi" "hello"] + [[1 2 3]] + ;; sequence, with condition (-> (h/sequence-of (h/fn int?)) (h/with-condition (h/fn (fn [coll] (= coll (reverse coll)))))) @@ -97,29 +110,38 @@ ;; sequence as a list (h/list-of (h/fn int?)) - ['(1 2 3)] - ['(1 :a) [1 2 3] #{1 2 3} - #_`(1 2 ~3)] ; this is not a list in cljs + ['(1 2 3) `(1 2 ~3)] + ['(1 :a) [1 2 3] #{1 2 3}] ;; sequence as a vector (h/vector-of (h/fn int?)) [[1 2 3]] [[1 :a] '(1 2 3) #{1 2 3} `(1 2 ~3)] + ;; sequence as a string + (h/string-of (h/enum (set "0123456789abcdef"))) + ["03ab4c" "cafe"] + ["coffee" [1 :a] '(1 2 3) #{1 2 3} `(1 2 ~3)] + ;; sequence with size specified using a model (-> (h/sequence-of (h/fn any?)) (h/with-count (h/enum #{2 3}))) - ['(1 2) [1 "2"] `(1 ~"2") [1 "2" :3]] - [#{1 "a"} [1 "2" :3 :4]] + ['(1 2) [1 "2"] `(1 ~"2") [1 "2" :3] "hi"] + [#{1 "a"} [1 "2" :3 :4] "hello"] ;; sequence with entries (fixed size is implied) (h/tuple (h/fn int?) (h/fn string?)) ['(1 "2") [1 "2"] `(1 ~"2")] [#{1 "a"} [1 "2" :3]] + ;; sequence with entries in a string + (h/string-tuple (h/val \a) (h/enum #{\b \c})) + ["ab" "ac"] + [[\a \b] #{\a \b}] + ;; alt (h/alt [:int (h/fn int?)] - [:strings (h/cat (h/fn string?))]) + [:strings (h/vector-of (h/fn string?))]) [1 ["1"]] [[1] "1" :1 [:1]] @@ -144,6 +166,12 @@ [[1 "2" 3] [1 :2 3] [1 ["a" :b] 3]] [[1 "a" :b 3]] + ;; cat & repeat - a color string + (-> (h/cat (h/val \#) + (h/repeat 6 6 (h/enum (set "0123456789abcdefABCDEF"))))) + ["#000000" "#af4Ea5"] + ["000000" "#cafe" "#coffee"] + ;; cat of cat, the inner cat is implicitly inlined (-> (h/cat (h/fn int?) (h/cat (h/fn int?))) @@ -163,15 +191,20 @@ [[] [1] [1 2] '() '(1) '(2 3)] [[1 2 3] '(1 2 3)] + ;; repeat - inside a list + (h/in-list (h/repeat 0 2 (h/fn int?))) + ['() '(1) '(2 3)] + [[] [1] [1 2] [1 2 3] '(1 2 3)] + ;; repeat - inside a vector (h/in-vector (h/repeat 0 2 (h/fn int?))) [[] [1] [1 2]] [[1 2 3] '() '(1) '(2 3) '(1 2 3)] - ;; repeat - inside a list - (h/in-list (h/repeat 0 2 (h/fn int?))) - ['() '(1) '(2 3)] - [[] [1] [1 2] [1 2 3] '(1 2 3)] + ;; repeat - inside a string + (h/in-string (h/repeat 4 6 (h/fn char?))) + ["hello"] + ["" "hi" [] [1] '(1 2 3)] ;; repeat - min > 0 (h/repeat 2 3 (h/fn int?)) @@ -196,6 +229,16 @@ [[[1 "a"]] [[1 "a"] [2 "b"]] ['(1 "a") [2 "b"]]] [[] [1] [1 2] [1 "a"] [1 "a" 2 "b"] [1 "a" 2 "b" 3 "c"]] + ;; char-cat & char-set + (-> (h/cat (h/char-cat "good") + (h/val \space) + (h/alt (h/char-cat "morning") + (h/char-cat "afternoon") + (h/repeat 3 10 (h/char-set "#?!@_*+%")))) + (h/in-string)) + ["good morning" "good afternoon" "good #@*+?!"] + ["good" "good " "good day"] + ;; let / ref (h/let ['pos-even? (h/and (h/fn pos-int?) (h/fn even?))] @@ -236,14 +279,24 @@ [1 1 1 "hi" "hi" "hi"]] [[1 1 "hi"] [1 "hi" "hi"] - [1 1 :no "hi" "hi"]]]] + [1 1 :no "hi" "hi"]] + ; let / ref - with shadowed local model + (h/let ['foo (h/ref 'bar) + 'bar (h/fn int?)] + (h/let ['bar (h/fn string?)] + (h/ref 'foo))) + [1] + ["hi"]]] (doseq [[model valid-coll invalid-coll] (partition 3 test-data)] (doseq [data valid-coll] (is (valid? model data))) (doseq [data invalid-coll] - (is (not (valid? model data))))))) + (is (not (valid? model data)))))) + + (is (thrown? #?(:clj Exception :cljs js/Object) + (valid? (h/let [] (h/ref 'foo)) 'bar)))) (deftest describe-test @@ -252,6 +305,16 @@ [1 1 2 :invalid] + (-> (h/fn int?) + (h/with-condition (h/fn odd?))) + [1 1 + 2 :invalid] + + (-> (h/fn symbol?) + (h/with-condition (h/fn (complement #{'if 'val})))) + ['a 'a + 'if :invalid] + ;; enum (h/enum #{1 "2" false nil}) [1 1 @@ -278,7 +341,7 @@ ;; set (h/set-of (h/fn int?)) - [#{1} #{1}] + [#{1 2} [1 2]] ;; map (h/map [:a {:optional true} (h/fn int?)] @@ -294,20 +357,29 @@ ; extra entry {:a 1, :b 2, :c 3} {:a 1, :b 2}] - ;; map-of - :keys - (h/map-of (h/fn keyword?) (h/fn any?)) - [{:a 1, :b 2} {:a 1, :b 2} + ;; map-of - entry-model + (h/map-of (h/vector (h/fn keyword?) (h/fn int?))) + [{:a 1, :b 2} [[:a 1] [:b 2]] {"a" 1} :invalid] - ;; map-of - :values - (h/map-of (h/fn any?) (h/fn int?)) - [{:a 1, "b" 2} {:a 1, "b" 2} - {:a "1"} :invalid] + ;; map-of - real world use case + (h/map-of (h/alt [:symbol (h/vector (h/fn simple-symbol?) (h/fn keyword?))] + [:keys (h/vector (h/val :keys) (h/vector-of (h/fn symbol?)))] + [:as (h/vector (h/val :as) (h/fn simple-symbol?))])) + '[{first-name :first-name + last-name :last-name + :keys [foo bar] + :as foobar} + [[:symbol [first-name :first-name]] + [:symbol [last-name :last-name]] + [:keys [:keys [foo bar]]] + [:as [:as foobar]]]] ;; sequence - :elements-model (h/sequence-of (h/fn int?)) [[1 2 3] [1 2 3] '(1 2 3) '(1 2 3) + `(1 2 3) '(1 2 3) [1 "2" 3] :invalid] ;; sequence - :elements-model with condition @@ -319,7 +391,14 @@ ;; sequence - :coll-type vector (h/vector-of (h/fn any?)) [[1 2 3] [1 2 3] - '(1 2 3) :invalid] + '(1 2 3) :invalid + `(1 2 3) :invalid] + + ;; sequence - :coll-type list + (h/list-of (h/fn any?)) + [[1 2 3] :invalid + '(1 2 3) '(1 2 3) + `(1 2 3) '(1 2 3)] ;; sequence - :entries (h/tuple (h/fn int?) (h/fn string?)) @@ -327,16 +406,27 @@ [1 2] :invalid [1] :invalid] + (h/tuple (h/fn int?) + [:text (h/fn string?)]) + [[1 "a"] {:text "a"}] + + (h/tuple [:number (h/fn int?)] + [:text (h/fn string?)]) + [[1 "a"] {:number 1, :text "a"}] + ;; sequence - :count-model (-> (h/sequence-of (h/fn any?)) (h/with-count (h/val 3))) [[1 2] :invalid [1 2 3] [1 2 3] - [1 2 3 4] :invalid] + [1 2 3 4] :invalid + "12" :invalid + "123" (into [] "123") + "1234" :invalid] ;; alt - not inside a sequence (h/alt [:number (h/fn int?)] - [:sequence (h/cat (h/fn string?))]) + [:sequence (h/vector-of (h/fn string?))]) [1 [:number 1] ["1"] [:sequence ["1"]] [1] :invalid @@ -457,4 +547,7 @@ (doseq [[model data-description-pairs] (partition 2 test-data)] (doseq [[data description] (partition 2 data-description-pairs)] (is (= [data (describe model data)] - [data description])))))) + [data description]))))) + + (is (thrown? #?(:clj Exception :cljs js/Object) + (describe (h/let [] (h/ref 'foo)) 'bar)))) diff --git a/test-resources/lib_tests/minimallist/generator_test.cljc b/test-resources/lib_tests/minimallist/generator_test.cljc new file mode 100644 index 00000000..af9f8706 --- /dev/null +++ b/test-resources/lib_tests/minimallist/generator_test.cljc @@ -0,0 +1,546 @@ +(ns minimallist.generator-test + (:require [clojure.test :refer [deftest testing is are]] + [clojure.test.check.generators :as tcg] + [clojure.string :as str] + [minimallist.core :refer [valid?]] + [minimallist.helper :as h] + [minimallist.util :as util] + [minimallist.generator :as mg :refer [gen fn-any? fn-int? fn-string? fn-char? + fn-symbol? fn-simple-symbol? fn-qualified-symbol? + fn-keyword? fn-simple-keyword? fn-qualified-keyword?]])) + +(defn- path-test-visitor [] + ;; Testing using side effects. + ;; A little ugly, but good enough for tests. + (let [paths (atom [])] + (fn + ([] @paths) + ([model stack path] + (swap! paths conj path) + model)))) + +(deftest postwalk-visit-order-test + (are [model expected-paths] + (let [visitor (path-test-visitor)] + (mg/postwalk model visitor) ; Create side effects + (= (visitor) expected-paths)) ; Collect and compare the side effects + + (h/let ['leaf (h/fn int?) + 'tree (h/ref 'leaf)] + (h/ref 'tree)) + [[:bindings 'leaf] + [:bindings 'tree] + [:body] + []] + + (h/let ['root (h/let ['leaf (h/fn int?) + 'tree (h/ref 'leaf)] + (h/ref 'tree))] + (h/ref 'root)) + [[:bindings 'root :bindings 'leaf] + [:bindings 'root :bindings 'tree] + [:bindings 'root :body] + [:bindings 'root] + [:body] + []] + + (h/let ['leaf (h/fn int?) + 'root (h/let ['tree (h/ref 'leaf)] + (h/ref 'tree))] + (h/ref 'root)) + [[:bindings 'leaf] + [:bindings 'root :bindings 'tree] + [:bindings 'root :body] + [:bindings 'root] + [:body] + []] + + ; test of no visit more than once + (h/let ['leaf (h/fn int?) + 'tree (h/tuple (h/ref 'leaf) (h/ref 'leaf))] + (h/ref 'tree)) + [[:bindings 'leaf] + [:bindings 'tree :entries 0 :model] + [:bindings 'tree :entries 1 :model] + [:bindings 'tree] + [:body] + []] + + ; test of no visit more than once, infinite loop otherwise + (h/let ['leaf (h/fn int?) + 'tree (h/tuple (h/ref 'tree) (h/ref 'leaf))] + (h/ref 'tree)) + [[:bindings 'tree :entries 0 :model] + [:bindings 'leaf] + [:bindings 'tree :entries 1 :model] + [:bindings 'tree] + [:body] + []] + + #__)) + +(deftest assoc-leaf-distance-visitor-test + (are [model expected-walked-model] + (= (-> model + (mg/postwalk mg/assoc-leaf-distance-visitor) + (util/walk-map-dissoc :fn)) + expected-walked-model) + + ; Recursive data-structure impossible to generate + ; This one is trying to bring the generator function in an infinite loop. + (h/let ['loop (h/ref 'loop)] + (h/ref 'loop)) + {:type :let + :bindings {'loop {:type :ref + :key 'loop}} + :body {:type :ref + :key 'loop}} + + ; Recursive data-structure impossible to generate + (h/let ['leaf (h/fn int?) + 'tree (h/tuple (h/ref 'tree) (h/ref 'leaf))] + (h/ref 'tree)) + {:type :let + :bindings {'leaf {:type :fn + ::mg/leaf-distance 0} + 'tree {:type :sequence + :entries [{:model {:type :ref + :key 'tree}} + {:model {:type :ref + :key 'leaf + ::mg/leaf-distance 1}}]}} + :body {:type :ref + :key 'tree}} + + ; Recursive data-structure impossible to generate + (h/let ['rec-map (h/map [:a (h/fn int?)] + [:b (h/ref 'rec-map)])] + (h/ref 'rec-map)) + {:type :let + :bindings {'rec-map {:type :map + :entries [{:key :a + :model {:type :fn + ::mg/leaf-distance 0}} + {:key :b + :model {:type :ref + :key 'rec-map}}]}} + :body {:type :ref + :key 'rec-map}} + + ; Recursive data-structure which can be generated + (h/let ['leaf (h/fn int?) + 'tree (h/alt (h/ref 'tree) (h/ref 'leaf))] + (h/ref 'tree)) + {:type :let + :bindings {'leaf {:type :fn + ::mg/leaf-distance 0} + 'tree {:type :alt + :entries [{:model {:type :ref + :key 'tree}} + {:model {:type :ref + :key 'leaf + ::mg/leaf-distance 1}}] + ::mg/leaf-distance 2}} + :body {:type :ref + :key 'tree + ::mg/leaf-distance 3} + ::mg/leaf-distance 4} + + (h/let ['rec-map (h/map [:a (h/fn int?)] + [:b {:optional true} (h/ref 'rec-map)])] + (h/ref 'rec-map)) + {:type :let + :bindings {'rec-map {:type :map + :entries [{:key :a + :model {:type :fn + ::mg/leaf-distance 0}} + {:key :b + :optional true + :model {:type :ref + :key 'rec-map}}] + ::mg/leaf-distance 1}} + :body {:type :ref + :key 'rec-map + ::mg/leaf-distance 2} + ::mg/leaf-distance 3} + + #__)) + + +(deftest assoc-min-cost-visitor-test + (are [model expected-walked-model] + (= (-> model + (mg/postwalk mg/assoc-min-cost-visitor) + (util/walk-map-dissoc :fn)) + expected-walked-model) + + (h/tuple (h/fn int?) (h/fn string?)) + {:type :sequence + :entries [{:model {:type :fn + ::mg/min-cost 1}} + {:model {:type :fn + ::mg/min-cost 1}}] + ::mg/min-cost 3} + + (h/cat (h/fn int?) (h/fn string?)) + {:type :cat + :entries [{:model {:type :fn + ::mg/min-cost 1}} + {:model {:type :fn + ::mg/min-cost 1}}] + ::mg/min-cost 3} + + (h/in-vector (h/cat (h/fn int?) (h/fn string?))) + {:type :cat + :coll-type :vector + :entries [{:model {:type :fn + ::mg/min-cost 1}} + {:model {:type :fn + ::mg/min-cost 1}}] + ::mg/min-cost 3} + + (h/not-inlined (h/cat (h/fn int?) (h/fn string?))) + {:type :cat + :inlined false + :entries [{:model {:type :fn + ::mg/min-cost 1}} + {:model {:type :fn + ::mg/min-cost 1}}] + ::mg/min-cost 3} + + (h/map [:a (h/fn int?)] + [:b {:optional true} (h/fn int?)]) + {:type :map + :entries [{:key :a + :model {:type :fn + ::mg/min-cost 1}} + {:key :b + :optional true + :model {:type :fn + ::mg/min-cost 1}}] + ::mg/min-cost 2} + + (h/map-of (h/vector (h/fn keyword?) (h/fn int?))) + {:type :map-of + :entry-model {:type :sequence + :coll-type :vector + :entries [{:model {:type :fn + ::mg/min-cost 1}} + {:model {:type :fn + ::mg/min-cost 1}}] + ::mg/min-cost 3} + ::mg/min-cost 1} + + (-> (h/map-of (h/vector (h/fn keyword?) (h/fn int?))) + (h/with-count (h/enum #{3 4}))) + {:type :map-of + :entry-model {:type :sequence + :coll-type :vector + :entries [{:model {:type :fn + ::mg/min-cost 1}} + {:model {:type :fn + ::mg/min-cost 1}}] + ::mg/min-cost 3} + :count-model {:type :enum + :values #{3 4}} + ::mg/min-cost 7} + + (h/set-of (h/fn any?)) + {:type :set-of + :elements-model {:type :fn + ::mg/min-cost 1} + ::mg/min-cost 1} + + (-> (h/set-of (h/fn any?)) + (h/with-count (h/val 3))) + {:type :set-of + :elements-model {:type :fn + ::mg/min-cost 1} + :count-model {:type :enum + :values #{3}} + ::mg/min-cost 4} + + (h/let ['foo (-> (h/set-of (h/fn int?)) + (h/with-count (h/val 3)))] + (h/ref 'foo)) + {:type :let + :bindings {'foo {:type :set-of + :count-model {:type :enum + :values #{3}} + :elements-model {:type :fn + ::mg/min-cost 1} + ::mg/min-cost 4}} + :body {:type :ref + :key 'foo + ::mg/min-cost 4} + ::mg/min-cost 4} + + #__)) + +(deftest budget-split-gen-test + (is (every? (fn [[a b c]] + (and (<= 0 a 5) + (<= 5 b 10) + (<= 10 c 15))) + (-> (#'mg/budget-split-gen 20.0 [0 5 10]) + tcg/sample))) + (is (every? #(= % [5 10 10]) + (-> (#'mg/budget-split-gen 20.0 [5 10 10]) + tcg/sample))) + (is (every? empty? + (-> (#'mg/budget-split-gen 10.0 []) + tcg/sample)))) + +(comment + ;; For occasional hand testing + + (tcg/sample (gen (-> (h/set-of fn-any?) + (h/with-count (h/enum #{1 2 3 10})) + (h/with-condition (h/fn (comp #{1 2 3} count)))))) + + (tcg/sample (gen (h/map-of (h/vector fn-int? fn-simple-symbol?)))) + + (tcg/sample (gen (-> (h/map [:a fn-int?]) + (h/with-optional-entries [:b fn-string?])))) + + (tcg/sample (gen (h/sequence-of fn-int?))) + + (tcg/sample (gen (h/tuple fn-int? fn-string?))) + + (tcg/sample (gen (h/cat fn-int? fn-string?))) + + (tcg/sample (gen (h/repeat 2 3 fn-int?))) + + (tcg/sample (gen (h/repeat 2 3 (h/cat fn-int? fn-string?)))) + + (tcg/sample (gen (h/let ['int? fn-int? + 'string? fn-string? + 'int-string? (h/cat (h/ref 'int?) (h/ref 'string?))] + (h/repeat 2 3 (h/ref 'int-string?))))) + + (tcg/sample (gen (-> (h/set-of fn-int?) + (h/with-condition (h/fn (fn [coll] + (or (empty? coll) + (some even? coll)))))))) + + (tcg/sample (gen (-> (h/set-of fn-any?) + (h/with-count (h/enum #{1 2 3 10})) + (h/with-condition (h/fn (comp #{1 2 3} count)))))) + + (tcg/sample (gen (h/let ['node (h/set-of (h/ref 'node))] + (h/ref 'node)))) + + (tcg/sample (gen (h/let ['node (h/map-of (h/vector fn-int? (h/ref 'node)))] + (h/ref 'node)) 50)) + + (tcg/sample (gen (h/let ['node (h/map-of (h/vector fn-keyword? (h/ref 'node)))] + (h/ref 'node)) 100) 1) + + (tcg/sample (gen (h/map [:a fn-int?]))) + + (tcg/sample (gen (-> (h/map [:a fn-int?]) + (h/with-optional-entries [:b fn-string?])))) + + (tcg/sample (gen (h/cat (h/vector-of fn-int?) + (h/vector-of fn-int?)) 20)) + + (tcg/sample (gen (h/repeat 5 10 fn-int?))) + + (tcg/sample (gen fn-symbol?)) + (tcg/sample (gen fn-simple-symbol?)) + (tcg/sample (gen fn-qualified-symbol?)) + + (tcg/sample (gen fn-keyword?)) + (tcg/sample (gen fn-simple-keyword?)) + (tcg/sample (gen fn-qualified-keyword?)) + + (tcg/sample (gen (-> (h/cat (h/char-cat "good") + (h/val \space) + (h/alt (h/char-cat "morning") + (h/char-cat "afternoon") + (h/repeat 3 10 (h/char-set "#?!@_*+%")))) + (h/in-string))) + 100) + + + #__) + +(deftest gen-test + (let [model fn-string?] + (is (every? (partial valid? model) + (tcg/sample (gen model))))) + + (let [model (h/enum #{:1 2 "3"})] + (is (every? (partial valid? model) + (tcg/sample (gen model))))) + + (let [model (-> (h/set-of fn-int?) + (h/with-condition (h/fn (fn [coll] + (or (empty? coll) + (some even? coll))))))] + (is (every? (partial valid? model) + (tcg/sample (gen model))))) + + (let [model (-> (h/set-of fn-any?) + (h/with-count (h/enum #{1 2 3 10})) + (h/with-condition (h/fn (comp #{1 2 3} count))))] + (is (every? (partial valid? model) + (tcg/sample (gen model))))) + + (let [model (h/map-of (h/vector fn-int? fn-string?))] + (is (every? (partial valid? model) + (tcg/sample (gen model))))) + + (let [model (-> (h/map [:a fn-int?]) + (h/with-optional-entries [:b fn-string?]) + (h/with-entries [:c fn-int?]) + (h/with-optional-entries [:d fn-string?])) + sample (tcg/sample (gen model) 100)] + (is (and (every? (partial valid? model) sample) + (every? (fn [element] (contains? element :a)) sample) + (some (fn [element] (contains? element :b)) sample) + (some (fn [element] (not (contains? element :b))) sample) + (every? (fn [element] (contains? element :c)) sample) + (some (fn [element] (contains? element :d)) sample) + (some (fn [element] (not (contains? element :d))) sample)))) + + (let [model (h/sequence-of fn-int?)] + (is (every? (partial valid? model) + (tcg/sample (gen model))))) + + (let [model (h/tuple fn-int? fn-string?) + sample (tcg/sample (gen model) 100)] + (is (and (every? (partial valid? model) sample) + (some list? sample) + (some vector? sample)))) + + (let [model (h/list fn-int? fn-string?) + sample (tcg/sample (gen model))] + (is (and (every? (partial valid? model) sample) + (every? list? sample)))) + + (let [model (h/vector fn-int? fn-string?) + sample (tcg/sample (gen model))] + (is (and (every? (partial valid? model) sample) + (every? vector? sample)))) + + (let [model (h/string-tuple fn-char? fn-char?) + sample (tcg/sample (gen model))] + (is (and (every? (partial valid? model) sample) + (every? string? sample)))) + + (let [model (h/in-list (h/cat fn-int? fn-string?)) + sample (tcg/sample (gen model))] + (is (and (every? (partial valid? model) sample) + (every? list? sample)))) + + (let [model (h/in-vector (h/cat fn-int? fn-string?)) + sample (tcg/sample (gen model))] + (is (and (every? (partial valid? model) sample) + (every? vector? sample)))) + + (let [model (h/in-string (h/cat fn-char? fn-char?)) + sample (tcg/sample (gen model))] + (is (and (every? (partial valid? model) sample) + (every? string? sample)))) + + (let [model (h/alt fn-int? fn-string?)] + (is (every? (partial valid? model) + (tcg/sample (gen model))))) + + (let [model (h/cat fn-int? fn-string?)] + (is (every? (partial valid? model) + (tcg/sample (gen model))))) + + (let [model (h/repeat 2 3 fn-int?)] + (is (every? (partial valid? model) + (tcg/sample (gen model))))) + + (let [model (h/repeat 2 3 (h/cat fn-int? fn-string?))] + (is (every? (partial valid? model) + (tcg/sample (gen model))))) + + (let [model (h/not-inlined (h/cat fn-int?))] + (is (every? (partial valid? model) + (tcg/sample (gen model))))) + + (let [model (h/not-inlined (h/repeat 1 2 fn-int?))] + (is (every? (partial valid? model) + (tcg/sample (gen model))))) + + (let [model (h/let ['int? fn-int? + 'string? fn-string? + 'int-string? (h/cat (h/ref 'int?) (h/ref 'string?))] + (h/repeat 2 3 (h/ref 'int-string?)))] + (is (every? (partial valid? model) + (tcg/sample (gen model))))) + + ;; Budget-based limit on model choice. + (let [model (h/let ['tree (h/alt [:leaf fn-int?] + [:branch (h/vector (h/ref 'tree) + (h/ref 'tree))])] + (h/ref 'tree))] + (is (every? (partial valid? model) + (tcg/sample (gen model))))) + + ;; Budget-based limit on variable set size. + (let [model (h/let ['node (h/set-of (h/ref 'node))] + (h/ref 'node))] + (is (every? (partial valid? model) + (tcg/sample (gen model))))) + + ;; Budget-based limit on variable sequence size. + (let [model (h/let ['node (h/vector-of (h/ref 'node))] + (h/ref 'node))] + (is (every? (partial valid? model) + (tcg/sample (gen model))))) + + ;; Budget-based limit on variable map size. + (let [model (h/let ['node (h/map-of (h/vector fn-int? (h/ref 'node)))] + (h/ref 'node))] + (is (every? (partial valid? model) + (tcg/sample (gen model))))) + + ;; Budget-based limit on optional entries in a map. + (let [model (h/let ['node (-> (h/map [:a fn-int?]) + (h/with-optional-entries [:x (h/ref 'node)] + [:y (h/ref 'node)] + [:z (h/ref 'node)]))] + (h/ref 'node))] + (is (every? (partial valid? model) + (tcg/sample (gen model))))) + + ;;; Budget-based limit on number of occurrences in a repeat. + ;(let [model (h/let ['node (h/repeat 0 1 (h/ref 'node))] + ; (h/ref 'node))] + ; (is (every? (partial valid? model) + ; (tcg/sample (gen model))))) + + ;; Model impossible to generate. + (let [model (h/let ['node (h/map [:a (h/ref 'node)])] + (h/ref 'node))] + (is (thrown? #?(:clj Exception :cljs js/Object) (tcg/sample (gen model))))) + + ;; Model impossible to generate. + (let [model (h/let ['node (h/tuple (h/ref 'node))] + (h/ref 'node))] + (is (thrown? #?(:clj Exception :cljs js/Object) (tcg/sample (gen model))))) + + ;; Model impossible to generate. + (let [model (h/let ['node (h/cat (h/ref 'node))] + (h/ref 'node))] + (is (thrown? #?(:clj Exception :cljs js/Object) (tcg/sample (gen model))))) + + ;; Model impossible to generate. + (let [model (h/let ['node (h/cat (h/ref 'node))] + (h/ref 'node))] + (is (thrown? #?(:clj Exception :cljs js/Object) (tcg/sample (gen model))))) + + (let [model (h/let ['node (h/repeat 1 2 (h/ref 'node))] + (h/ref 'node))] + (is (thrown? #?(:clj Exception :cljs js/Object) (tcg/sample (gen model)))))) + +;; TODO: [later] reuse the cat-ipsum model for parsing the output. + +;; TODO: in the :alt node, introduce a property :occurrence for the generator. +;; TODO: generate models, use them to generate data, should not stack overflow. diff --git a/test-resources/lib_tests/minimallist/util_test.cljc b/test-resources/lib_tests/minimallist/util_test.cljc new file mode 100644 index 00000000..3a0fbd0f --- /dev/null +++ b/test-resources/lib_tests/minimallist/util_test.cljc @@ -0,0 +1,53 @@ +(ns minimallist.util-test + (:require [clojure.test :refer [deftest testing is are]] + [minimallist.util :as util] + [minimallist.helper :as h])) + +(deftest reduce-update-test + (let [m {:a 1 + :b 5} + f (fn [acc elm] + (let [elm10 (* elm 10)] + [(conj acc elm10) elm10]))] + (is (= (-> [[] m] + (util/reduce-update :a f) + (util/reduce-update :b f)) + [[10 50] {:a 10, :b 50}])))) + +(deftest reduce-update-in-test + (let [m {:a {:x 1, :y 2} + :b [3 4 5]} + f (fn [acc elm] + (let [elm10 (* elm 10)] + [(conj acc elm10) elm10]))] + (is (= (-> [[] m] + (util/reduce-update-in [:a :x] f) + (util/reduce-update-in [:b 2] f)) + [[10 50] {:a {:x 10, :y 2}, :b [3 4 50]}])))) + +(deftest reduce-mapv + (let [m {:a {:x 1, :y 2} + :b [3 4 5]} + f (fn [acc elm] + (let [elm10 (* elm 10)] + [(conj acc elm10) elm10]))] + (is (= (util/reduce-update [[] m] :b (partial util/reduce-mapv f)) + [[30 40 50] {:a {:x 1, :y 2}, :b [30 40 50]}])))) + +(deftest iterate-while-different-test + (let [inc-up-to-10 (fn [x] (cond-> x (< x 10) inc))] + (is (= (util/iterate-while-different inc-up-to-10 0 0) 0)) + (is (= (util/iterate-while-different inc-up-to-10 0 5) 5)) + (is (= (util/iterate-while-different inc-up-to-10 0 10) 10)) + (is (= (util/iterate-while-different inc-up-to-10 0 15) 10)) + + (is (= (util/iterate-while-different inc-up-to-10 7 2) 9)) + (is (= (util/iterate-while-different inc-up-to-10 7 3) 10)) + (is (= (util/iterate-while-different inc-up-to-10 7 4) 10)) + + (is (= (util/iterate-while-different inc-up-to-10 12 0) 12)) + (is (= (util/iterate-while-different inc-up-to-10 12 3) 12)) + + (is (= (util/iterate-while-different inc-up-to-10 0 ##Inf) 10)) + (is (= (util/iterate-while-different inc-up-to-10 10 ##Inf) 10)) + (is (= (util/iterate-while-different inc-up-to-10 15 ##Inf) 15)))) diff --git a/test-resources/lib_tests/slingshot/slingshot_test.clj b/test-resources/lib_tests/slingshot/slingshot_test.clj index 09938332..f787a862 100644 --- a/test-resources/lib_tests/slingshot/slingshot_test.clj +++ b/test-resources/lib_tests/slingshot/slingshot_test.clj @@ -74,18 +74,19 @@ (mega-try (throw+ exception-1)) (mega-try (throw exception-1)) (try (throw+ exception-1) - (catch Exception e [:class-exception e])) + (catch Exception e [:class-exception e])) (try (throw exception-1) - (catch Exception e [:class-exception e]))))) + (catch Exception e [:class-exception e]))))) (testing "IllegalArgumentException thrown by clojure/core" (is (= :class-iae (first (mega-try (str/replace "foo" 1 1))))))) (testing "catch by java class generically" (is (= [:class-string "fail"] (mega-try (throw+ "fail"))))) + ;; BB-TEST-PATCH: bb has different record internals #_(testing "catch by clojure record type" - (is (= [:class-exception-record exception-record-1] - (mega-try (throw+ exception-record-1))))) + (is (= [:class-exception-record exception-record-1] + (mega-try (throw+ exception-record-1))))) (testing "catch by key is present" (is (= [:key-is-present #{:a-key}] (mega-try (throw+ #{:a-key}))))) diff --git a/test-resources/lib_tests/slingshot/support_test.clj b/test-resources/lib_tests/slingshot/support_test.clj index 12d2c142..9618bd73 100644 --- a/test-resources/lib_tests/slingshot/support_test.clj +++ b/test-resources/lib_tests/slingshot/support_test.clj @@ -46,9 +46,11 @@ (defn stack-trace-fn [] (stack-trace)) +;; BB-TEST-PATCH: Returns jdk.internal.reflect.DelegatingMethodAccessorImpl +;; instead of what's expected #_(deftest test-stack-trace (let [{:keys [methodName className]} (-> (stack-trace-fn) first bean)] - (is (= methodName "invoke")) + (is (.startsWith ^String methodName "invoke")) (is (re-find #"stack_trace_fn" className)))) (deftest test-resolve-local diff --git a/test-resources/lib_tests/version_clj/compare_test.cljc b/test-resources/lib_tests/version_clj/compare_test.cljc index c7ac75df..3eb0222f 100644 --- a/test-resources/lib_tests/version_clj/compare_test.cljc +++ b/test-resources/lib_tests/version_clj/compare_test.cljc @@ -70,4 +70,13 @@ ;; Some more zero-extension Tests "1-SNAPSHOT" "1.0-SNAPSHOT" 0 "1-alpha" "1-alpha0" 0 + + ;; Prefixed versions + "v1" "v1" 0 + "v1" "v2" -1 + "v1" "v1.1" -1 + "v1.1" "v1.2" -1 + "v1.1" "v2" -1 + "alpaca1.0" "bermuda1.0" -1 )) + diff --git a/test-resources/lib_tests/version_clj/split_test.cljc b/test-resources/lib_tests/version_clj/split_test.cljc index 51cac090..54ae6ab2 100644 --- a/test-resources/lib_tests/version_clj/split_test.cljc +++ b/test-resources/lib_tests/version_clj/split_test.cljc @@ -35,6 +35,10 @@ "0.5.0-alpha.1" [[0 5 0] ["alpha" 1]] "0.5.0-alpha.1" [[0 5 0] ["alpha" 1]] "0.0.3-alpha.8+oryOS.15" [[0 0 3] ["alpha" [8 "+oryos"] 15]] + "v1" [["v" 1]] + "v1.1" [["v" [1 1]]] + "ver1" [["ver" 1]] + "ver1.1" [["ver" [1 1]]] )) (deftest t-split-without-qualifiers diff --git a/test-resources/lib_tests/version_clj/via_use_test.clj b/test-resources/lib_tests/version_clj/via_use_test.clj index f75fa6bd..0d4e7526 100644 --- a/test-resources/lib_tests/version_clj/via_use_test.clj +++ b/test-resources/lib_tests/version_clj/via_use_test.clj @@ -6,6 +6,7 @@ (use 'version-clj.core) +;; BB-TEST-PATCH: This test doesn't exist upstream (deftest sanity-test (is (= [[1 0 0] ["snapshot"]] (version->seq "1.0.0-SNAPSHOT"))) (is (= 0 (version-compare "1.0" "1.0.0")))