diff --git a/.clj-kondo/potemkin/potemkin/config.edn b/.clj-kondo/potemkin/potemkin/config.edn new file mode 100644 index 0000000..3f59f3e --- /dev/null +++ b/.clj-kondo/potemkin/potemkin/config.edn @@ -0,0 +1,62 @@ +{:lint-as {potemkin.collections/compile-if clojure.core/if + potemkin.collections/reify-map-type clojure.core/reify + potemkin.collections/def-map-type clj-kondo.lint-as/def-catch-all + potemkin.collections/def-derived-map clj-kondo.lint-as/def-catch-all + + potemkin.types/reify+ clojure.core/reify + potemkin.types/defprotocol+ clojure.core/defprotocol + potemkin.types/deftype+ clojure.core/deftype + potemkin.types/defrecord+ clojure.core/defrecord + potemkin.types/definterface+ clojure.core/defprotocol + potemkin.types/extend-protocol+ clojure.core/extend-protocol + potemkin.types/def-abstract-type clj-kondo.lint-as/def-catch-all + + potemkin.utils/doit clojure.core/doseq + potemkin.utils/doary clojure.core/doseq + potemkin.utils/condp-case clojure.core/condp + potemkin.utils/fast-bound-fn clojure.core/bound-fn + + potemkin.walk/prewalk clojure.walk/prewalk + potemkin.walk/postwalk clojure.walk/postwalk + potemkin.walk/walk clojure.walk/walk + + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;;;; top-level from import-vars + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + ;; Have hooks + ;;potemkin/import-fn potemkin.namespaces/import-fn + ;;potemkin/import-macro potemkin.namespaces/import-macro + ;;potemkin/import-def potemkin.namespaces/import-def + + ;; Internal, not transitive + ;;potemkin/unify-gensyms potemkin.macros/unify-gensyms + ;;potemkin/normalize-gensyms potemkin.macros/normalize-gensyms + ;;potemkin/equivalent? potemkin.macros/equivalent? + + potemkin/condp-case clojure.core/condp + potemkin/doit potemkin.utils/doit + potemkin/doary potemkin.utils/doary + + potemkin/def-abstract-type clj-kondo.lint-as/def-catch-all + potemkin/reify+ clojure.core/reify + potemkin/defprotocol+ clojure.core/defprotocol + potemkin/deftype+ clojure.core/deftype + potemkin/defrecord+ clojure.core/defrecord + potemkin/definterface+ clojure.core/defprotocol + potemkin/extend-protocol+ clojure.core/extend-protocol + + potemkin/reify-map-type clojure.core/reify + potemkin/def-derived-map clj-kondo.lint-as/def-catch-all + potemkin/def-map-type clj-kondo.lint-as/def-catch-all} + + ;; leave import-vars alone, kondo special-cases it + :hooks {:macroexpand {#_#_potemkin.namespaces/import-vars potemkin.namespaces/import-vars + potemkin.namespaces/import-fn potemkin.namespaces/import-fn + potemkin.namespaces/import-macro potemkin.namespaces/import-macro + potemkin.namespaces/import-def potemkin.namespaces/import-def + + #_#_potemkin/import-vars potemkin.namespaces/import-vars + potemkin/import-fn potemkin.namespaces/import-fn + potemkin/import-macro potemkin.namespaces/import-macro + potemkin/import-def potemkin.namespaces/import-def}}} diff --git a/.clj-kondo/potemkin/potemkin/potemkin/namespaces.clj b/.clj-kondo/potemkin/potemkin/potemkin/namespaces.clj new file mode 100644 index 0000000..a247af5 --- /dev/null +++ b/.clj-kondo/potemkin/potemkin/potemkin/namespaces.clj @@ -0,0 +1,56 @@ +(ns potemkin.namespaces + (:require [clj-kondo.hooks-api :as api])) + +(defn import-macro* + ([sym] + `(def ~(-> sym name symbol) ~sym)) + ([sym name] + `(def ~name ~sym))) + +(defmacro import-fn + ([sym] + (import-macro* sym)) + ([sym name] + (import-macro* sym name))) + +(defmacro import-macro + ([sym] + (import-macro* sym)) + ([sym name] + (import-macro* sym name))) + +(defmacro import-def + ([sym] + (import-macro* sym)) + ([sym name] + (import-macro* sym name))) + +#_ +(defmacro import-vars + "Imports a list of vars from other namespaces." + [& syms] + (let [unravel (fn unravel [x] + (if (sequential? x) + (->> x + rest + (mapcat unravel) + (map + #(symbol + (str (first x) + (when-let [n (namespace %)] + (str "." n))) + (name %)))) + [x])) + syms (mapcat unravel syms) + result `(do + ~@(map + (fn [sym] + (let [vr (resolve sym) + m (meta vr)] + (cond + (nil? vr) `(throw (ex-info (format "`%s` does not exist" '~sym) {})) + (:macro m) `(def ~(-> sym name symbol) ~sym) + (:arglists m) `(def ~(-> sym name symbol) ~sym) + :else `(def ~(-> sym name symbol) ~sym)))) + syms))] + result)) diff --git a/project.clj b/project.clj index 76e79cd..ff75f4f 100644 --- a/project.clj +++ b/project.clj @@ -11,7 +11,8 @@ :dependencies [[org.clojure/clojure "1.11.1"] [kelveden/clj-wiremock "1.8.0"] - [potemkin "0.4.6"]] + [potemkin "0.4.6"] + [camel-snake-kebab "0.4.2"]] :plugins [[lein-cloverage "1.2.3"] [lein-shell "0.5.0"] diff --git a/src/clj_wiremock_extras/near_misses.clj b/src/clj_wiremock_extras/near_misses.clj new file mode 100644 index 0000000..83b73be --- /dev/null +++ b/src/clj_wiremock_extras/near_misses.clj @@ -0,0 +1,19 @@ +(ns clj-wiremock-extras.near-misses + (:require [clj-http.client :as http] + [clj-wiremock.core :as wmk] + [clj-wiremock.server :as wmk-server] + [cheshire.core :as cheshire] + [camel-snake-kebab.core :as csk] + [camel-snake-kebab.extras :as csk-extras])) + +(defn near-misses + ([] + (near-misses (wmk/root-server))) + ([server] + (let [url (wmk-server/admin-url server "/requests/unmatched/near-misses")] + (->> url + (http/get) + (:body) + (cheshire/decode) + (csk-extras/transform-keys csk/->kebab-case-keyword) + (:near-misses))))) \ No newline at end of file diff --git a/test/clj_wiremock_extras/near_misses_test.clj b/test/clj_wiremock_extras/near_misses_test.clj new file mode 100644 index 0000000..58a9956 --- /dev/null +++ b/test/clj_wiremock_extras/near_misses_test.clj @@ -0,0 +1,55 @@ +(ns clj-wiremock-extras.near-misses-test + (:require + [clj-wiremock-extras.near-misses :refer [near-misses]] + [clj-wiremock.core :as wmk] + [freeport.core :refer [get-free-port!]] + [clojure.test :refer [deftest is testing use-fixtures]] + [clj-http.client :as http])) + +(def wiremock-port (get-free-port!)) +(def wiremock-url (str "http://localhost:" wiremock-port)) + +(use-fixtures :once + (partial wmk/wiremock-fixture [{:port wiremock-port}])) + +(def correct-path "/foo") +(def miss-path "/bar") + +(defn- http-get + [path] + (:status (http/get (str wiremock-url path) {:throw-exceptions false}))) + +(deftest near-misses-test + (testing "near misses returns empty list when no near misses" + (let [stub {:req [:GET "/foo"] + :res [200 {:body "OK"}]}] + + (wmk/with-stubs [stub] + (http-get correct-path) + (is (= [] (near-misses)))))) + + (testing "near misses returns values of a near miss when one occurs" + (let [stub {:req [:GET "/foo"] + :res [200 {:body "OK"}]}] + + (wmk/with-stubs [stub] + (http-get miss-path) + (let [misses (near-misses)] + (is (= 1 (count misses))) + (is (= "/bar" (get-in misses [0 :request :url]))) + (is (= "/foo" (get-in misses [0 :stub-mapping :request :url-path]))))))) + + (testing "near misses returns values of multiple near misses in descending order" + (let [stub {:req [:GET "/foo"] + :res [200 {:body "OK"}]}] + + (wmk/with-stubs [stub] + (http-get "/1") + (http-get correct-path) + (http-get "/3") + (let [misses (near-misses)] + (is (= 2 (count misses))) + (is (= "/foo" (get-in misses [0 :stub-mapping :request :url-path]))) + (is (= "/3" (get-in misses [0 :request :url]))) + (is (= "/foo" (get-in misses [1 :stub-mapping :request :url-path]))) + (is (= "/1" (get-in misses [1 :request :url]))))))))