Created
April 23, 2026 13:00
-
-
Save igrishaev/7467d35ed7d04476dab688f0708d5eee to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (deftype MM [-form] | |
| Object | |
| (toString [_this] | |
| (str -form))) | |
| (defmacro mm [form] | |
| `(new MM '~form)) | |
| (deftype Mismatch [^String -message] | |
| Object | |
| (toString [this] | |
| -message)) | |
| (defn mismatch [template & args] | |
| (new Mismatch (apply format template args))) | |
| (defn mismatch? [x] | |
| (instance? Mismatch x)) | |
| (defmulti match | |
| (fn [a b] | |
| [(type a) (type b)])) | |
| (defn mism [a b] | |
| `(~'mismatch (~'actual ~a) (~'expected ~b))) | |
| (defmethod match [Object Object] | |
| [a b] | |
| (when-not (= a b) | |
| (mism a b)) | |
| #_ | |
| (or (= a b) | |
| (mismatch "%s <> %s" a b))) | |
| (defmethod match [clojure.lang.Counted Number] | |
| [a b] | |
| (= (cc/count a) b)) | |
| (defmethod match [String Number] | |
| [a b] | |
| (= (cc/count a) b)) | |
| (defmethod match [Object Class] | |
| [x cls] | |
| (instance? cls x)) | |
| (defmethod match [String java.util.regex.Pattern] | |
| [s re] | |
| (boolean (cc/re-find re s))) | |
| (defmethod match [Object clojure.lang.IFn] | |
| [x ifn] | |
| (boolean (ifn x))) | |
| (defmethod match [clojure.lang.PersistentVector clojure.lang.PersistentVector] | |
| [l1 l2] | |
| (let [iter1 (clojure.lang.RT/iter l1) | |
| iter2 (clojure.lang.RT/iter l2)] | |
| (loop [i 0 | |
| acc []] | |
| (let [next1? (.hasNext iter1) | |
| next2? (.hasNext iter2)] | |
| (case [next1? next2?] | |
| [false false] | |
| nil | |
| [true true] | |
| (let [v1 (.next iter1) | |
| v2 (.next iter2) | |
| result (match v1 v2)] | |
| (if result | |
| (conj acc (mism v1 v2)) | |
| (recur (inc i) (conj acc v1)))) | |
| t | |
| [true false] | |
| (mism (.next iter1) 'missing) | |
| [false true] | |
| (mism 'missing (.next iter2))))) | |
| #_ | |
| (loop [i 0] | |
| (let [next1? (.hasNext iter1) | |
| next2? (.hasNext iter2)] | |
| (case [next1? next2?] | |
| [false false] | |
| true | |
| [true true] | |
| (let [v1 (.next iter1) | |
| v2 (.next iter2) | |
| result (match v1 v2)] | |
| (cond | |
| (mismatch? result) | |
| (mismatch "items mismatch, index: %s, %s and %s, reason: %s" | |
| i v1 v2 result) | |
| (not result) | |
| (mismatch "items mismatch, index: %s, %s and %s" | |
| i v1 v2) | |
| :else | |
| (recur (inc i)))) | |
| [true false] | |
| (mismatch "the right collection has %s items, but the left one has more" | |
| i) | |
| [false true] | |
| (mismatch "the left collection has %s items, but the right one has more" | |
| i)))))) | |
| (defn space [n] | |
| (clojure.string/join (repeat n \space))) | |
| merge-with | |
| (defmethod match [clojure.lang.PersistentArrayMap clojure.lang.PersistentArrayMap] | |
| [m1 m2] | |
| (let [keys2 (vec (keys m2)) | |
| len (cc/count keys2)] | |
| (loop [i 0 | |
| path []] | |
| (if (= i len) | |
| true | |
| (let [k (nth keys2 i)] | |
| (if (contains? m1 k) | |
| (let [v1 (get m1 k) | |
| v2 (get m2 k) | |
| result | |
| (match v1 v2) | |
| path | |
| (conj path k) | |
| lvl | |
| (cc/count path)] | |
| (cond | |
| (mismatch? result) | |
| (mismatch "items mismatch, path: %s%s%n-%s%n-%s%s, %nreason: %s" | |
| path | |
| (space (* i 2 lvl)) v1 | |
| (space (* i 2 lvl)) v2 | |
| result) | |
| (not result) | |
| (mismatch "items mismatch, path: %s, %s and %s" | |
| path v1 v2) | |
| :else | |
| (recur (inc i) path))) | |
| (mismatch "the left map doesn't have key %s" k))))))) | |
| (comment | |
| (defmethod assert-expr 'match? [msg form] | |
| `(let [[_# v1# v2#] ~form] | |
| (if (match v1# v2#) | |
| (do-report {:type :pass :message ~msg | |
| :expected '~form :actual :foo}) | |
| (do-report {:type :fail :message ~msg | |
| :expected '~form :actual :foo}))))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment