summaryrefslogtreecommitdiff
path: root/src/unheard/interval_test.clj
diff options
context:
space:
mode:
authorJake Zerrer <him@jakezerrer.com>2025-11-26 09:02:27 -0500
committerJake Zerrer <him@jakezerrer.com>2025-11-26 13:10:08 -0500
commit076288da762787ae2874204c5212df8571ff4564 (patch)
treebf5bbcd5cdb2f38288683fd03817ab2172c87ac9 /src/unheard/interval_test.clj
parent0b6ceecd47cc1faf715419914c77f68a5d789727 (diff)
Have claude create RatioValueInterval
Diffstat (limited to 'src/unheard/interval_test.clj')
-rw-r--r--src/unheard/interval_test.clj178
1 files changed, 178 insertions, 0 deletions
diff --git a/src/unheard/interval_test.clj b/src/unheard/interval_test.clj
new file mode 100644
index 0000000..6878923
--- /dev/null
+++ b/src/unheard/interval_test.clj
@@ -0,0 +1,178 @@
+(ns unheard.interval-test
+ (:require [unheard.interval :as sut]
+ [hyperfiddle.rcf :refer [tests]]))
+
+(tests "Create interval with ratio boundaries and value"
+ (let [iv (sut/ratio-interval 1/4 3/4 {:note :C, :velocity 64})]
+ (.getNormStart iv)
+ :=
+ 1/4
+ (.getNormEnd iv)
+ :=
+ 3/4 (sut/interval-value iv)
+ := {:note :C, :velocity 64}))
+
+(tests "Interval unique identifier"
+ (let [iv (sut/ratio-interval 1/4 3/4 :test)]
+ (.getUniqueIdentifier iv)
+ :=
+ "[1/4,3/4]"))
+
+(tests "Interval comparison - start takes precedence"
+ (let [iv1 (sut/ratio-interval 1/4 1/2 :first)
+ iv2 (sut/ratio-interval 1/2 3/4 :second)
+ iv3 (sut/ratio-interval 1/3 2/3 :third)]
+ ;; iv1 starts before iv2
+ (.compareTo iv1 iv2)
+ :=
+ -1
+ (.compareTo iv2 iv1)
+ :=
+ 1
+ ;; iv1 starts before iv3
+ (.compareTo iv1 iv3)
+ :=
+ -1
+ ;; iv3 starts after iv1 but before iv2
+ (.compareTo iv3 iv2)
+ := -1))
+
+(tests "Interval comparison - end is tiebreaker when starts are equal"
+ (let [iv1 (sut/ratio-interval 1/4 1/2 :a)
+ iv2 (sut/ratio-interval 1/4 3/4 :b)]
+ ;; Same start, iv1 ends before iv2
+ (.compareTo iv1 iv2)
+ :=
+ -1 (.compareTo iv2 iv1)
+ := 1))
+
+(tests "Interval comparison - equal intervals"
+ (let [iv1 (sut/ratio-interval 1/4 1/2 :a)
+ iv2 (sut/ratio-interval 1/4 1/2 :b)]
+ ;; Same boundaries (values don't matter for comparison)
+ (.compareTo iv1 iv2)
+ :=
+ 0))
+
+(tests "Find overlaps - basic cases"
+ (let [coll (sut/create-ratio-interval-collection)
+ iv1 (sut/ratio-interval 1/4 1/2 :first)
+ iv2 (sut/ratio-interval 1/2 3/4 :second)
+ iv3 (sut/ratio-interval 1/3 2/3 :third)]
+ (.add coll iv1)
+ (.add coll iv2)
+ (.add coll iv3)
+ ;; Query [1/3, 1/2] should overlap with all three
+ (let [query (sut/ratio-interval 1/3 1/2 nil)
+ overlaps (sut/find-overlaps coll query)]
+ (count overlaps)
+ :=
+ 3)
+ ;; Query [5/8, 7/8] should overlap with iv2 and iv3
+ (let [query (sut/ratio-interval 5/8 7/8 nil)
+ overlaps (sut/find-overlaps coll query)]
+ (count overlaps)
+ :=
+ 2)))
+
+(tests "Find overlaps - touching intervals at boundaries"
+ (let [coll (sut/create-ratio-interval-collection)
+ iv1 (sut/ratio-interval 0 1/4 :left)
+ iv2 (sut/ratio-interval 1/4 1/2 :right)]
+ (.add coll iv1)
+ (.add coll iv2)
+ ;; Query at exact boundary point should overlap both
+ (let [query (sut/ratio-interval 1/4 1/4 :boundary)
+ overlaps (sut/find-overlaps coll query)]
+ (count overlaps)
+ :=
+ 2 (set (map sut/interval-value overlaps))
+ := #{:left :right})))
+
+(tests "Find overlaps - point interval"
+ (let [coll (sut/create-ratio-interval-collection)
+ iv1 (sut/ratio-interval 1/4 1/2 :wide)
+ iv2 (sut/ratio-interval 1/3 1/3 :point)]
+ (.add coll iv1)
+ (.add coll iv2)
+ ;; Point query inside wide interval
+ (let [query (sut/ratio-interval 1/3 1/3 nil)
+ overlaps (sut/find-overlaps coll query)]
+ (count overlaps)
+ :=
+ 2)))
+
+(tests "Find overlaps - no overlap"
+ (let [coll (sut/create-ratio-interval-collection)
+ iv1 (sut/ratio-interval 1/4 1/2 :first)
+ iv2 (sut/ratio-interval 3/4 7/8 :second)]
+ (.add coll iv1)
+ (.add coll iv2)
+ ;; Query between the two intervals
+ (let [query (sut/ratio-interval 5/8 11/16 nil)
+ overlaps (sut/find-overlaps coll query)]
+ (count overlaps)
+ :=
+ 0)))
+
+(tests "Interval with improper fractions"
+ (let [iv (sut/ratio-interval 5/4 7/4 :improper)]
+ (.getNormStart iv)
+ :=
+ 5/4
+ (.getNormEnd iv)
+ :=
+ 7/4 (sut/interval-value iv)
+ := :improper))
+
+(tests "Interval with negative ratios"
+ (let [iv (sut/ratio-interval -3/4 -1/4 :negative)]
+ (.getNormStart iv)
+ :=
+ -3/4 (.getNormEnd iv)
+ := -1/4))
+
+(tests "Interval toString representation"
+ (let [iv (sut/ratio-interval 1/4 3/4 {:data :test})]
+ (str iv)
+ :=
+ "[1/4, 3/4] -> {:data :test}"))
+
+(tests "Collection operations"
+ (let [coll (sut/create-ratio-interval-collection)
+ iv1 (sut/ratio-interval 1/4 1/2 :first)
+ iv2 (sut/ratio-interval 1/2 3/4 :second)]
+ (.add coll iv1)
+ (.add coll iv2)
+ (.size coll)
+ :=
+ 2
+ ;; Can iterate over collection
+ (set (map sut/interval-value coll))
+ :=
+ #{:first :second}
+ ;; Can clear collection
+ (.clear coll)
+ (.size coll)
+ :=
+ 0))
+
+(tests "Value field can hold various types"
+ (let [iv-map (sut/ratio-interval 0 1 {:key :value})
+ iv-keyword (sut/ratio-interval 0 1 :keyword)
+ iv-string (sut/ratio-interval 0 1 "string")
+ iv-number (sut/ratio-interval 0 1 42)
+ iv-nil (sut/ratio-interval 0 1 nil)]
+ (sut/interval-value iv-map)
+ :=
+ {:key :value}
+ (sut/interval-value iv-keyword)
+ :=
+ :keyword
+ (sut/interval-value iv-string)
+ :=
+ "string"
+ (sut/interval-value iv-number)
+ :=
+ 42 (sut/interval-value iv-nil)
+ := nil))