From 5555ea4ede9b7be3f2ab2ef7105264ec62bef680 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 12 Mar 2021 20:31:58 +0100 Subject: [PATCH] APersistentMap test --- src/babashka/impl/classes.clj | 1 + src/babashka/impl/proxy.clj | 19 +++++++++-- test/babashka/proxy_test.clj | 63 +++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 test/babashka/proxy_test.clj diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 1185bbb9..aea63a1e 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -253,6 +253,7 @@ :fields [clojure.lang.PersistentQueue] :instance-checks [clojure.lang.APersistentMap ;; for proxy + clojure.lang.AMapEntry ;; for proxy clojure.lang.Associative clojure.lang.Atom clojure.lang.Cons diff --git a/src/babashka/impl/proxy.clj b/src/babashka/impl/proxy.clj index 59bfec91..a859c53d 100644 --- a/src/babashka/impl/proxy.clj +++ b/src/babashka/impl/proxy.clj @@ -12,7 +12,22 @@ (case (.getName ^Class class) "clojure.lang.APersistentMap" (proxy [clojure.lang.APersistentMap] [] - (seq [] ((method-or-bust methods 'seq))) + (iterator [] (if-let [m (get methods 'iterator)] + (m) + (proxy-super iterator))) ;; TODO: should we call proxy-super as a fallback always? + (containsKey [k] (if-let [m (get methods 'containsKey)] + (m k) + (proxy-super containsKey k))) + (entryAt [k] ((method-or-bust methods 'entryAt) k)) (valAt ([k] ((method-or-bust methods 'valAt) k)) - ([k default] ((method-or-bust methods 'valAt) k default)))))) + ([k default] ((method-or-bust methods 'valAt) k default))) + (cons [v] ((method-or-bust methods 'cons) v)) + (count [] ((method-or-bust methods 'count))) + (assoc [k v] ((method-or-bust methods 'assoc) k v)) + (without [k] ((method-or-bust methods 'without) k)) + (seq [] ((method-or-bust methods 'seq)))) + "clojure.lang.AMapEntry" + (proxy [clojure.lang.AMapEntry] [] + (key [] ((method-or-bust methods 'key))) + (val [] ((method-or-bust methods 'val)))))) diff --git a/test/babashka/proxy_test.clj b/test/babashka/proxy_test.clj new file mode 100644 index 00000000..c59e0e71 --- /dev/null +++ b/test/babashka/proxy_test.clj @@ -0,0 +1,63 @@ +(ns babashka.proxy-test + (:require + [babashka.test-utils :as test-utils] + [clojure.edn :as edn] + [clojure.test :as test :refer [deftest is]])) + +(defn bb [& args] + (edn/read-string + {:readers *data-readers* + :eof nil} + (apply test-utils/bb nil (map str args)))) + +(def code + '(do + (defn auto-deref + "If value implements IDeref, deref it, otherwise return original." + [x] + (if (instance? clojure.lang.IDeref x) + @x + x)) + (defn proxy-deref-map + {:added "1.0"} + [m] + (proxy [clojure.lang.APersistentMap] + [] + (iterator [] + ::TODO) + (containsKey [k] (contains? m k)) + (entryAt [k] (when (contains? m k) (proxy [clojure.lang.AMapEntry] [] + (key [] k) + (val [] (auto-deref(get m k)))))) + (valAt ([k] (auto-deref (get m k))) + ([k default] (auto-deref (get m k default)))) + (cons [v] (proxy-deref-map (conj m v))) + (count [] (count m)) + (assoc [k v] (proxy-deref-map (assoc m k v))) + (without [k] (proxy-deref-map (dissoc m k))) + (seq [] (map (fn [[k v]](proxy [clojure.lang.AMapEntry] [] + (key [] k) + (val [] (auto-deref (get m k))))) m)))) + (let [m (proxy-deref-map + {:a (delay 1) + :b (delay 2) + :c 3})] + [(:a m) + (:b m) + (:c m) + (contains? m :c) + (find m :c) + (-> (conj m [:d (delay 5)]) + :d) + (count m) + (-> (assoc m :d (delay 5)) + :d) + (-> (dissoc m :a) + (contains? :a)) + (seq m)]))) + +(deftest APersistentMap-proxy-test + (is (= [1 2 3 true [:c 3] + 5 3 5 false + '([:a 1] [:b 2] [:c 3])] + (bb code))))