summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStuart Halloway <stu@thinkrelevance.com>2010-05-11 11:56:21 -0400
committerStuart Halloway <stu@thinkrelevance.com>2010-05-20 21:25:19 -0400
commitcd8fc7c11213fbe99355bc8d27455b01d8d50c82 (patch)
treeb50a7ba970a0f0af350266b64c0ad7fda366ac9e
parent4f729ba2432d8ffbe7c2f74f680b472e528cba4c (diff)
promote clojure.contrib.io to clojure.java.io (with api changes)
Signed-off-by: Stuart Halloway <stu@thinkrelevance.com>
-rw-r--r--src/clj/clojure/core.clj50
-rw-r--r--src/clj/clojure/java/io.clj429
-rw-r--r--test/clojure/test_clojure.clj1
-rw-r--r--test/clojure/test_clojure/java/io.clj185
-rw-r--r--test/clojure/test_clojure/metadata.clj3
5 files changed, 650 insertions, 18 deletions
diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj
index 4c466c56..0a2a39ae 100644
--- a/src/clj/clojure/core.clj
+++ b/src/clj/clojure/core.clj
@@ -3918,23 +3918,6 @@
{:added "1.0"}
[v] (instance? clojure.lang.Var v))
-(defn slurp
- "Reads the file named by f using the encoding enc into a string
- and returns it."
- {:added "1.0"}
- ([f] (slurp f (.name (java.nio.charset.Charset/defaultCharset))))
- ([^String f ^String enc]
- (with-open [r (new java.io.BufferedReader
- (new java.io.InputStreamReader
- (new java.io.FileInputStream f) enc))]
- (let [sb (new StringBuilder)]
- (loop [c (.read r)]
- (if (neg? c)
- (str sb)
- (do
- (.append sb (char c))
- (recur (.read r)))))))))
-
(defn subs
"Returns the substring of s beginning at start inclusive, and ending
at end (defaults to length of string), exclusive."
@@ -5338,6 +5321,39 @@
(let [s (seq coll)]
(clojure.core.protocols/internal-reduce s f val))))
+(require '[clojure.java.io :as jio])
+
+(defn- normalize-slurp-opts
+ [opts]
+ (if (string? (first opts))
+ (do
+ (println "WARNING: (slurp f enc) is deprecated, use (slurp f :encoding enc).")
+ [:encoding (first opts)])
+ opts))
+
+(defn slurp
+ "Reads the file named by f using the encoding enc into a string
+ and returns it."
+ {:added "1.0"}
+ ([f & opts]
+ (let [opts (normalize-slurp-opts opts)
+ sb (StringBuilder.)]
+ (with-open [#^java.io.Reader r (apply jio/reader f opts)]
+ (loop [c (.read r)]
+ (if (neg? c)
+ (str sb)
+ (do
+ (.append sb (char c))
+ (recur (.read r)))))))))
+
+(defn spit
+ "Opposite of slurp. Opens f with writer, writes content, then
+ closes f."
+ {:added "1.2"}
+ [f content & options]
+ (with-open [#^java.io.Writer w (apply jio/writer f options)]
+ (.write w content)))
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; futures (needs proxy);;;;;;;;;;;;;;;;;;
(defn future-call
"Takes a function of no args and yields a future object that will
diff --git a/src/clj/clojure/java/io.clj b/src/clj/clojure/java/io.clj
new file mode 100644
index 00000000..bed18bc9
--- /dev/null
+++ b/src/clj/clojure/java/io.clj
@@ -0,0 +1,429 @@
+; Copyright (c) Rich Hickey. All rights reserved.
+; The use and distribution terms for this software are covered by the
+; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
+; which can be found in the file epl-v10.html at the root of this distribution.
+; By using this software in any fashion, you are agreeing to be bound by
+; the terms of this license.
+; You must not remove this notice, or any other, from this software.
+
+(ns
+ ^{:author "Stuart Sierra, Chas Emerick, Stuart Halloway",
+ :doc "This file defines polymorphic I/O utility functions for Clojure."}
+ clojure.java.io
+ (:import
+ (java.io Reader InputStream InputStreamReader PushbackReader
+ BufferedReader File OutputStream
+ OutputStreamWriter BufferedWriter Writer
+ FileInputStream FileOutputStream ByteArrayOutputStream
+ StringReader ByteArrayInputStream
+ BufferedInputStream BufferedOutputStream
+ CharArrayReader Closeable)
+ (java.net URI URL MalformedURLException Socket)))
+
+(def
+ ^{:doc "Type object for a Java primitive byte array."
+ :private true
+ }
+ byte-array-type (class (make-array Byte/TYPE 0)))
+
+(def
+ ^{:doc "Type object for a Java primitive char array."
+ :private true}
+ char-array-type (class (make-array Character/TYPE 0)))
+
+(defprotocol ^{:added "1.2"} Coercions
+ "Coerce between various 'resource-namish' things."
+ (as-file [x] "Coerce argument to a file.")
+ (as-url [x] "Coerce argument to a URL."))
+
+(extend-protocol Coercions
+ nil
+ (as-file [_] nil)
+ (as-url [_] nil)
+
+ String
+ (as-file [s] (File. s))
+ (as-url [s] (URL. s))
+
+ File
+ (as-file [f] f)
+ (as-url [f] (.toURL f))
+
+ URL
+ (as-url [u] u)
+ (as-file [u]
+ (if (= "file" (.getProtocol u))
+ (as-file (.getPath u))
+ (throw (IllegalArgumentException. "Not a file: " u))))
+
+ URI
+ (as-url [u] (.toURL u))
+ (as-file [u] (as-file (as-url u))))
+
+(defprotocol IOFactory
+ (make-reader [x opts])
+ (make-writer [x opts])
+ (make-input-stream [x opts])
+ (make-output-stream [x opts]))
+
+(defn ^Reader reader
+ "Attempts to coerce its argument into an open java.io.Reader.
+ The default implementations of this protocol always return a
+ java.io.BufferedReader.
+
+ Default implementations are provided for Reader, BufferedReader,
+ InputStream, File, URI, URL, Socket, byte arrays, character arrays,
+ and String.
+
+ If argument is a String, it tries to resolve it first as a URI, then
+ as a local file name. URIs with a 'file' protocol are converted to
+ local file names.
+
+ Should be used inside with-open to ensure the Reader is properly
+ closed."
+ {:added "1.2"}
+ [x & opts]
+ (make-reader x (when opts (apply hash-map opts))))
+
+(defn ^Writer writer
+ "Attempts to coerce its argument into an open java.io.Writer.
+ The default implementations of this protocol always return a
+ java.io.BufferedWriter.
+
+ Default implementations are provided for Writer, BufferedWriter,
+ OutputStream, File, URI, URL, Socket, and String.
+
+ If the argument is a String, it tries to resolve it first as a URI, then
+ as a local file name. URIs with a 'file' protocol are converted to
+ local file names.
+
+ Should be used inside with-open to ensure the Writer is properly
+ closed."
+ {:added "1.2"}
+ [x & opts]
+ (make-writer x (when opts (apply hash-map opts))))
+
+(defn ^InputStream input-stream
+ "Attempts to coerce its argument into an open java.io.InputStream.
+ The default implementations of this protocol always return a
+ java.io.BufferedInputStream.
+
+ Default implementations are defined for OutputStream, File, URI, URL,
+ Socket, byte array, and String arguments.
+
+ If the argument is a String, it tries to resolve it first as a URI, then
+ as a local file name. URIs with a 'file' protocol are converted to
+ local file names.
+
+ Should be used inside with-open to ensure the InputStream is properly
+ closed."
+ {:added "1.2"}
+ [x & opts]
+ (make-input-stream x (when opts (apply hash-map opts))))
+
+(defn ^OutputStream output-stream
+ "Attempts to coerce its argument into an open java.io.OutputStream.
+ The default implementations of this protocol always return a
+ java.io.BufferedOutputStream.
+
+ Default implementations are defined for OutputStream, File, URI, URL,
+ Socket, and String arguments.
+
+ If the argument is a String, it tries to resolve it first as a URI, then
+ as a local file name. URIs with a 'file' protocol are converted to
+ local file names.
+
+ Should be used inside with-open to ensure the OutputStream is
+ properly closed."
+ {:added "1.2"}
+ [x & opts]
+ (make-output-stream x (when opts (apply hash-map opts))))
+
+(defn- ^Boolean append? [opts]
+ (boolean (:append opts)))
+
+(defn- ^String encoding [opts]
+ (or (:encoding opts) "UTF-8"))
+
+(defn- buffer-size [opts]
+ (or (:buffer-size opts) 1024))
+
+(def default-streams-impl
+ {:make-reader (fn [x opts] (make-reader (make-input-stream x opts) opts))
+ :make-writer (fn [x opts] (make-writer (make-output-stream x opts) opts))
+ :make-input-stream (fn [x opts]
+ (throw (IllegalArgumentException.
+ (str "Cannot open <" (pr-str x) "> as an InputStream."))))
+ :make-output-stream (fn [x opts]
+ (throw (IllegalArgumentException.
+ (str "Cannot open <" (pr-str x) "> as an OutputStream."))))})
+
+(defn- inputstream->reader
+ [^InputStream is opts]
+ (make-reader (InputStreamReader. is (encoding opts)) opts))
+
+(defn- outputstream->writer
+ [^OutputStream os opts]
+ (make-writer (OutputStreamWriter. os (encoding opts)) opts))
+
+(extend BufferedInputStream
+ IOFactory
+ (assoc default-streams-impl
+ :make-input-stream (fn [x opts] x)
+ :make-reader inputstream->reader))
+
+(extend InputStream
+ IOFactory
+ (assoc default-streams-impl
+ :make-input-stream (fn [x opts] (BufferedInputStream. x))
+ :make-reader inputstream->reader))
+
+(extend Reader
+ IOFactory
+ (assoc default-streams-impl
+ :make-reader (fn [x opts] (BufferedReader. x))))
+
+(extend BufferedReader
+ IOFactory
+ (assoc default-streams-impl
+ :make-reader (fn [x opts] x)))
+
+(extend Writer
+ IOFactory
+ (assoc default-streams-impl
+ :make-writer (fn [x opts] (BufferedWriter. x))))
+
+(extend BufferedWriter
+ IOFactory
+ (assoc default-streams-impl
+ :make-writer (fn [x opts] x)))
+
+(extend OutputStream
+ IOFactory
+ (assoc default-streams-impl
+ :make-output-stream (fn [x opts] (BufferedOutputStream. x))
+ :make-writer outputstream->writer))
+
+(extend BufferedOutputStream
+ IOFactory
+ (assoc default-streams-impl
+ :make-output-stream (fn [x opts] x)
+ :make-writer outputstream->writer))
+
+(extend File
+ IOFactory
+ (assoc default-streams-impl
+ :make-input-stream (fn [^File x opts] (make-input-stream (FileInputStream. x) opts))
+ :make-output-stream (fn [^File x opts] (make-output-stream (FileOutputStream. x (append? opts)) opts))))
+
+(extend URL
+ IOFactory
+ (assoc default-streams-impl
+ :make-input-stream (fn [^URL x opts]
+ (make-input-stream
+ (if (= "file" (.getProtocol x))
+ (FileInputStream. (.getPath x))
+ (.openStream x)) opts))
+ :make-output-stream (fn [^URL x opts]
+ (if (= "file" (.getProtocol x))
+ (make-output-stream (File. (.getPath x)) opts)
+ (throw (IllegalArgumentException. (str "Can not write to non-file URL <" x ">")))))))
+
+(extend URI
+ IOFactory
+ (assoc default-streams-impl
+ :make-input-stream (fn [^URI x opts] (make-input-stream (.toURL x) opts))
+ :make-output-stream (fn [^URI x opts] (make-output-stream (.toURL x) opts))))
+
+(extend String
+ IOFactory
+ (assoc default-streams-impl
+ :make-input-stream (fn [^String x opts]
+ (try
+ (make-input-stream (URL. x) opts)
+ (catch MalformedURLException e
+ (make-input-stream (File. x) opts))))
+ :make-output-stream (fn [^String x opts]
+ (try
+ (make-output-stream (URL. x) opts)
+ (catch MalformedURLException err
+ (make-output-stream (File. x) opts))))))
+
+(extend Socket
+ IOFactory
+ (assoc default-streams-impl
+ :make-input-stream (fn [^Socket x opts] (.getInputStream x))
+ :output-stream (fn [^Socket x opts] (output-stream (.getOutputStream x) opts))))
+
+(extend byte-array-type
+ IOFactory
+ (assoc default-streams-impl
+ :make-input-stream (fn [x opts] (make-input-stream (ByteArrayInputStream. x) opts))))
+
+(extend char-array-type
+ IOFactory
+ (assoc default-streams-impl
+ :make-reader (fn [x opts] (make-reader (CharArrayReader. x) opts))))
+
+(extend Object
+ IOFactory
+ default-streams-impl)
+
+(defmulti
+ #^{:doc "Internal helper for copy"
+ :private true
+ :arglists '([input output opts])}
+ do-copy
+ (fn [input output opts] [(type input) (type output)]))
+
+(defmethod do-copy [InputStream OutputStream] [#^InputStream input #^OutputStream output opts]
+ (let [buffer (make-array Byte/TYPE (buffer-size opts))]
+ (loop []
+ (let [size (.read input buffer)]
+ (when (pos? size)
+ (do (.write output buffer 0 size)
+ (recur)))))))
+
+(defmethod do-copy [InputStream Writer] [#^InputStream input #^Writer output opts]
+ (let [#^"[B" buffer (make-array Byte/TYPE (buffer-size opts))]
+ (loop []
+ (let [size (.read input buffer)]
+ (when (pos? size)
+ (let [chars (.toCharArray (String. buffer 0 size (encoding opts)))]
+ (do (.write output chars)
+ (recur))))))))
+
+(defmethod do-copy [InputStream File] [#^InputStream input #^File output opts]
+ (with-open [out (FileOutputStream. output)]
+ (do-copy input out opts)))
+
+(defmethod do-copy [Reader OutputStream] [#^Reader input #^OutputStream output opts]
+ (let [#^"[C" buffer (make-array Character/TYPE (buffer-size opts))]
+ (loop []
+ (let [size (.read input buffer)]
+ (when (pos? size)
+ (let [bytes (.getBytes (String. buffer 0 size) (encoding opts))]
+ (do (.write output bytes)
+ (recur))))))))
+
+(defmethod do-copy [Reader Writer] [#^Reader input #^Writer output opts]
+ (let [#^"[C" buffer (make-array Character/TYPE (buffer-size opts))]
+ (loop []
+ (let [size (.read input buffer)]
+ (when (pos? size)
+ (do (.write output buffer 0 size)
+ (recur)))))))
+
+(defmethod do-copy [Reader File] [#^Reader input #^File output opts]
+ (with-open [out (FileOutputStream. output)]
+ (do-copy input out opts)))
+
+(defmethod do-copy [File OutputStream] [#^File input #^OutputStream output opts]
+ (with-open [in (FileInputStream. input)]
+ (do-copy in output opts)))
+
+(defmethod do-copy [File Writer] [#^File input #^Writer output opts]
+ (with-open [in (FileInputStream. input)]
+ (do-copy in output opts)))
+
+(defmethod do-copy [File File] [#^File input #^File output opts]
+ (with-open [in (FileInputStream. input)
+ out (FileOutputStream. output)]
+ (do-copy in out opts)))
+
+(defmethod do-copy [String OutputStream] [#^String input #^OutputStream output opts]
+ (do-copy (StringReader. input) output opts))
+
+(defmethod do-copy [String Writer] [#^String input #^Writer output opts]
+ (do-copy (StringReader. input) output opts))
+
+(defmethod do-copy [String File] [#^String input #^File output opts]
+ (do-copy (StringReader. input) output opts))
+
+(defmethod do-copy [char-array-type OutputStream] [input #^OutputStream output opts]
+ (do-copy (CharArrayReader. input) output opts))
+
+(defmethod do-copy [char-array-type Writer] [input #^Writer output opts]
+ (do-copy (CharArrayReader. input) output opts))
+
+(defmethod do-copy [char-array-type File] [input #^File output opts]
+ (do-copy (CharArrayReader. input) output opts))
+
+(defmethod do-copy [byte-array-type OutputStream] [#^"[B" input #^OutputStream output opts]
+ (do-copy (ByteArrayInputStream. input) output opts))
+
+(defmethod do-copy [byte-array-type Writer] [#^"[B" input #^Writer output opts]
+ (do-copy (ByteArrayInputStream. input) output opts))
+
+(defmethod do-copy [byte-array-type File] [#^"[B" input #^Writer output opts]
+ (do-copy (ByteArrayInputStream. input) output opts))
+
+(defn copy
+ "Copies input to output. Returns nil or throws IOException.
+ Input may be an InputStream, Reader, File, byte[], or String.
+ Output may be an OutputStream, Writer, or File.
+
+ Options are key/value pairs and may be one of
+
+ :buffer-size buffer size to use, default is 1024.
+ :encoding encoding to use if converting between
+ byte and char streams.
+
+ Does not close any streams except those it opens itself
+ (on a File)."
+ {:added "1.2"}
+ [input output & opts]
+ (do-copy input output (when opts (apply hash-map opts))))
+
+(defn ^String as-relative-path
+ "Take an as-file-able thing and return a string if it is
+ a relative path, else IllegalArgumentException."
+ {:added "1.2"}
+ [x]
+ (let [^File f (as-file x)]
+ (if (.isAbsolute f)
+ (throw (IllegalArgumentException. (str f " is not a relative path")))
+ (.getPath f))))
+
+(defn ^File file
+ "Returns a java.io.File from string or file args."
+ {:added "1.2"}
+ ([arg]
+ (as-file arg))
+ ([parent child]
+ (File. ^File (as-file parent) ^String (as-relative-path child)))
+ ([parent child & more]
+ (reduce file (file parent child) more)))
+
+(defn delete-file
+ "Delete file f. Raise an exception if it fails unless silently is true."
+ {:added "1.2"}
+ [f & [silently]]
+ (or (.delete (file f))
+ silently
+ (throw (java.io.IOException. (str "Couldn't delete " f)))))
+
+(defn delete-file-recursively
+ "Delete file f. If it's a directory, recursively delete all its contents.
+ Raise an exception if any deletion fails unless silently is true."
+ {:added "1.2"}
+ [f & [silently]]
+ (let [f (file f)]
+ (if (.isDirectory f)
+ (doseq [child (.listFiles f)]
+ (delete-file-recursively child silently)))
+ (delete-file f silently)))
+
+(defn make-parents
+ "Create all parent directories of file. Pass extra args
+ as you would to file."
+ {:added "1.2"}
+ [f & more]
+ (.mkdirs (.getParentFile ^File (apply file f more))))
+
+(defn ^URL resource
+ "Returns the URL for a named resource. Use the context class loader
+ if no loader is specified."
+ {:added "1.2"}
+ ([n] (resource n (.getContextClassLoader (Thread/currentThread))))
+ ([n ^ClassLoader loader] (.getResource loader n)))
diff --git a/test/clojure/test_clojure.clj b/test/clojure/test_clojure.clj
index 9dd0bde2..9bde9009 100644
--- a/test/clojure/test_clojure.clj
+++ b/test/clojure/test_clojure.clj
@@ -57,6 +57,7 @@
:serialization
:rt
:repl
+ :java.io
])
(def test-namespaces
diff --git a/test/clojure/test_clojure/java/io.clj b/test/clojure/test_clojure/java/io.clj
new file mode 100644
index 00000000..b42d26db
--- /dev/null
+++ b/test/clojure/test_clojure/java/io.clj
@@ -0,0 +1,185 @@
+(ns clojure.test-clojure.java.io
+ (:use clojure.test clojure.java.io)
+ (:import (java.io File FileInputStream BufferedInputStream
+ FileOutputStream OutputStreamWriter InputStreamReader
+ ByteArrayInputStream ByteArrayOutputStream)
+ (java.net URL URI)))
+
+(defn temp-file
+ [prefix suffix]
+ (doto (File/createTempFile prefix suffix)
+ (.deleteOnExit)))
+
+(deftest test-spit-and-slurp
+ (let [f (temp-file "clojure.contrib" "text")]
+ (spit f "foobar")
+ (is (= "foobar" (slurp f)))
+ (spit f "foobar" :encoding "UTF-16")
+ (is (= "foobar" (slurp f :encoding "UTF-16")))
+ (testing "deprecated arity"
+ (is (=
+ "WARNING: (slurp f enc) is deprecated, use (slurp f :encoding enc).\n"
+ (with-out-str
+ (is (= "foobar" (slurp f "UTF-16")))))))))
+
+(deftest test-streams-defaults
+ (let [f (temp-file "clojure.contrib" "test-reader-writer")
+ content "testing"]
+ (try
+ (is (thrown? Exception (reader (Object.))))
+ (is (thrown? Exception (writer (Object.))))
+
+ (are [write-to read-from] (= content (do
+ (spit write-to content :encoding "UTF-8")
+ (slurp read-from :encoding "UTF-8")))
+ f f
+ (.getAbsolutePath f) (.getAbsolutePath f)
+ (.toURL f) (.toURL f)
+ (.toURI f) (.toURI f)
+ (FileOutputStream. f) (FileInputStream. f)
+ (OutputStreamWriter. (FileOutputStream. f) "UTF-8") (reader f :encoding "UTF-8")
+ f (FileInputStream. f)
+ (writer f :encoding "UTF-8") (InputStreamReader. (FileInputStream. f) "UTF-8"))
+
+ (is (= content (slurp (.getBytes content "UTF-8"))))
+ (is (= content (slurp (.toCharArray content))))
+ (finally
+ (.delete f)))))
+
+(defn bytes-should-equal [byte-array-1 byte-array-2 msg]
+ (is (= @#'clojure.java.io/byte-array-type (class byte-array-1) (class byte-array-2)) msg)
+ (is (= (into [] byte-array-1) (into [] byte-array-2)) msg))
+
+(defn data-fixture
+ "in memory fixture data for tests"
+ [encoding]
+ (let [bs (.getBytes "hello" encoding)
+ cs (.toCharArray "hello")
+ i (ByteArrayInputStream. bs)
+ r (InputStreamReader. i)
+ o (ByteArrayOutputStream.)
+ w (OutputStreamWriter. o)]
+ {:bs bs
+ :i i
+ :r r
+ :o o
+ :s "hello"
+ :cs cs
+ :w w}))
+
+(deftest test-copy
+ (dorun
+ (for [{:keys [in out flush] :as test}
+ [{:in :i :out :o}
+ {:in :i :out :w}
+ {:in :r :out :o}
+ {:in :r :out :w}
+ {:in :cs :out :o}
+ {:in :cs :out :w}
+ {:in :bs :out :o}
+ {:in :bs :out :w}]
+
+ opts
+ [{} {:buffer-size 256}]]
+ (let [{:keys [s o] :as d} (data-fixture "UTF-8")]
+ (apply copy (in d) (out d) (flatten (vec opts)))
+ #_(when (= out :w) (.flush (:w d)))
+ (.flush (out d))
+ (bytes-should-equal (.getBytes s "UTF-8")
+ (.toByteArray o)
+ (str "combination " test opts))))))
+
+(deftest test-copy-encodings
+ (testing "from inputstream UTF-16 to writer UTF-8"
+ (let [{:keys [i s o w bs]} (data-fixture "UTF-16")]
+ (copy i w :encoding "UTF-16")
+ (.flush w)
+ (bytes-should-equal (.getBytes s "UTF-8") (.toByteArray o) "")))
+ (testing "from reader UTF-8 to output-stream UTF-16"
+ (let [{:keys [r o s]} (data-fixture "UTF-8")]
+ (copy r o :encoding "UTF-16")
+ (bytes-should-equal (.getBytes s "UTF-16") (.toByteArray o) ""))))
+
+(deftest test-as-file
+ (are [result input] (= result (as-file input))
+ (File. "foo") "foo"
+ (File. "bar") (File. "bar")
+ (File. "baz") (URL. "file:baz")
+ (File. "quux") (URI. "file:quux")
+ nil nil))
+
+(deftest test-file
+ (are [result args] (= (File. result) (apply file args))
+ "foo" ["foo"]
+ "foo/bar" ["foo" "bar"]
+ "foo/bar/baz" ["foo" "bar" "baz"]))
+(deftest test-as-url
+ (are [file-part input] (= (URL. (str "file:" file-part)) (as-url input))
+ "foo" "file:foo"
+ "/foo" (File. "/foo")
+ "baz" (URL. "file:baz")
+ "quux" (URI. "file:quux"))
+ (is (nil? (as-url nil))))
+
+(deftest test-delete-file
+ (let [file (temp-file "test" "deletion")
+ not-file (File. (str (java.util.UUID/randomUUID)))]
+ (delete-file (.getAbsolutePath file))
+ (is (not (.exists file)))
+ (is (thrown? java.io.IOException (delete-file not-file)))
+ (is (= :silently (delete-file not-file :silently)))))
+
+(deftest test-as-relative-path
+ (testing "strings"
+ (is (= "foo" (as-relative-path "foo"))))
+ (testing "absolute path strings are forbidden"
+ (is (thrown? IllegalArgumentException (as-relative-path (str File/separator "baz")))))
+ (testing "relative File paths"
+ (is (= "bar" (as-relative-path (File. "bar")))))
+ (testing "absolute File paths are forbidden"
+ (is (thrown? IllegalArgumentException (as-relative-path (File. (str File/separator "quux")))))))
+
+(defn stream-should-have [stream expected-bytes msg]
+ (let [actual-bytes (byte-array (alength expected-bytes))]
+ (.read stream actual-bytes)
+ (is (= -1 (.read stream)) (str msg " : should be end of stream"))
+ (is (= (seq expected-bytes) (seq actual-bytes)) (str msg " : byte arrays should match"))))
+
+(deftest test-input-stream
+ (let [file (temp-file "test-input-stream" "txt")
+ bytes (.getBytes "foobar")]
+ (spit file "foobar")
+ (doseq [[expr msg]
+ [[file File]
+ [(FileInputStream. file) FileInputStream]
+ [(BufferedInputStream. (FileInputStream. file)) BufferedInputStream]
+ [(.. file toURI) URI]
+ [(.. file toURI toURL) URL]
+ [(.. file toURI toURL toString) "URL as String"]
+ [(.. file toString) "File as String"]]]
+ (with-open [s (input-stream expr)]
+ (stream-should-have s bytes msg)))))
+
+(deftest test-streams-buffering
+ (let [data (.getBytes "")]
+ (is (instance? java.io.BufferedReader (reader data)))
+ (is (instance? java.io.BufferedWriter (writer (java.io.ByteArrayOutputStream.))))
+ (is (instance? java.io.BufferedInputStream (input-stream data)))
+ (is (instance? java.io.BufferedOutputStream (output-stream (java.io.ByteArrayOutputStream.))))))
+
+(deftest test-resource
+ (is (nil? (resource "non/existent/resource")))
+ (is (instance? URL (resource "clojure/core.clj")))
+ (let [file (temp-file "test-resource" "txt")
+ url (as-url (.getParentFile file))
+ loader (java.net.URLClassLoader. (into-array [url]))]
+ (is (nil? (resource "non/existent/resource" loader)))
+ (is (instance? URL (resource (.getName file) loader)))))
+
+(deftest test-make-parents
+ (let [tmp (System/getProperty "java.io.tmpdir")]
+ (delete-file-recursively (file tmp "test-make-parents") :silently)
+ (make-parents tmp "test-make-parents" "child" "grandchild")
+ (is (.isDirectory (file tmp "test-make-parents" "child")))
+ (is (not (.isDirectory (file tmp "test-make-parents" "child" "grandchild"))))
+ (delete-file-recursively (file tmp "test-make-parents"))))
diff --git a/test/clojure/test_clojure/metadata.clj b/test/clojure/test_clojure/metadata.clj
index d3a35f24..53919e9d 100644
--- a/test/clojure/test_clojure/metadata.clj
+++ b/test/clojure/test_clojure/metadata.clj
@@ -20,7 +20,8 @@
clojure.test
clojure.walk
clojure.xml
- clojure.zip])
+ clojure.zip
+ clojure.java.io])
(doseq [ns public-namespaces]
(require ns))