sparse-array/test/sparse_array/core_test.clj
Simon Brooke 1aa3173dc9 merge dense with sparse now works
Not yet sure I'm right about the semantics of sparse-with-dense: are nils in a dense array first class values?
2019-06-28 09:45:05 +01:00

239 lines
8.9 KiB
Clojure

(ns sparse-array.core-test
(:require [clojure.test :refer :all]
[sparse-array.core :refer :all]))
(deftest creation-and-testing
(testing "Creation and testing."
(is (sparse-array? (make-sparse-array :x :y :z)))
(is (sparse-array? {:dimensions 2,
:coord :x,
:content '(:y),
3 {:dimensions 1,
:coord :y,
:content :data,
4 "hello"},
4 {:dimensions 1,
:coord :y,
:content :data,
3 "goodbye"}}))
(is (= (sparse-array? []) false))
(is (= (sparse-array? "hello") false))
(is (=
(sparse-array?
(dissoc (make-sparse-array :x :y :z) :dimensions))
false)
"All mandatory keywords must be present: dimensions")
(is (=
(sparse-array?
(dissoc (make-sparse-array :x :y :z) :coord))
false)
"All mandatory keywords must be present: coord")
(is (=
(sparse-array?
(dissoc (make-sparse-array :x :y :z) :content))
false)
"All mandatory keywords must be present: content")
(is (=
(sparse-array? {:dimensions 2,
:coord :x,
:content '(:y),
3 {:dimensions 1,
:coord :y,
:content :data,
4 "hello"},
4 {:dimensions 1,
:coord :y,
:content :data,
3 "goodbye"}
5 :foo})
false)
"Can't have data in a non-data layer")
))
(deftest testing-safe
(testing "Checking that correct exceptions are thrown when `*safe-sparse-operations*` is true"
(binding [*safe-sparse-operations* true]
(is
(thrown-with-msg?
clojure.lang.ExceptionInfo
#"Array must be a map"
(sparse-array? [])))
(is
(thrown-with-msg?
clojure.lang.ExceptionInfo
#"The value of `:dimensions` must be a positive integer, not .*"
(sparse-array?
(dissoc (make-sparse-array :x :y :z) :dimensions)))
"All mandatory keywords must be present: dimensions")
(is (thrown-with-msg?
clojure.lang.ExceptionInfo
#"The value of `:coord` must be a keyword, not .*"
(sparse-array?
(dissoc (make-sparse-array :x :y :z) :coord))))
(is (thrown-with-msg?
clojure.lang.ExceptionInfo
#"If there are no further axes the value of `:content` must be `:data`"
(sparse-array?
(dissoc (make-sparse-array :x :y :z) :content)))
"All mandatory keywords must be present: content")
(is (thrown-with-msg?
clojure.lang.ExceptionInfo
#"Array must be a map"
(sparse-array? {:dimensions 2,
:coord :x,
:content '(:y),
3 {:dimensions 1,
:coord :y,
:content :data,
4 "hello"},
4 {:dimensions 1,
:coord :y,
:content :data,
3 "goodbye"}
5 :foo}))
"Can't have data in a non-data layer"))))
(deftest put-and-get
(testing "get"
(let [expected "hello"
array {:dimensions 2,
:coord :x,
:content '(:y)
3 {:dimensions 1 :coord :y :content :data 4 "hello"}}
actual (get array 3 4)]
(is (= actual expected)))
(let [expected nil
array {:dimensions 2,
:coord :x,
:content '(:y)
3 {:dimensions 1 :coord :y :content :data 4 "hello"}}
actual (get array 4 3)]
(is (= actual expected))))
(testing "put"
(let [expected "hello"
array {:dimensions 2,
:coord :x,
:content '(:y)}
actual (((put array expected 3 4) 3) 4)]
(is (= actual expected))))
(testing "round trip, one dimension"
(let
[expected "hello"
actual (get (put (make-sparse-array :x) expected 3) 3)]
(is (= actual expected)))
(binding [*safe-sparse-operations* true]
;; enabling error handling shouldn't make any difference
(let
[expected "hello"
actual (get (put (make-sparse-array :x) expected 3) 3)]
(is (= actual expected)))))
(testing "round trip, two dimensions"
(let
[expected "hello"
actual (get (put (make-sparse-array :x :y) expected 3 4) 3 4)]
(is (= actual expected)))
(binding [*safe-sparse-operations* true]
;; enabling error handling shouldn't make any difference
(let
[expected "hello"
actual (get (put (make-sparse-array :x :y) expected 3 4) 3 4)]
(is (= actual expected)))))
(testing "round trip, three dimensions"
(let
[expected "hello"
actual (get (put (make-sparse-array :x :y :z) expected 3 4 5) 3 4 5)]
(is (= actual expected))))
(testing "round trip, four dimensions"
(let
[expected "hello"
actual (get (put (make-sparse-array :p :q :r :s) expected 3 4 5 6) 3 4 5 6)]
(is (= actual expected))))
(testing "Error handling, number of dimensions"
(binding [*safe-sparse-operations* true]
(is
(thrown-with-msg?
clojure.lang.ExceptionInfo
#"Expected 3 coordinates; found 2"
(put (make-sparse-array :x :y :z) "hello" 3 4)))
(is
(thrown-with-msg?
clojure.lang.ExceptionInfo
#"Expected 3 coordinates; found 4"
(put (make-sparse-array :x :y :z) "hello" 3 4 5 6)))
(is
(thrown-with-msg?
clojure.lang.ExceptionInfo
#"Expected 3 coordinates; found 2"
(get (make-sparse-array :x :y :z) 3 4)))
(is
(thrown-with-msg?
clojure.lang.ExceptionInfo
#"Expected 3 coordinates; found 4"
(get (make-sparse-array :x :y :z) 3 4 5 6))))))
(deftest merge-test
(testing "merge, sparse arrays, one dimension"
(let
[merged (merge-arrays
(put (make-sparse-array :x) "hello" 3)
(put (make-sparse-array :x) "goodbye" 4))]
(is (= "hello" (get merged 3)))
(is (= "goodbye" (get merged 4)))))
(testing "merge, sparse arrays, two dimensions"
(let
[merged (merge-arrays
(put (make-sparse-array :x :y) "hello" 3 4)
(put (make-sparse-array :x :y) "goodbye" 4 3))]
(is (= "hello" (get merged 3 4)))
(is (= "goodbye" (get merged 4 3)))))
(testing "merge, dense with sparse, two dimensions")
(let [dense [[[nil nil nil][nil nil nil][nil nil nil]]
[[nil nil nil][nil nil nil][nil nil nil]]
[[nil nil nil][nil nil nil][nil nil nil]]]
sparse (put (put (make-sparse-array :x :y :z) "hello" 0 0 0) "goodbye" 2 2 2)
expected [[["hello" nil nil] [nil nil nil] [nil nil nil]]
[[nil nil nil] [nil nil nil] [nil nil nil]]
[[nil nil nil] [nil nil nil] [nil nil "goodbye"]]]
actual (merge-arrays dense sparse)]
(is (= actual expected))))
(deftest dense-to-sparse-tests
(testing "dense-to-sparse, one dimension"
(let [dense [nil nil nil "hello" nil "goodbye"]
sparse (dense-to-sparse dense)]
(is (= "hello" (get sparse 3)))
(is (= "goodbye" (get sparse 5))))))
(deftest dense-dimensions-tests
(testing "dense-dimensions"
(is (= 0 (dense-dimensions 1)))
(is (= 1 (dense-dimensions [1 2 3])))
(is (= 2 (dense-dimensions [[1 2 3][2 4 6][3 6 9]])))
(is (= 3
(dense-dimensions
[[[1 2 3][2 4 6][3 6 9]]
[[2 4 6][4 16 36][6 12 18]]
[[3 6 9][18 96 (* 6 36 3)][100 200 300]]])))))
(deftest sparse-to-dense-tests
(testing "Conversion from sparse to dense arrays"
(let [expected [[nil nil nil nil nil]
[nil nil nil nil nil]
[nil nil nil nil nil]
[nil nil nil nil "hello"]
[nil nil nil "goodbye" nil]]
actual (sparse-to-dense {:dimensions 2,
:coord :x,
:content '(:y),
3 {:dimensions 1,
:coord :y,
:content :data,
4 "hello"},
4 {:dimensions 1,
:coord :y,
:content :data,
3 "goodbye"}})]
(is (= actual expected)))))