Convert 10 test libs using add-libtest
Also improved add-libtest to only require maven artifact and rely on clojars for getting git-url most of the time
This commit is contained in:
parent
c0588be686
commit
d5b3f0f4f6
26 changed files with 1482 additions and 141 deletions
10
deps.edn
10
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"}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
23
test-resources/lib_tests/aero/lumo_test.cljs
Normal file
23
test-resources/lib_tests/aero/lumo_test.cljs
Normal file
|
|
@ -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))))))
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)}}
|
||||
|
|
|
|||
121
test-resources/lib_tests/bond/assertions_test.clj
Normal file
121
test-resources/lib_tests/bond/assertions_test.clj
Normal file
|
|
@ -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 [])))))
|
||||
109
test-resources/lib_tests/bond/james_test.clj
Normal file
109
test-resources/lib_tests/bond/james_test.clj
Normal file
|
|
@ -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))))))
|
||||
35
test-resources/lib_tests/bond/target_data.clj
Normal file
35
test-resources/lib_tests/bond/target_data.clj
Normal file
|
|
@ -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)))
|
||||
|
|
@ -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))
|
||||
|
|
|
|||
16
test-resources/lib_tests/camel_snake_kebab/extras_test.cljc
Normal file
16
test-resources/lib_tests/camel_snake_kebab/extras_test.cljc
Normal file
|
|
@ -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"}]}))
|
||||
|
|
@ -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")))
|
||||
10
test-resources/lib_tests/camel_snake_kebab/test_runner.cljs
Normal file
10
test-resources/lib_tests/camel_snake_kebab/test_runner.cljs
Normal file
|
|
@ -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)
|
||||
|
|
@ -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)))))
|
||||
(is (= sample-1 sample-2)))))
|
||||
|
|
|
|||
307
test-resources/lib_tests/com/stuartsierra/component_test.clj
Normal file
307
test-resources/lib_tests/com/stuartsierra/component_test.clj
Normal file
|
|
@ -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)))))
|
||||
|
|
@ -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))))
|
||||
5
test-resources/lib_tests/failjure/runner.cljs
Normal file
5
test-resources/lib_tests/failjure/runner.cljs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
(ns failjure.runner
|
||||
(:require [doo.runner :refer-macros [doo-tests]]
|
||||
[failjure.test-core]))
|
||||
|
||||
(doo-tests 'failjure.test-core)
|
||||
|
|
@ -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}))))
|
||||
|
||||
|
|
|
|||
|
|
@ -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))))
|
||||
|
|
|
|||
546
test-resources/lib_tests/minimallist/generator_test.cljc
Normal file
546
test-resources/lib_tests/minimallist/generator_test.cljc
Normal file
|
|
@ -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.
|
||||
53
test-resources/lib_tests/minimallist/util_test.cljc
Normal file
53
test-resources/lib_tests/minimallist/util_test.cljc
Normal file
|
|
@ -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))))
|
||||
|
|
@ -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})))))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
))
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")))
|
||||
|
|
|
|||
Loading…
Reference in a new issue