155 lines
5.2 KiB
Clojure
155 lines
5.2 KiB
Clojure
(ns babashka.reify-test
|
|
(:require
|
|
[babashka.test-utils :as test-utils]
|
|
[clojure.edn :as edn]
|
|
[clojure.string :as str]
|
|
[clojure.test :as test :refer [deftest is testing]]))
|
|
|
|
(defn bb [input & args]
|
|
(edn/read-string
|
|
{:readers *data-readers*
|
|
:eof nil}
|
|
(apply test-utils/bb (when (some? input) (str input)) (map str args))))
|
|
|
|
(deftest file-filter-test
|
|
(is (true? (bb nil "
|
|
(def filter-obj (reify java.io.FileFilter
|
|
(accept [this f] (prn (.getPath f)) true)))
|
|
(def filename-filter-obj
|
|
(reify java.io.FilenameFilter
|
|
(accept [this f name] (prn name) true)))
|
|
(def s1 (with-out-str (.listFiles (clojure.java.io/file \".\") filter-obj)))
|
|
(def s2 (with-out-str (.listFiles (clojure.java.io/file \".\") filename-filter-obj)))
|
|
(and (pos? (count s1)) (pos? (count s2)))"))))
|
|
|
|
(deftest reify-multiple-arities-test
|
|
(testing "ILookup"
|
|
(is (= ["->:foo" 10]
|
|
(bb nil "
|
|
(def m (reify clojure.lang.ILookup
|
|
(valAt [this x] (str \"->\" x))
|
|
(valAt [this x y] y)))
|
|
[(:foo m) (:foo m 10)]"))))
|
|
(testing "IFn"
|
|
(is (= [:yo :three :six :twelve :eighteen :nineteen 19]
|
|
(bb nil "
|
|
(def m (reify clojure.lang.IFn
|
|
(invoke [this] :yo)
|
|
(invoke [this _ _ _] :three)
|
|
(invoke [this _ _ _ _ _ _] :six)
|
|
(invoke [this _ _ _ _ _ _ _ _ _ _ _ _] :twelve)
|
|
(invoke [this _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _] :eighteen)
|
|
(invoke [this _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _] :nineteen)
|
|
(applyTo [this args] (last args))))
|
|
[
|
|
(m)
|
|
(m 1 2 3)
|
|
(m 1 2 3 4 5 6)
|
|
(m 1 2 3 4 5 6 1 2 3 4 5 6)
|
|
(m 1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 5 6)
|
|
(m 1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 5 6 1)
|
|
(apply m (range 20))
|
|
]")))))
|
|
|
|
(deftest reify-object
|
|
(testing "empty methods"
|
|
(is (str/starts-with?
|
|
(bb nil "
|
|
(str (reify Object))")
|
|
"babashka.impl.reify")))
|
|
(testing "toString"
|
|
(is (= ":foo"
|
|
(bb nil "
|
|
(def m (reify Object
|
|
(toString [_] (str :foo))))
|
|
(str m)
|
|
"))))
|
|
(testing "toString + protocol"
|
|
(is (= ":dude1:dude2"
|
|
(bb nil "
|
|
(defprotocol Dude (dude [_])) (def obj (reify Object (toString [_] (str :dude1)) Dude (dude [_] :dude2))) (str (str obj) (dude obj))
|
|
"))))
|
|
(testing "Hashcode still works when only overriding toString"
|
|
(is (number?
|
|
(bb nil "
|
|
(def m (reify Object
|
|
(toString [_] (str :foo))))
|
|
(hash m)
|
|
")))))
|
|
|
|
(deftest reify-file-visitor-test
|
|
(let [prog '(do (ns dude
|
|
(:import
|
|
[java.io File]
|
|
[java.nio.file FileSystems FileVisitor FileVisitResult Files Path])
|
|
(:gen-class))
|
|
|
|
(defn match-paths
|
|
"Match glob to paths under root and return a collection of Path objects"
|
|
[^File root glob]
|
|
(let [root-path (.toPath root)
|
|
matcher (.getPathMatcher (FileSystems/getDefault) (str "glob:" glob))
|
|
paths (volatile! [])
|
|
visitor (reify FileVisitor
|
|
(visitFile [_ path attrs]
|
|
(when (.matches matcher (.relativize root-path ^Path path))
|
|
(vswap! paths conj path))
|
|
FileVisitResult/CONTINUE)
|
|
(visitFileFailed [_ path ex]
|
|
FileVisitResult/CONTINUE)
|
|
(preVisitDirectory [_ _ _] FileVisitResult/CONTINUE)
|
|
(postVisitDirectory [_ _ _] FileVisitResult/CONTINUE))]
|
|
(Files/walkFileTree root-path visitor)
|
|
@paths))
|
|
|
|
[(count (match-paths (File. ".") "**"))
|
|
;; visitFileFailed is implemented
|
|
(count (match-paths (File. "xxx") "**"))])
|
|
[x y] (bb nil prog)]
|
|
(is (pos? x))
|
|
(is (zero? y))))
|
|
|
|
(deftest reify-default-method-test
|
|
(let [prog '(do (def iter (let [coll [:a :b :c] idx (volatile! -1)]
|
|
(reify java.util.Iterator (hasNext [_] (< @idx 2))
|
|
(next [_] (nth coll (vswap! idx inc))))))
|
|
(def res (volatile! []))
|
|
(vswap! res conj (.hasNext iter))
|
|
(vswap! res conj (.next iter))
|
|
(.forEachRemaining
|
|
iter (reify java.util.function.Consumer (accept [_ x] (vswap! res conj x))))
|
|
(= [true :a :b :c] @res))]
|
|
(is (true? (bb nil prog)))))
|
|
|
|
(deftest reify-multiple-interfaces-test
|
|
(testing "throws exception"
|
|
(is (thrown?
|
|
clojure.lang.ExceptionInfo
|
|
(bb nil "
|
|
(reify
|
|
java.lang.Object (toString [_] \"foo\")
|
|
clojure.lang.Seqable (seq [_] '(1 2 3)))")))))
|
|
|
|
(deftest reify-runnable-and-garbage-collection-test
|
|
(is (bb nil "
|
|
(def cleaner (java.lang.ref.Cleaner/create))
|
|
(def deleted? (atom false))
|
|
(defn make-cleanable-ref []
|
|
(let [obj (Object.)]
|
|
(.register cleaner obj
|
|
(reify java.lang.Runnable
|
|
(run [_]
|
|
(reset! deleted? true))))
|
|
nil))
|
|
(defn force-gc []
|
|
(let [t (atom (Object.))
|
|
wr (java.lang.ref.WeakReference. @t)]
|
|
(reset! t nil)
|
|
(while (or (.get wr)
|
|
(not @deleted?))
|
|
(System/gc)
|
|
(System/runFinalization))))
|
|
(make-cleanable-ref)
|
|
(force-gc)
|
|
@deleted?
|
|
")))
|