interval_tree_test.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. // Copyright 2016 The etcd Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package adt
  15. import (
  16. "math/rand"
  17. "reflect"
  18. "testing"
  19. "time"
  20. )
  21. // TestIntervalTreeInsert tests interval tree insertion.
  22. func TestIntervalTreeInsert(t *testing.T) {
  23. // "Introduction to Algorithms" (Cormen et al, 3rd ed.) chapter 14, Figure 14.4
  24. ivt := NewIntervalTree()
  25. ivt.Insert(NewInt64Interval(16, 21), 30)
  26. ivt.Insert(NewInt64Interval(8, 9), 23)
  27. ivt.Insert(NewInt64Interval(0, 3), 3)
  28. ivt.Insert(NewInt64Interval(5, 8), 10)
  29. ivt.Insert(NewInt64Interval(6, 10), 10)
  30. ivt.Insert(NewInt64Interval(15, 23), 23)
  31. ivt.Insert(NewInt64Interval(17, 19), 20)
  32. ivt.Insert(NewInt64Interval(25, 30), 30)
  33. ivt.Insert(NewInt64Interval(26, 26), 26)
  34. ivt.Insert(NewInt64Interval(19, 20), 20)
  35. expected := []visitedInterval{
  36. {root: NewInt64Interval(16, 21), color: black, left: NewInt64Interval(8, 9), right: NewInt64Interval(25, 30), depth: 0},
  37. {root: NewInt64Interval(8, 9), color: red, left: NewInt64Interval(5, 8), right: NewInt64Interval(15, 23), depth: 1},
  38. {root: NewInt64Interval(25, 30), color: red, left: NewInt64Interval(17, 19), right: NewInt64Interval(26, 26), depth: 1},
  39. {root: NewInt64Interval(5, 8), color: black, left: NewInt64Interval(0, 3), right: NewInt64Interval(6, 10), depth: 2},
  40. {root: NewInt64Interval(15, 23), color: black, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 2},
  41. {root: NewInt64Interval(17, 19), color: black, left: newInt64EmptyInterval(), right: NewInt64Interval(19, 20), depth: 2},
  42. {root: NewInt64Interval(26, 26), color: black, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 2},
  43. {root: NewInt64Interval(0, 3), color: red, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 3},
  44. {root: NewInt64Interval(6, 10), color: red, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 3},
  45. {root: NewInt64Interval(19, 20), color: red, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 3},
  46. }
  47. tr := ivt.(*intervalTree)
  48. visits := tr.visitLevel()
  49. if !reflect.DeepEqual(expected, visits) {
  50. t.Fatalf("level order expected %v, got %v", expected, visits)
  51. }
  52. }
  53. // TestIntervalTreeSelfBalanced ensures range tree is self-balanced after inserting ranges to the tree.
  54. // Use https://www.cs.usfca.edu/~galles/visualization/RedBlack.html for test case creation.
  55. //
  56. // Regular Binary Search Tree
  57. // [0,1]
  58. // \
  59. // [1,2]
  60. // \
  61. // [3,4]
  62. // \
  63. // [5,6]
  64. // \
  65. // [7,8]
  66. // \
  67. // [8,9]
  68. //
  69. // Self-Balancing Binary Search Tree
  70. // [1,2]
  71. // / \
  72. // [0,1] [5,6]
  73. // / \
  74. // [3,4] [7,8]
  75. // \
  76. // [8,9]
  77. //
  78. func TestIntervalTreeSelfBalanced(t *testing.T) {
  79. ivt := NewIntervalTree()
  80. ivt.Insert(NewInt64Interval(0, 1), 0)
  81. ivt.Insert(NewInt64Interval(1, 2), 0)
  82. ivt.Insert(NewInt64Interval(3, 4), 0)
  83. ivt.Insert(NewInt64Interval(5, 6), 0)
  84. ivt.Insert(NewInt64Interval(7, 8), 0)
  85. ivt.Insert(NewInt64Interval(8, 9), 0)
  86. expected := []visitedInterval{
  87. {root: NewInt64Interval(1, 2), color: black, left: NewInt64Interval(0, 1), right: NewInt64Interval(5, 6), depth: 0},
  88. {root: NewInt64Interval(0, 1), color: black, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 1},
  89. {root: NewInt64Interval(5, 6), color: red, left: NewInt64Interval(3, 4), right: NewInt64Interval(7, 8), depth: 1},
  90. {root: NewInt64Interval(3, 4), color: black, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 2},
  91. {root: NewInt64Interval(7, 8), color: black, left: newInt64EmptyInterval(), right: NewInt64Interval(8, 9), depth: 2},
  92. {root: NewInt64Interval(8, 9), color: red, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 3},
  93. }
  94. tr := ivt.(*intervalTree)
  95. visits := tr.visitLevel()
  96. if !reflect.DeepEqual(expected, visits) {
  97. t.Fatalf("level order expected %v, got %v", expected, visits)
  98. }
  99. if visits[len(visits)-1].depth != 3 {
  100. t.Fatalf("expected self-balanced tree with last level 3, but last level got %d", visits[len(visits)-1].depth)
  101. }
  102. }
  103. // TestIntervalTreeDelete ensures delete operation maintains red-black tree properties.
  104. // Use https://www.cs.usfca.edu/~galles/visualization/RedBlack.html for test case creation.
  105. // See https://github.com/etcd-io/etcd/issues/10877 for more detail.
  106. //
  107. //
  108. // After insertion:
  109. // [510,511]
  110. // / \
  111. // ---------- -----------------------
  112. // / \
  113. // [82,83] [830,831]
  114. // / \ / \
  115. // / \ / \
  116. // [11,12] [383,384](red) [647,648] [899,900](red)
  117. // / \ / \ / \
  118. // / \ / \ / \
  119. // [261,262] [410,411] [514,515](red) [815,816](red) [888,889] [972,973]
  120. // / \ /
  121. // / \ /
  122. // [238,239](red) [292,293](red) [953,954](red)
  123. //
  124. //
  125. // After deleting 514 (no rebalance):
  126. // [510,511]
  127. // / \
  128. // ---------- -----------------------
  129. // / \
  130. // [82,83] [830,831]
  131. // / \ / \
  132. // / \ / \
  133. // [11,12] [383,384](red) [647,648] [899,900](red)
  134. // / \ \ / \
  135. // / \ \ / \
  136. // [261,262] [410,411] [815,816](red) [888,889] [972,973]
  137. // / \ /
  138. // / \ /
  139. // [238,239](red) [292,293](red) [953,954](red)
  140. //
  141. //
  142. // After deleting 11 (requires rebalancing):
  143. // [510,511]
  144. // / \
  145. // ---------- --------------------------
  146. // / \
  147. // [383,384] [830,831]
  148. // / \ / \
  149. // / \ / \
  150. // [261,262](red) [410,411] [647,648] [899,900](red)
  151. // / \ \ / \
  152. // / \ \ / \
  153. // [82,83] [292,293] [815,816](red) [888,889] [972,973]
  154. // \ /
  155. // \ /
  156. // [238,239](red) [953,954](red)
  157. //
  158. //
  159. func TestIntervalTreeDelete(t *testing.T) {
  160. ivt := NewIntervalTree()
  161. ivt.Insert(NewInt64Interval(510, 511), 0)
  162. ivt.Insert(NewInt64Interval(82, 83), 0)
  163. ivt.Insert(NewInt64Interval(830, 831), 0)
  164. ivt.Insert(NewInt64Interval(11, 12), 0)
  165. ivt.Insert(NewInt64Interval(383, 384), 0)
  166. ivt.Insert(NewInt64Interval(647, 648), 0)
  167. ivt.Insert(NewInt64Interval(899, 900), 0)
  168. ivt.Insert(NewInt64Interval(261, 262), 0)
  169. ivt.Insert(NewInt64Interval(410, 411), 0)
  170. ivt.Insert(NewInt64Interval(514, 515), 0)
  171. ivt.Insert(NewInt64Interval(815, 816), 0)
  172. ivt.Insert(NewInt64Interval(888, 889), 0)
  173. ivt.Insert(NewInt64Interval(972, 973), 0)
  174. ivt.Insert(NewInt64Interval(238, 239), 0)
  175. ivt.Insert(NewInt64Interval(292, 293), 0)
  176. ivt.Insert(NewInt64Interval(953, 954), 0)
  177. tr := ivt.(*intervalTree)
  178. expectedBeforeDelete := []visitedInterval{
  179. {root: NewInt64Interval(510, 511), color: black, left: NewInt64Interval(82, 83), right: NewInt64Interval(830, 831), depth: 0},
  180. {root: NewInt64Interval(82, 83), color: black, left: NewInt64Interval(11, 12), right: NewInt64Interval(383, 384), depth: 1},
  181. {root: NewInt64Interval(830, 831), color: black, left: NewInt64Interval(647, 648), right: NewInt64Interval(899, 900), depth: 1},
  182. {root: NewInt64Interval(11, 12), color: black, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 2},
  183. {root: NewInt64Interval(383, 384), color: red, left: NewInt64Interval(261, 262), right: NewInt64Interval(410, 411), depth: 2},
  184. {root: NewInt64Interval(647, 648), color: black, left: NewInt64Interval(514, 515), right: NewInt64Interval(815, 816), depth: 2},
  185. {root: NewInt64Interval(899, 900), color: red, left: NewInt64Interval(888, 889), right: NewInt64Interval(972, 973), depth: 2},
  186. {root: NewInt64Interval(261, 262), color: black, left: NewInt64Interval(238, 239), right: NewInt64Interval(292, 293), depth: 3},
  187. {root: NewInt64Interval(410, 411), color: black, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 3},
  188. {root: NewInt64Interval(514, 515), color: red, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 3},
  189. {root: NewInt64Interval(815, 816), color: red, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 3},
  190. {root: NewInt64Interval(888, 889), color: black, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 3},
  191. {root: NewInt64Interval(972, 973), color: black, left: NewInt64Interval(953, 954), right: newInt64EmptyInterval(), depth: 3},
  192. {root: NewInt64Interval(238, 239), color: red, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 4},
  193. {root: NewInt64Interval(292, 293), color: red, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 4},
  194. {root: NewInt64Interval(953, 954), color: red, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 4},
  195. }
  196. visitsBeforeDelete := tr.visitLevel()
  197. if !reflect.DeepEqual(expectedBeforeDelete, visitsBeforeDelete) {
  198. t.Fatalf("level order after insertion expected %v, got %v", expectedBeforeDelete, visitsBeforeDelete)
  199. }
  200. // delete the node "514"
  201. range514 := NewInt64Interval(514, 515)
  202. if deleted := tr.Delete(NewInt64Interval(514, 515)); !deleted {
  203. t.Fatalf("range %v not deleted", range514)
  204. }
  205. expectedAfterDelete514 := []visitedInterval{
  206. {root: NewInt64Interval(510, 511), color: black, left: NewInt64Interval(82, 83), right: NewInt64Interval(830, 831), depth: 0},
  207. {root: NewInt64Interval(82, 83), color: black, left: NewInt64Interval(11, 12), right: NewInt64Interval(383, 384), depth: 1},
  208. {root: NewInt64Interval(830, 831), color: black, left: NewInt64Interval(647, 648), right: NewInt64Interval(899, 900), depth: 1},
  209. {root: NewInt64Interval(11, 12), color: black, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 2},
  210. {root: NewInt64Interval(383, 384), color: red, left: NewInt64Interval(261, 262), right: NewInt64Interval(410, 411), depth: 2},
  211. {root: NewInt64Interval(647, 648), color: black, left: newInt64EmptyInterval(), right: NewInt64Interval(815, 816), depth: 2},
  212. {root: NewInt64Interval(899, 900), color: red, left: NewInt64Interval(888, 889), right: NewInt64Interval(972, 973), depth: 2},
  213. {root: NewInt64Interval(261, 262), color: black, left: NewInt64Interval(238, 239), right: NewInt64Interval(292, 293), depth: 3},
  214. {root: NewInt64Interval(410, 411), color: black, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 3},
  215. {root: NewInt64Interval(815, 816), color: red, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 3},
  216. {root: NewInt64Interval(888, 889), color: black, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 3},
  217. {root: NewInt64Interval(972, 973), color: black, left: NewInt64Interval(953, 954), right: newInt64EmptyInterval(), depth: 3},
  218. {root: NewInt64Interval(238, 239), color: red, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 4},
  219. {root: NewInt64Interval(292, 293), color: red, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 4},
  220. {root: NewInt64Interval(953, 954), color: red, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 4},
  221. }
  222. visitsAfterDelete514 := tr.visitLevel()
  223. if !reflect.DeepEqual(expectedAfterDelete514, visitsAfterDelete514) {
  224. t.Fatalf("level order after deleting '514' expected %v, got %v", expectedAfterDelete514, visitsAfterDelete514)
  225. }
  226. // delete the node "11"
  227. range11 := NewInt64Interval(11, 12)
  228. if deleted := tr.Delete(NewInt64Interval(11, 12)); !deleted {
  229. t.Fatalf("range %v not deleted", range11)
  230. }
  231. expectedAfterDelete11 := []visitedInterval{
  232. {root: NewInt64Interval(510, 511), color: black, left: NewInt64Interval(383, 384), right: NewInt64Interval(830, 831), depth: 0},
  233. {root: NewInt64Interval(383, 384), color: black, left: NewInt64Interval(261, 262), right: NewInt64Interval(410, 411), depth: 1},
  234. {root: NewInt64Interval(830, 831), color: black, left: NewInt64Interval(647, 648), right: NewInt64Interval(899, 900), depth: 1},
  235. {root: NewInt64Interval(261, 262), color: red, left: NewInt64Interval(82, 83), right: NewInt64Interval(292, 293), depth: 2},
  236. {root: NewInt64Interval(410, 411), color: black, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 2},
  237. {root: NewInt64Interval(647, 648), color: black, left: newInt64EmptyInterval(), right: NewInt64Interval(815, 816), depth: 2},
  238. {root: NewInt64Interval(899, 900), color: red, left: NewInt64Interval(888, 889), right: NewInt64Interval(972, 973), depth: 2},
  239. {root: NewInt64Interval(82, 83), color: black, left: newInt64EmptyInterval(), right: NewInt64Interval(238, 239), depth: 3},
  240. {root: NewInt64Interval(292, 293), color: black, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 3},
  241. {root: NewInt64Interval(815, 816), color: red, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 3},
  242. {root: NewInt64Interval(888, 889), color: black, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 3},
  243. {root: NewInt64Interval(972, 973), color: black, left: NewInt64Interval(953, 954), right: newInt64EmptyInterval(), depth: 3},
  244. {root: NewInt64Interval(238, 239), color: red, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 4},
  245. {root: NewInt64Interval(953, 954), color: red, left: newInt64EmptyInterval(), right: newInt64EmptyInterval(), depth: 4},
  246. }
  247. visitsAfterDelete11 := tr.visitLevel()
  248. if !reflect.DeepEqual(expectedAfterDelete11, visitsAfterDelete11) {
  249. // "black-height" property is violated here
  250. //
  251. // TODO: fix this
  252. // [510,511]
  253. // / \
  254. // ---------- --------------------------
  255. // / \
  256. // [82,83] [830,831]
  257. // \ / \
  258. // \ / \
  259. // [383,384] [647,648] [899,900]
  260. // / \ \ / \
  261. // / \ \ / \
  262. // [261,262] [410,411] [815,816] [888,889] [972,973]
  263. // / \ /
  264. // / \ /
  265. // [238,239] [292,293] [953,954]
  266. //
  267. t.Fatalf("level order after deleting '11' expected %v, got %v", expectedAfterDelete11, visitsAfterDelete11)
  268. }
  269. }
  270. func TestIntervalTreeIntersects(t *testing.T) {
  271. ivt := NewIntervalTree()
  272. ivt.Insert(NewStringInterval("1", "3"), 123)
  273. if ivt.Intersects(NewStringPoint("0")) {
  274. t.Errorf("contains 0")
  275. }
  276. if !ivt.Intersects(NewStringPoint("1")) {
  277. t.Errorf("missing 1")
  278. }
  279. if !ivt.Intersects(NewStringPoint("11")) {
  280. t.Errorf("missing 11")
  281. }
  282. if !ivt.Intersects(NewStringPoint("2")) {
  283. t.Errorf("missing 2")
  284. }
  285. if ivt.Intersects(NewStringPoint("3")) {
  286. t.Errorf("contains 3")
  287. }
  288. }
  289. func TestIntervalTreeStringAffine(t *testing.T) {
  290. ivt := NewIntervalTree()
  291. ivt.Insert(NewStringAffineInterval("8", ""), 123)
  292. if !ivt.Intersects(NewStringAffinePoint("9")) {
  293. t.Errorf("missing 9")
  294. }
  295. if ivt.Intersects(NewStringAffinePoint("7")) {
  296. t.Errorf("contains 7")
  297. }
  298. }
  299. func TestIntervalTreeStab(t *testing.T) {
  300. ivt := NewIntervalTree()
  301. ivt.Insert(NewStringInterval("0", "1"), 123)
  302. ivt.Insert(NewStringInterval("0", "2"), 456)
  303. ivt.Insert(NewStringInterval("5", "6"), 789)
  304. ivt.Insert(NewStringInterval("6", "8"), 999)
  305. ivt.Insert(NewStringInterval("0", "3"), 0)
  306. tr := ivt.(*intervalTree)
  307. if tr.root.max.Compare(StringComparable("8")) != 0 {
  308. t.Fatalf("wrong root max got %v, expected 8", tr.root.max)
  309. }
  310. if x := len(ivt.Stab(NewStringPoint("0"))); x != 3 {
  311. t.Errorf("got %d, expected 3", x)
  312. }
  313. if x := len(ivt.Stab(NewStringPoint("1"))); x != 2 {
  314. t.Errorf("got %d, expected 2", x)
  315. }
  316. if x := len(ivt.Stab(NewStringPoint("2"))); x != 1 {
  317. t.Errorf("got %d, expected 1", x)
  318. }
  319. if x := len(ivt.Stab(NewStringPoint("3"))); x != 0 {
  320. t.Errorf("got %d, expected 0", x)
  321. }
  322. if x := len(ivt.Stab(NewStringPoint("5"))); x != 1 {
  323. t.Errorf("got %d, expected 1", x)
  324. }
  325. if x := len(ivt.Stab(NewStringPoint("55"))); x != 1 {
  326. t.Errorf("got %d, expected 1", x)
  327. }
  328. if x := len(ivt.Stab(NewStringPoint("6"))); x != 1 {
  329. t.Errorf("got %d, expected 1", x)
  330. }
  331. }
  332. type xy struct {
  333. x int64
  334. y int64
  335. }
  336. func TestIntervalTreeRandom(t *testing.T) {
  337. // generate unique intervals
  338. ivs := make(map[xy]struct{})
  339. ivt := NewIntervalTree()
  340. maxv := 128
  341. rand.Seed(time.Now().UnixNano())
  342. for i := rand.Intn(maxv) + 1; i != 0; i-- {
  343. x, y := int64(rand.Intn(maxv)), int64(rand.Intn(maxv))
  344. if x > y {
  345. t := x
  346. x = y
  347. y = t
  348. } else if x == y {
  349. y++
  350. }
  351. iv := xy{x, y}
  352. if _, ok := ivs[iv]; ok {
  353. // don't double insert
  354. continue
  355. }
  356. ivt.Insert(NewInt64Interval(x, y), 123)
  357. ivs[iv] = struct{}{}
  358. }
  359. for ab := range ivs {
  360. for xy := range ivs {
  361. v := xy.x + int64(rand.Intn(int(xy.y-xy.x)))
  362. if slen := len(ivt.Stab(NewInt64Point(v))); slen == 0 {
  363. t.Fatalf("expected %v stab non-zero for [%+v)", v, xy)
  364. }
  365. if !ivt.Intersects(NewInt64Point(v)) {
  366. t.Fatalf("did not get %d as expected for [%+v)", v, xy)
  367. }
  368. }
  369. if !ivt.Delete(NewInt64Interval(ab.x, ab.y)) {
  370. t.Errorf("did not delete %v as expected", ab)
  371. }
  372. delete(ivs, ab)
  373. }
  374. if ivt.Len() != 0 {
  375. t.Errorf("got ivt.Len() = %v, expected 0", ivt.Len())
  376. }
  377. }
  378. // TestIntervalTreeSortedVisit tests that intervals are visited in sorted order.
  379. func TestIntervalTreeSortedVisit(t *testing.T) {
  380. tests := []struct {
  381. ivls []Interval
  382. visitRange Interval
  383. }{
  384. {
  385. ivls: []Interval{NewInt64Interval(1, 10), NewInt64Interval(2, 5), NewInt64Interval(3, 6)},
  386. visitRange: NewInt64Interval(0, 100),
  387. },
  388. {
  389. ivls: []Interval{NewInt64Interval(1, 10), NewInt64Interval(10, 12), NewInt64Interval(3, 6)},
  390. visitRange: NewInt64Interval(0, 100),
  391. },
  392. {
  393. ivls: []Interval{NewInt64Interval(2, 3), NewInt64Interval(3, 4), NewInt64Interval(6, 7), NewInt64Interval(5, 6)},
  394. visitRange: NewInt64Interval(0, 100),
  395. },
  396. {
  397. ivls: []Interval{
  398. NewInt64Interval(2, 3),
  399. NewInt64Interval(2, 4),
  400. NewInt64Interval(3, 7),
  401. NewInt64Interval(2, 5),
  402. NewInt64Interval(3, 8),
  403. NewInt64Interval(3, 5),
  404. },
  405. visitRange: NewInt64Interval(0, 100),
  406. },
  407. }
  408. for i, tt := range tests {
  409. ivt := NewIntervalTree()
  410. for _, ivl := range tt.ivls {
  411. ivt.Insert(ivl, struct{}{})
  412. }
  413. last := tt.ivls[0].Begin
  414. count := 0
  415. chk := func(iv *IntervalValue) bool {
  416. if last.Compare(iv.Ivl.Begin) > 0 {
  417. t.Errorf("#%d: expected less than %d, got interval %+v", i, last, iv.Ivl)
  418. }
  419. last = iv.Ivl.Begin
  420. count++
  421. return true
  422. }
  423. ivt.Visit(tt.visitRange, chk)
  424. if count != len(tt.ivls) {
  425. t.Errorf("#%d: did not cover all intervals. expected %d, got %d", i, len(tt.ivls), count)
  426. }
  427. }
  428. }
  429. // TestIntervalTreeVisitExit tests that visiting can be stopped.
  430. func TestIntervalTreeVisitExit(t *testing.T) {
  431. ivls := []Interval{NewInt64Interval(1, 10), NewInt64Interval(2, 5), NewInt64Interval(3, 6), NewInt64Interval(4, 8)}
  432. ivlRange := NewInt64Interval(0, 100)
  433. tests := []struct {
  434. f IntervalVisitor
  435. wcount int
  436. }{
  437. {
  438. f: func(n *IntervalValue) bool { return false },
  439. wcount: 1,
  440. },
  441. {
  442. f: func(n *IntervalValue) bool { return n.Ivl.Begin.Compare(ivls[0].Begin) <= 0 },
  443. wcount: 2,
  444. },
  445. {
  446. f: func(n *IntervalValue) bool { return n.Ivl.Begin.Compare(ivls[2].Begin) < 0 },
  447. wcount: 3,
  448. },
  449. {
  450. f: func(n *IntervalValue) bool { return true },
  451. wcount: 4,
  452. },
  453. }
  454. for i, tt := range tests {
  455. ivt := NewIntervalTree()
  456. for _, ivl := range ivls {
  457. ivt.Insert(ivl, struct{}{})
  458. }
  459. count := 0
  460. ivt.Visit(ivlRange, func(n *IntervalValue) bool {
  461. count++
  462. return tt.f(n)
  463. })
  464. if count != tt.wcount {
  465. t.Errorf("#%d: expected count %d, got %d", i, tt.wcount, count)
  466. }
  467. }
  468. }
  469. // TestIntervalTreeContains tests that contains returns true iff the ivt maps the entire interval.
  470. func TestIntervalTreeContains(t *testing.T) {
  471. tests := []struct {
  472. ivls []Interval
  473. chkIvl Interval
  474. wContains bool
  475. }{
  476. {
  477. ivls: []Interval{NewInt64Interval(1, 10)},
  478. chkIvl: NewInt64Interval(0, 100),
  479. wContains: false,
  480. },
  481. {
  482. ivls: []Interval{NewInt64Interval(1, 10)},
  483. chkIvl: NewInt64Interval(1, 10),
  484. wContains: true,
  485. },
  486. {
  487. ivls: []Interval{NewInt64Interval(1, 10)},
  488. chkIvl: NewInt64Interval(2, 8),
  489. wContains: true,
  490. },
  491. {
  492. ivls: []Interval{NewInt64Interval(1, 5), NewInt64Interval(6, 10)},
  493. chkIvl: NewInt64Interval(1, 10),
  494. wContains: false,
  495. },
  496. {
  497. ivls: []Interval{NewInt64Interval(1, 5), NewInt64Interval(3, 10)},
  498. chkIvl: NewInt64Interval(1, 10),
  499. wContains: true,
  500. },
  501. {
  502. ivls: []Interval{NewInt64Interval(1, 4), NewInt64Interval(4, 7), NewInt64Interval(3, 10)},
  503. chkIvl: NewInt64Interval(1, 10),
  504. wContains: true,
  505. },
  506. {
  507. ivls: []Interval{},
  508. chkIvl: NewInt64Interval(1, 10),
  509. wContains: false,
  510. },
  511. }
  512. for i, tt := range tests {
  513. ivt := NewIntervalTree()
  514. for _, ivl := range tt.ivls {
  515. ivt.Insert(ivl, struct{}{})
  516. }
  517. if v := ivt.Contains(tt.chkIvl); v != tt.wContains {
  518. t.Errorf("#%d: ivt.Contains got %v, expected %v", i, v, tt.wContains)
  519. }
  520. }
  521. }