deftype gives different object instances which causes comparisons of sets with different instances to fail, as it check the instance equality instead of value equality, which can be provided by using defrecord instead of deftype
131 lines
5.7 KiB
Clojure
131 lines
5.7 KiB
Clojure
(ns challenge.discrete-value-range-test
|
|
(:require
|
|
[clojure.test :refer [deftest testing is]]
|
|
[challenge.discrete-value-range :as range]))
|
|
|
|
(defrecord IntInclusiveDiscreteValueRange
|
|
[^int start ^int end]
|
|
range/DiscreteValueRange
|
|
(abuts [_this other]
|
|
(or (= 1 (abs (- start (.end other))))
|
|
(= 1 (abs (- end (.start other))))))
|
|
(value-before [__this]
|
|
(dec start))
|
|
(value-after [_this]
|
|
(inc end))
|
|
(start [_this]
|
|
start)
|
|
(end [_this]
|
|
end)
|
|
(range-type [_this]
|
|
:int-range-inclusive)
|
|
(union [this other]
|
|
(when-not (range/abuts this other)
|
|
(throw (ex-info "Cannot union non-abutting ranges" {})))
|
|
|
|
(range/->discrete-value-range (.range-type this)
|
|
(min start (.start other))
|
|
(max end (.end other))))
|
|
|
|
Object
|
|
(toString [_this]
|
|
(str start ".." end)))
|
|
|
|
(defn int-range-inclusive [start end]
|
|
(assert (<= start end) (str "start : " start "; end: " end))
|
|
(->IntInclusiveDiscreteValueRange start end))
|
|
|
|
(defmethod range/->discrete-value-range :int-range-inclusive [_ start end]
|
|
(int-range-inclusive start end))
|
|
|
|
(deftest integer-ranges-sanity-test
|
|
(testing "value equality"
|
|
(is (= (int-range-inclusive 0 1)
|
|
(int-range-inclusive 0 1))))
|
|
|
|
(testing "abuts"
|
|
(is (= true (range/abuts (int-range-inclusive 0 1)
|
|
(int-range-inclusive 2 3))))
|
|
(is (= true (range/abuts (int-range-inclusive 1 1)
|
|
(int-range-inclusive 2 3))))
|
|
(is (= true (range/abuts (int-range-inclusive 4 7)
|
|
(int-range-inclusive 2 3))))
|
|
(is (= false (range/abuts (int-range-inclusive 4 7)
|
|
(int-range-inclusive 1 2)))))
|
|
(testing "value-before"
|
|
(is (= 0 (range/value-before (int-range-inclusive 1 8)))))
|
|
(testing "value-after"
|
|
(is (= 9 (range/value-after (int-range-inclusive 1 8)))))
|
|
(testing "start"
|
|
(is (= 1 (range/start (int-range-inclusive 1 8)))))
|
|
(testing "end"
|
|
(is (= 8 (range/end (int-range-inclusive 1 8))))))
|
|
|
|
;; test against integer ranges for easy of expression and interpretation
|
|
(deftest ordered-range-values
|
|
(testing "ordered range values are sorted by value and then the range's start boundary before any end boundary"
|
|
(is (= [{:value 1 :boundary-type :start :type :int-range-inclusive}
|
|
{:value 2 :boundary-type :end :type :int-range-inclusive}
|
|
{:value 4 :boundary-type :start :type :int-range-inclusive}
|
|
{:value 5 :boundary-type :start :type :int-range-inclusive}
|
|
{:value 5 :boundary-type :start :type :int-range-inclusive}
|
|
{:value 5 :boundary-type :end :type :int-range-inclusive}
|
|
{:value 5 :boundary-type :end :type :int-range-inclusive}
|
|
{:value 8 :boundary-type :end :type :int-range-inclusive}]
|
|
(#'range/ordered-range-values [(int-range-inclusive 1 2)
|
|
(int-range-inclusive 4 5)
|
|
(int-range-inclusive 5 8)
|
|
(int-range-inclusive 5 5)])))
|
|
(is (= [{:value 5 :boundary-type :start :type :int-range-inclusive}
|
|
{:value 5 :boundary-type :start :type :int-range-inclusive}
|
|
{:value 5 :boundary-type :end :type :int-range-inclusive}
|
|
{:value 5 :boundary-type :end :type :int-range-inclusive}]
|
|
(#'range/ordered-range-values [(int-range-inclusive 5 5)
|
|
(int-range-inclusive 5 5)])))))
|
|
|
|
;; test against integer ranges for easy of expression and interpretation
|
|
(deftest consolidate-ranges
|
|
(testing "combines overlapping ranges"
|
|
(is (= [(int-range-inclusive 5 5)]
|
|
(range/consolidate [(int-range-inclusive 5 5)
|
|
(int-range-inclusive 5 5)])))
|
|
(is (= [(int-range-inclusive 0 1)
|
|
(int-range-inclusive 3 7)
|
|
(int-range-inclusive 9 11)]
|
|
(range/consolidate [(int-range-inclusive 0 1)
|
|
(int-range-inclusive 3 4)
|
|
(int-range-inclusive 3 7)
|
|
(int-range-inclusive 5 5)
|
|
(int-range-inclusive 9 11)
|
|
(int-range-inclusive 5 5)])))
|
|
(is (= [(int-range-inclusive 2 11)]
|
|
(range/consolidate [(int-range-inclusive 2 4)
|
|
(int-range-inclusive 3 7)
|
|
(int-range-inclusive 5 5)
|
|
(int-range-inclusive 6 11)
|
|
(int-range-inclusive 5 5)]))))
|
|
|
|
(testing "conjoins abutting ranges"
|
|
(is (= [(int-range-inclusive 0 9)]
|
|
(range/consolidate [(int-range-inclusive 0 1)
|
|
(int-range-inclusive 2 4)
|
|
(int-range-inclusive 5 5)
|
|
(int-range-inclusive 6 9)
|
|
(int-range-inclusive 5 5)])))
|
|
(is (= [(int-range-inclusive 0 9)]
|
|
(range/consolidate [(int-range-inclusive 0 1)
|
|
(int-range-inclusive 2 3)
|
|
(int-range-inclusive 4 5)
|
|
(int-range-inclusive 6 9)
|
|
(int-range-inclusive 5 5)]))))
|
|
|
|
(testing "combines overlapping ranges and conjoins abutting ranges"
|
|
(is (= [(int-range-inclusive 0 7)
|
|
(int-range-inclusive 13 17)]
|
|
(range/consolidate [(int-range-inclusive 0 1)
|
|
(int-range-inclusive 2 4)
|
|
(int-range-inclusive 3 7)
|
|
(int-range-inclusive 5 5)
|
|
(int-range-inclusive 13 17)
|
|
(int-range-inclusive 5 5)])))))
|