clj-commons / byte-streams

A Rosetta stone for JVM byte representations
417 stars 33 forks source link

Possible conversions returns impossible conversions #24

Closed jcf closed 7 years ago

jcf commented 7 years ago

Hello there!

I'm writing a generative test where I'd like to create objects that can be converted to a ByteArrayInputStream via byte-streams/convert and have come across something unexpected.

When I run the following code to convert a ByteArrayInputStream into each of the possible conversions I get a lot of IllegalArgumentExceptions for seqs, vectors and streams of types.

(doseq [c (byte-streams/possible-conversions java.io.ByteArrayInputStream)]
  (try
    (byte-streams/convert (java.io.ByteArrayInputStream. (.getBytes "a")) c)
    (catch IllegalArgumentException exception
      (println (.getMessage exception)))))
Don't know how to convert class java.io.ByteArrayInputStream into (stream-of java.nio.ByteBuffer)
Don't know how to convert class java.io.ByteArrayInputStream into (stream-of java.io.InputStream)
Don't know how to convert class java.io.ByteArrayInputStream into (stream-of java.lang.String)
Don't know how to convert class java.io.ByteArrayInputStream into (seq-of java.nio.ByteBuffer)
Don't know how to convert class java.io.ByteArrayInputStream into (seq-of java.io.InputStream)
Don't know how to convert class java.io.ByteArrayInputStream into (stream-of java.lang.CharSequence)
Don't know how to convert class java.io.ByteArrayInputStream into (seq-of java.nio.channels.ReadableByteChannel)
Don't know how to convert class java.io.ByteArrayInputStream into (stream-of java.io.InputStream)
Don't know how to convert class java.io.ByteArrayInputStream into (stream-of [B)
Don't know how to convert class java.io.ByteArrayInputStream into (stream-of io.netty.buffer.ByteBuf)
Don't know how to convert class java.io.ByteArrayInputStream into (seq-of java.nio.ByteBuffer)
Don't know how to convert class java.io.ByteArrayInputStream into (stream-of [B)
Don't know how to convert class java.io.ByteArrayInputStream into (stream-of java.lang.CharSequence)
Don't know how to convert class java.io.ByteArrayInputStream into (stream-of [B)
Don't know how to convert class java.io.ByteArrayInputStream into (seq-of java.lang.String)
Don't know how to convert class java.io.ByteArrayInputStream into (stream-of java.nio.channels.ReadableByteChannel)
Don't know how to convert class java.io.ByteArrayInputStream into (stream-of [B)
Don't know how to convert class java.io.ByteArrayInputStream into (stream-of java.io.Reader)
Don't know how to convert class java.io.ByteArrayInputStream into (stream-of [B)
Don't know how to convert class java.io.ByteArrayInputStream into (seq-of [B)
Don't know how to convert class java.io.ByteArrayInputStream into (seq-of java.lang.CharSequence)
Don't know how to convert class java.io.ByteArrayInputStream into (vector-of java.nio.ByteBuffer)
Don't know how to convert class java.io.ByteArrayInputStream into (stream-of java.nio.channels.ReadableByteChannel)
Don't know how to convert class java.io.ByteArrayInputStream into (seq-of java.io.InputStream)
Don't know how to convert class java.io.ByteArrayInputStream into (seq-of [B)
Don't know how to convert class java.io.ByteArrayInputStream into (seq-of io.netty.buffer.ByteBuf)
Don't know how to convert class java.io.ByteArrayInputStream into (seq-of java.lang.CharSequence)
Don't know how to convert class java.io.ByteArrayInputStream into (stream-of java.io.InputStream)
Don't know how to convert class java.io.ByteArrayInputStream into (seq-of java.nio.ByteBuffer)
Don't know how to convert class java.io.ByteArrayInputStream into (seq-of java.io.InputStream)
Don't know how to convert class java.io.ByteArrayInputStream into (seq-of java.lang.String)
Don't know how to convert class java.io.ByteArrayInputStream into (seq-of [B)
Don't know how to convert class java.io.ByteArrayInputStream into (seq-of java.nio.channels.ReadableByteChannel)
Don't know how to convert class java.io.ByteArrayInputStream into (seq-of [B)
Don't know how to convert class java.io.ByteArrayInputStream into (seq-of java.io.Reader)
Don't know how to convert class java.io.ByteArrayInputStream into (stream-of java.lang.String)
Don't know how to convert class java.io.ByteArrayInputStream into (seq-of [B)

Perhaps I'm misinterpreting the use of possible in byte-streams/possible-conversions? Is there a method of getting a list of conversions that will always work? Would filtering out the implicit conversions be enough?

The generator in question in case anyone's interested looks like this:

;; (require '[clojure.spec :as s])
;; (require '[clojure.spec.gen :as gen])

(defn- convertible?
  [x to]
  (some? (byte-streams/conversion-path x to)))

(s/def ::baisable
  (s/with-gen
    #(convertible? % ByteArrayInputStream)
    (fn []
      (->> (gen/tuple (gen/fmap #(ByteArrayInputStream. %) (gen/bytes))
                      (gen/elements (byte-streams/possible-conversions
                                     ByteArrayInputStream)))
           (gen/fmap (fn [[bais dest]] (byte-streams/convert bais dest)))))))
jcf commented 7 years ago

As I read this issue back to myself it really does seem like possible-conversions just doesn't do what I need, and that I should dig into the byte-streams.graph namespace to extract what I need.

jcf commented 7 years ago

Problem solved!

byte-streams/possible-conversions does some pretty printing, which means you don't get actual Types back.

Using the following modified version of possible-conversions works as expected:

(defn possible-conversions
  [src]
  (let [^byte_streams.graph.Type src (byte-streams.graph/type src)
        pred (cond
               (.type src)
               (partial #'byte-streams/converter src)

               (= 'seq (.wrapper src))
               #'byte-streams/seq-converter

               (= 'stream (.wrapper src))
               #'byte-streams/stream-converter)]
    (->> @byte-streams/conversions
         byte-streams.graph/possible-targets
         (filter pred))))

Sorry for the noise!