From bf183a33a8951649333f8fa9437b370a4f7f76f9 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 18 Jun 2024 09:08:12 +0200 Subject: [PATCH] Add bytechannel + more tests (#1706) Co-authored-by: Jarppe --- src/babashka/impl/classes.clj | 4 + src/babashka/impl/proxy.clj | 12 ++ .../bytechannel_and_related_classes.bb | 22 ++++ .../proxy_inputstream_outputstream.bb | 111 ++++++++++++++++++ test/babashka/interop_test.clj | 6 + 5 files changed, 155 insertions(+) create mode 100644 test-resources/bytechannel_and_related_classes.bb create mode 100644 test-resources/proxy_inputstream_outputstream.bb diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj index 80d9b127..a2c3c8e1 100644 --- a/src/babashka/impl/classes.clj +++ b/src/babashka/impl/classes.clj @@ -372,8 +372,12 @@ java.nio.MappedByteBuffer java.nio.file.OpenOption java.nio.file.StandardOpenOption + java.nio.channels.ByteChannel + java.nio.channels.Channels java.nio.channels.FileChannel java.nio.channels.FileChannel$MapMode + java.nio.channels.ReadableByteChannel + java.nio.channels.WritableByteChannel java.nio.channels.ServerSocketChannel java.nio.channels.SocketChannel java.nio.charset.Charset diff --git a/src/babashka/impl/proxy.clj b/src/babashka/impl/proxy.clj index 7e4ad722..665be140 100644 --- a/src/babashka/impl/proxy.clj +++ b/src/babashka/impl/proxy.clj @@ -79,6 +79,18 @@ (handle [sig] ((method-or-bust methods 'handle) this sig))) + ["java.io.InputStream" #{}] + (proxy [java.io.InputStream] [] + (available [] ((method-or-bust methods 'available) this)) + (close [] ((method-or-bust methods 'close) this)) + (read + ([] + ((method-or-bust methods 'read) this)) + ([bs] + ((method-or-bust methods 'read) this bs)) + ([bs off len] + ((method-or-bust methods 'read) this bs off len)))) + ["java.io.PipedInputStream" #{}] (proxy [java.io.PipedInputStream] [] (available [] ((method-or-bust methods 'available) this)) diff --git a/test-resources/bytechannel_and_related_classes.bb b/test-resources/bytechannel_and_related_classes.bb new file mode 100644 index 00000000..61b81991 --- /dev/null +++ b/test-resources/bytechannel_and_related_classes.bb @@ -0,0 +1,22 @@ +(ns bytechannel-and-related-classes + (:require [clojure.java.io :as io]) + (:import (java.nio.file OpenOption + StandardOpenOption) + (java.nio.channels ByteChannel + FileChannel + ReadableByteChannel + WritableByteChannel + Channels))) + +(when (and (let [ch (-> (.getBytes "Hello") + (java.io.ByteArrayInputStream.) + (Channels/newChannel))] + (instance? ReadableByteChannel ch)) + (let [ch (-> (java.io.ByteArrayOutputStream.) + (Channels/newChannel))] + (instance? WritableByteChannel ch)) + (with-open [ch (FileChannel/open (-> (io/file "README.md") + (.toPath)) + (into-array OpenOption [StandardOpenOption/READ]))] + (instance? ByteChannel ch))) + (println :success)) diff --git a/test-resources/proxy_inputstream_outputstream.bb b/test-resources/proxy_inputstream_outputstream.bb new file mode 100644 index 00000000..65b2c654 --- /dev/null +++ b/test-resources/proxy_inputstream_outputstream.bb @@ -0,0 +1,111 @@ +(ns proxy-inputstream-outputstream + (:import (java.io InputStream OutputStream) + (java.nio ByteBuffer))) + + +;; +;; Accept a ByteBuffer and return an InputStream that reads data from +;; the given buffer. +;; + + +(defn buffer->input-stream ^InputStream [^ByteBuffer buffer] + (proxy [InputStream] [] + (read + ([] + (if (.hasRemaining buffer) + (-> (.get buffer) + (bit-and 0xff)) + -1)) + ([b] + (.read this b 0 (alength b))) + ([b off len] + (if (.hasRemaining buffer) + (let [len (min (alength b) + (.remaining buffer))] + (.get buffer b off len) + len) + -1))))) + + +;; +;; Accept a ByteBuffer and return an OutputStream that writes into the +;; buffer. +;; + + +(defn buffer->output-stream ^OutputStream [^ByteBuffer buffer] + (proxy [OutputStream] [] + (write + ([v] + (if (bytes? v) + (.put buffer ^bytes v) + (.put buffer (-> (Integer. v) (.byteValue))))) + ([v off len] + (.put buffer ^bytes v 0 (alength v)))))) + + +;; +;; Tests: +;; + + +(defn read-byte-by-byte-test [] + (let [in (-> (.getBytes "Hello") + (ByteBuffer/wrap) + (buffer->input-stream))] + (and (= (.read in) (int \H)) + (= (.read in) (int \e)) + (= (.read in) (int \l)) + (= (.read in) (int \l)) + (= (.read in) (int \o)) + (= (.read in) -1)))) + +(defn read-byte-array [] + (let [in (-> (.getBytes "Hello") + (ByteBuffer/wrap) + (buffer->input-stream)) + buffer (byte-array 10) + len (.read in buffer)] + (and (= len 5) + (= (String. buffer 0 len) "Hello")))) + +(defn read-all [] + (let [in (-> (.getBytes "Hello") + (ByteBuffer/wrap) + (buffer->input-stream)) + data (.readAllBytes in)] + (= (String. data) "Hello"))) + +(defn write-byte-by-byte [] + (let [buffer (ByteBuffer/allocate 10) + out (buffer->output-stream buffer)] + (.write out (int \H)) + (.write out (int \e)) + (.write out (int \l)) + (.write out (int \l)) + (.write out (int \o)) + (= (String. (.array buffer) + 0 + (.position buffer)) + "Hello"))) + +(defn write-byte-array [] + (let [buffer (ByteBuffer/allocate 10) + out (buffer->output-stream buffer)] + (.write out (.getBytes "Hello")) + (= (String. (.array buffer) + 0 + (.position buffer)) + "Hello"))) + +;; +;; Run all tests: +;; + +(when (and (read-byte-by-byte-test) + (read-byte-array) + (read-all) + (write-byte-by-byte) + (write-byte-array)) + (println ":success")) diff --git a/test/babashka/interop_test.clj b/test/babashka/interop_test.clj index 0f537d86..59e88287 100644 --- a/test/babashka/interop_test.clj +++ b/test/babashka/interop_test.clj @@ -23,6 +23,12 @@ (deftest domain-sockets-test (is (= :success (bb nil (slurp "test-resources/domain_sockets.bb"))))) +(deftest byte-channels-test + (is (= :success (bb nil (slurp "test-resources/bytechannel_and_related_classes.bb"))))) + +(deftest proxy-inputstream-outputstream-test + (is (= :success (bb nil (slurp "test-resources/proxy_inputstream_outputstream.bb"))))) + (deftest map-entry-create-test (is (true? (bb nil "(= (first {1 2}) (clojure.lang.MapEntry. 1 2)